Browse Source

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

lifanagju_citu 9 months ago
parent
commit
33ad5edd83

+ 100 - 208
src/components/AreaSelect/index.vue

@@ -1,252 +1,144 @@
 <template>
-  <div class="d-flex floatCard" :style="{ 'z-index': 999 }" @mouseleave="handleMouseLeave">
-    <v-card class="card">
-      <div class="leftCard">
-        <div
-          class="leftCardItem" :class="{'leftIndexAct': index === leftIndex}"
-          v-for="(item, index) in items" :key="item.id"
-          @mouseover="handleMouseOver(item, index)"
-        >
-          <div class="rowItem d-flex">
-            <span class="categoryName">{{ item.name }}</span>
-            <span class="mdi mdi-menu-right"></span>
-          </div>
-        </div>
+  <v-card class="card rightCardBox">
+      <div v-if="showSelect" class="pa-3 currentSelect">
+        <span>已选择:</span>
+        <v-chip 
+          class="mr-3" 
+          label
+          size="small"
+          color="primary"
+          closable
+          v-for="k in currentSelect" 
+          :key="k.id"
+          @click:close="handleClick(k)"
+        >{{ k.name }}</v-chip>
       </div>
-    </v-card>
-    <v-card v-if="rightObj.show" class="card rightCardBox">
       <div class="rightCard">
-        <div class="categoryName">{{ rightObj.data.name }}</div>
-        <div v-for="(item, index) in rightObj.data.children" :key="item.id">
-          <v-divider v-if="index" class="divider"></v-divider>
+        <div v-for="item in items" :key="item.id">
           <div class="rowItem d-flex">
             <div class="categoryName2">{{ item.name }}</div>
             <div class="rightContent">
               <div v-if="!item.children?.length"></div>
-              <div 
-                v-else 
-                :class="['jobItem', {'active': selectItems.includes(val.id)}]" 
-                v-for="val in item.children" 
-                :key="val.id" 
-                @click="handleAreaClick(val, item.name)"
-              >
-              {{ val.name }}</div>
+              <div
+                v-else
+                :class="['jobItem', {'active': idChecked.includes(val.id)}]"
+                v-for="val in item.children" :key="val.id"
+                @click="handleClick(val)"
+              >{{ val.name }}</div>
             </div>
           </div>
         </div>
       </div>
     </v-card>
-  </div>
 </template>
 
 <script setup>
+defineOptions({ name:'common-components-area'})
 import { getDict } from '@/hooks/web/useDictionaries'
-import { reactive, ref } from 'vue';
-defineOptions({ name:'common-components-jobTypeCard'})
-
-const emits = defineEmits(['handleAreaClick'])
+import { ref } from 'vue'
+import Snackbar from '@/plugins/snackbar'
 
+const emits = defineEmits(['handleClick'])
 const props = defineProps({
-  // 是否单选(首页为单选)
-  isSingle: {
+  limit: { // 限制最大可选择数量, 不限制传false或者0
+    type: [Number, Boolean],
+    default: 3
+  },
+  select: {
+    type: Array,
+    default: () => []
+  },
+  showSelect: {
     type: Boolean,
     default: false
   },
-  select: {
+  currentData: {
     type: Array,
     default: () => []
   }
 })
-const selectItems = ref([])
-// 回显
-if (props.select.length) {
-  selectItems.value = props.select
-}
 
-// 点击
-const handleAreaClick = async (val, preName) => {
-  const obj = selectItems.value.includes(val.id)
-  if (props.isSingle) {
-    selectItems.value = [val.id]
-  } else {
-    if (obj) {
-      selectItems.value = selectItems.value.filter(e => e.id !== val.id)
-    } else selectItems.value.push(val.id)
-  }
-  emits('handleAreaClick', selectItems.value, val.name, preName)
-}
+let items = ref()
+let idChecked = ref([])
+let currentSelect = ref([])
+// 回显
+if (props.currentData.length) currentSelect.value = props.currentData
+console.log(props.select, 'props')
+if (props.select.length) idChecked.value = props.select.map(e => e + '') // 数据中的id是字符串
 
-let items = ref([])
 getDict('areaTreeData', null, 'areaTreeData').then(({ data }) => {
   data = data?.length && data || []
-  const chinaTreeData = data.filter(e => e.id === '1')
-  if (!chinaTreeData.length) return
-  items.value = chinaTreeData[0].children
+  const china = data.find(e => e.id === '1')
+  items.value = china?.children?.length ? china.children : []
 })
 
-// 右侧列表信息
-const leftIndex = ref(null)
-const rightObj = reactive({ show: false, data: {} })
-
-const handleMouseOver = (val, index) => {
-  leftIndex.value = index
-  rightObj.data = val
-  rightObj.show = true
-}
-const handleMouseLeave = () => {
-  rightObj.show = false
-  leftIndex.value = null
+// 设置选中ids
+const handleClick = (val) => {
+  const isExist = idChecked.value.includes(val.id)
+  if (!isExist) {
+    // 添加
+    if (props.limit === 1) {
+      currentSelect.value = [val]
+      idChecked.value = [val.id]
+    } else {
+      if (props.limit === idChecked.value.length) return Snackbar.warning(`最多可选${props.limit}个城市`)
+      currentSelect.value.push(val)
+      idChecked.value.push(val.id)
+    }
+  } else {
+    // 删除
+    currentSelect.value = currentSelect.value.filter(e => e.id !== val.id)
+    idChecked.value = idChecked.value.filter(e => e !== val.id)
+  }
+  emits('handleClick', idChecked.value, currentSelect.value)
 }
 </script>
 
 <style lang="scss" scoped>
-.active {
-  color: var(--v-primary-base) !important;
-  font-weight: 700;
-}
-:deep(.v-window) {
-  height: 392px !important;
+.currentSelect {
+  position: sticky;
+  background-color: var(--color-f2f4f7);
 }
-.floatCard {
-  .leftIndexAct { color: var(--v-primary-base); }
-  .leftCard {
-    height: 242px;
-    width: 172px;
-    margin: 4px 0;
-    overflow-y: auto;
-    .leftCardItem {
-      height: 36px;
-      line-height: 36px;
-      padding: 0 16px;
+.card { border-radius: 12px; }
+.rightCard {
+  position: relative;
+  height: 384px;
+  width: 786px;
+  margin: 4px 0;
+  padding: 0 16px;
+  overflow-y: auto;
+  .categoryName2 { font-size: 14px; color: #000; width: 150px; margin-right: 4px;}
+  .jobItem { font-size: 14px; color: var(--color-333); }
+  .active { color: var(--v-primary-base); font-weight: 700; }
+  .rowItem {
+    padding: 8px 0;
+  }
+  .divider {
+    margin-left: 150px;
+  }
+  .rightContent {
+    flex: 1;
+    div {
+      margin: 4px 28px 2px 0;
+      float: left;
       cursor: pointer;
       &:hover {
         color: var(--v-primary-base);
-        background-color: var(--color-f8);
-      }
-      .categoryName { font-size: 14px; font-family: 微软雅黑; }
-    }
-    .rowItem { justify-content: space-between; }
-  }
-  .rightCardBox { margin-left: 4px; }
-  .rightCard {
-    height: 242px;
-    width: 525px;
-    margin: 4px 0;
-    padding: 0 16px;
-    overflow-y: auto;
-    .categoryName { font-size: 16px; line-height: 28px; margin-top: 6px;}
-    .categoryName2 { font-size: 14px; color: var(--color-666); width: 110px; margin-right: 4px;}
-    .jobItem { font-size: 14px; color: var(--color-333); }
-    .rowItem {
-      padding: 8px 0;
-    }
-    .divider {
-      margin-left: 110px;
-    }
-    .rightContent {
-      flex: 1;
-      div {
-        margin: 4px 28px 2px 0;
-        float: left;
-        cursor: pointer;
-        color: var(--color-333);
-        &:hover {
-          color: var(--v-primary-base);
-        }
       }
     }
   }
 }
-.hasPageCard {
-  width: 100%;
-  .card { border-radius: 12px; }
-  .leftIndexAct {
-    height: 48px;
-    margin: 0 4px;
-    border-radius: 12px;
-    // background-color: var(--v-primary-base);
-  }
-  justify-content: center; // 后面的flex会继承
-  .leftCard {
-    height: 384px;
-    width: 380px;
-    margin: 4px 0;
-    overflow-x: hidden;
-    overflow-y: auto;
-    .leftCardItem {
-      height: 42px;
-      line-height: 42px;
-      padding: 0 16px;
-      .title { font-size: 14px; }
-      .mdi-menu-right { font-size: 20px; }
-    }
-    .jobItemsBox {
-      flex: 1;
-      padding:0 8px;
-      .outerCovering {
-        display: flex;
-        flex-wrap: wrap; /* 允许换行 */
-        width: 100%; /* 设置容器宽度 */
-        height: 42px;
-        overflow: hidden;
-        // border: 1px solid red; /* 可视化边界 */
-        .jobItems {
-          font-size: 14px;
-          margin-left: 12px;
-          cursor: pointer;
-          color: var(--color-666);
-          font-family: 微软雅黑; 
-          &:hover {
-            color: var(--v-primary-base);
-            // background-color: var(--color-f8);
-          }
-        }
-      }
-    }
-  }
-  .rightCardBox { flex: 1; margin-left: 12px;}
-  .rightCard {
-    height: 384px;
-    // min-width: 786px;
-    margin: 4px 0;
-    padding: 0 16px;
-    overflow-y: auto;
-    .categoryName { font-size: 16px; line-height: 28px; margin-top: 6px; color: var(--v-primary-base)}
-    .categoryName2 { font-size: 14px; color: var(--color-666); width: 110px; margin-right: 4px;}
-    .jobItem { font-size: 14px; color: var(--color-333); }
-    .rowItem {
-      padding: 8px 0;
-    }
-    .divider {
-      margin-left: 110px;
-    }
-    .rightContent {
-      flex: 1;
-      div {
-        margin: 4px 28px 2px 0;
-        float: left;
-        cursor: pointer;
-        color: var(--color-333);
-        &:hover {
-          color: var(--v-primary-base);
-        }
-      }
-    }
-  }
+
+::-webkit-scrollbar {
+  width: 4px;
+  height: 10px;
 }
-// ::v-deep {
-  ::-webkit-scrollbar {
-    width: 4px;
-    height: 10px;
-    // display: none;
-  }
-  ::-webkit-scrollbar-thumb, .temporaryAdd ::-webkit-scrollbar-thumb, .details_edit ::-webkit-scrollbar-thumb {
-    // 滚动条-颜色
-    background: #c3c3c379;
-  }
-  ::-webkit-scrollbar-track, .temporaryAdd ::-webkit-scrollbar-track, .details_edit ::-webkit-scrollbar-track {
-    // 滚动条-底色
-    background: #e5e5e58f;
-  }
-// }
-</style>
+::-webkit-scrollbar-thumb, .temporaryAdd ::-webkit-scrollbar-thumb, .details_edit ::-webkit-scrollbar-thumb {
+  // 滚动条-颜色
+  background: #c3c3c379;
+}
+::-webkit-scrollbar-track, .temporaryAdd ::-webkit-scrollbar-track, .details_edit ::-webkit-scrollbar-track {
+  // 滚动条-底色
+  background: #e5e5e58f;
+}
+</style>

+ 0 - 2
src/components/FormUI/TextInput/index.vue

@@ -71,8 +71,6 @@ watch(() => props.modelValue, (newVal) => {
 
 const modelValueUpDate = (val) => {
   value.value = val
-  console.log('1', value.value)
-  console.log('modelValueUpDate val', val)
   emit('update:modelValue', value.value)
   debouncedCallbackUpDate(value.value) // emit('change', value.value)
 }

+ 1 - 1
src/components/FormUI/nestedListGroup/index.vue

@@ -28,7 +28,7 @@
       @update:modelValue="modelValueUpDate"
     >
     </v-text-field>
-    <v-menu activator="#menu-activator" :close-on-content-click="closeOnContentClick">
+    <v-menu activator="#menu-activator" :close-on-content-click="item.closeOnContentClick">
       <listGroup
         :list="item.items"
         :option="option"

+ 2 - 2
src/store/user.js

@@ -72,7 +72,7 @@ export const useUserStore = defineStore('user',
       // 获取当前登录账户信息
       async getUserInfos () {
         try {
-          const api = this.loginType === 'enterprise' ? getEnterprisingUserInfo : getUserInfo
+          const api = localStorage.getItem('loginType') === 'enterprise' ? getEnterprisingUserInfo : getUserInfo
           const data = await api({ id: this.accountInfo.userId })
           this.userInfo = data
           localStorage.setItem('userInfo', JSON.stringify(data))
@@ -85,7 +85,7 @@ export const useUserStore = defineStore('user',
       // 获取当前登录账户的基本信息(人才信息)
       async getUserBaseInfos (userId = null) {
         try {
-          const api = this.loginType === 'enterprise' ? null : getBaseInfo
+          const api = localStorage.getItem('loginType') === 'enterprise' ? null : getBaseInfo
           if (!api) return
           const data = await api({ userId: userId || this.accountInfo.userId })
           if (!data) return localStorage.setItem('baseInfo', '{}')

+ 15 - 15
src/views/recruit/enterprise/talentPool/components/filter.vue

@@ -119,21 +119,21 @@ const formItems = ref({
       dictTypeName: 'menduner_exp_type',
       items: []
     },
-    {
-      slotName: 'residence',
-      key: 'residence',
-      value: null,
-      col: 6,
-      flexStyle: 'mr-3',
-      label: '户籍地'
-    },
-    {
-      slotName: 'areaIds',
-      key: 'areaIds',
-      value: null,
-      col: 6,
-      label: '期望城市'
-    },
+    // {
+    //   slotName: 'residence',
+    //   key: 'residence',
+    //   value: null,
+    //   col: 6,
+    //   flexStyle: 'mr-3',
+    //   label: '户籍地'
+    // },
+    // {
+    //   slotName: 'areaIds',
+    //   key: 'areaIds',
+    //   value: null,
+    //   col: 6,
+    //   label: '期望城市'
+    // },
     {
       type: 'vueDatePicker',
       key: 'firstWorkTime',

+ 6 - 3
src/views/recruit/personal/PersonalCenter/dynamic/right.vue

@@ -41,9 +41,12 @@
         <div class="d-flex attachment-item my-2" v-for="k in attachmentList" :key="k.id">
           <v-icon color="primary">mdi-file-account</v-icon>
           <div class="file-name ellipsis ml-2">{{ k.title }}</div>
-          <v-icon class="cursor-pointer" color="primary" @click="previewFile(k.url)">mdi-eye-outline</v-icon>
+          <!-- <v-icon class="cursor-pointer" color="primary" @click="previewFile(k.url)">mdi-eye-outline</v-icon>
           <v-icon class="cursor-pointer mx-2" color="primary" @click="handleDownload(k)">mdi-download-box-outline</v-icon>
-          <v-icon class="cursor-pointer" color="error" @click="handleDelete(k)">mdi-trash-can-outline</v-icon>
+          <v-icon class="cursor-pointer" color="error" @click="handleDelete(k)">mdi-trash-can-outline</v-icon> -->
+          <span class="cursor-pointer color-primary" @click="previewFile(k.url)">预览</span>
+          <span class="cursor-pointer mx-2 color-primary" @click="handleDownload(k)">下载</span>
+          <span class="cursor-pointer color-error" @click="handleDelete(k)">删除</span>
         </div>
       </div>
       <div v-else class="more-text d-flex justify-center">暂无简历,请先上传</div>
@@ -256,7 +259,7 @@ const interviewScheduleMore = () => {
     color: #555;
     font-size: 14px;
     .file-name {
-      width: 230px;
+      width: 219px;
     }
   }
 }

+ 11 - 1
src/views/recruit/personal/remuse/components/basicInfo.vue

@@ -190,7 +190,17 @@ const items = ref({
       label: '中文名 *',
       col: 6,
       outlined: true,
-      rules: [v => !!v || '请输入您的中文名']
+      rules: [
+        value => {
+          if (value) return true
+          return '请输入您的中文名'
+        },
+        value => {
+          var regex = /^[\u4e00-\u9fa5]+$/
+          if (regex.test(value)) return true
+          return '请输入正确的中文名'
+        }
+      ]
     },
     {
       type: 'ifRadio',

+ 16 - 3
src/views/recruit/personal/remuse/components/dict.js

@@ -38,6 +38,16 @@ const dictList = [
     value: 'jobTypeData',
     itemKey: 'value',
     itemText: 'label'
+  },
+  { 
+    type: 'menduner_area_type', 
+    apiType: 'areaList', 
+    key: 'interestedAreaIdList', 
+    label: 'interestedArea', 
+    isArray: true, 
+    value: 'areaTypeData', 
+    itemKey: 'id', 
+    itemText: 'name' 
   }
 ]
 
@@ -60,9 +70,12 @@ export const dealJobData = (list) => {
     res = list.map(e => {
       let obj = {}
       if (item.isArray) {
-        e[item.label] = e[item.key].map(val => {
-          return obj = dictObj[item.value].find(i => i[item.itemKey] === val)
-        })
+        if (e[item.key] && e[item.key].length) {
+          const result = e[item.key].map(val => {
+            return obj = dictObj[item.value].find(i => i[item.itemKey] === val)
+          })
+          e[item.label] = result && result.length ? result.filter(Boolean) : []
+        }
       } else {
         obj = dictObj[item.value].find(k => Number(k[item.itemKey]) === Number(e[item.key]))
         if (!obj) return

+ 56 - 18
src/views/recruit/personal/remuse/components/jobIntention.vue

@@ -22,7 +22,9 @@
             <div class="line" v-if="k.industry.length && k.jobTypeName">|</div>
             <div class="grey-text">{{ k.jobTypeName }}</div>
             <div class="line" v-if="k.jobTypeName && k.workArea">|</div>
-            <div class="grey-text">{{ k.workArea }}</div>
+            <div class="grey-text ellipsis" style="max-width: 160px;">
+              {{ k.interestedArea && k.interestedArea.length ? k.workArea + ',' + k.interestedArea.map(e => e.name).join(',') : k.workArea }}
+            </div>
           </div>
           <div class="float-right" v-if="k.active">
             <v-btn variant="text" color="primary" prepend-icon="mdi-square-edit-outline" @click="handleEdit(k)">{{ $t('common.edit') }}</v-btn>
@@ -61,6 +63,20 @@
             <industryTypeCard :select="query.industryIdList" :currentData="currentSelect" showSelect @handleClickIndustry="handleIndustry"></industryTypeCard>
           </v-menu>
         </template>
+        <!-- 其它感兴趣的城市 -->
+        <template #interestedAreaIdList="{ item }">
+          <v-menu :close-delay="1" :open-delay="0" v-bind="$attrs" :close-on-content-click="false">
+            <template v-slot:activator="{  props }">
+              <TextInput
+                v-model="item.value"
+                :item="item"
+                v-bind="props"
+                style="position: relative;"
+              ></TextInput>
+            </template>
+            <AreaSelect :select="query.interestedAreaIdList" :currentData="areaSelect" :limit="false" showSelect @handleClick="handleArea"></AreaSelect>
+          </v-menu>
+        </template>
       </CtForm>
       <div class="text-end">
         <v-btn class="half-button mr-3" variant="tonal" @click="isAdd = false; resetForm()">{{ $t('common.cancel') }}</v-btn>
@@ -115,8 +131,7 @@ const items = ref({
       key: 'payFrom',
       value: null,
       label: '期望薪资(最低要求) *',
-      col: 6,
-      flexStyle: 'mr-3',
+      col: 4,
       outlined: true,
       rules: [v => !!v || '请输入薪资最低要求']
     },
@@ -125,10 +140,28 @@ const items = ref({
       key: 'payTo',
       value: null,
       label: '期望薪资(最高要求) *',
-      col: 6,
+      col: 4,
       outlined: true,
+      flexStyle: 'mx-3',
       rules: [v => !!v || '请输入薪资最高要求']
     },
+    {
+      type: 'autocomplete',
+      key: 'jobType',
+      value: null,
+      label: '求职类型 *',
+      outlined: true,
+      itemText: 'label',
+      col: 4,
+      itemValue: 'value',
+      rules: [v => !!v || '请选择求职类型'],
+      items: [
+        { label: '全职', value: '0' },
+        { label: '兼职', value: '1' },
+        { label: '临时', value: '2' },
+        { label: '实习', value: '3' }
+      ]
+    },
     {
       type: 'autocomplete',
       key: 'workAreaProvinceId',
@@ -158,21 +191,10 @@ const items = ref({
       change: null
     },
     {
-      type: 'autocomplete',
-      key: 'jobType',
+      slotName: 'interestedAreaIdList',
+      key: 'interestedAreaIdList',
       value: null,
-      label: '求职类型 *',
-      outlined: true,
-      itemText: 'label',
-      col: 12,
-      itemValue: 'value',
-      rules: [v => !!v || '请选择求职类型'],
-      items: [
-        { label: '全职', value: '0' },
-        { label: '兼职', value: '1' },
-        { label: '临时', value: '2' },
-        { label: '实习', value: '3' }
-      ]
+      label: '其它感兴趣的城市'
     }
   ]
 })
@@ -229,6 +251,16 @@ const handleIndustry = (list, arr) => {
   setValue('industryIdList', str)
 }
 
+// 其它感兴趣的城市
+let areaSelect = reactive([])
+const handleArea = (list, arr) => {
+  if (!list.length) return setValue('interestedAreaIdList', '')
+  query.interestedAreaIdList = list
+  areaSelect = arr
+  const str = arr.map(e => e.name).join('、')
+  setValue('interestedAreaIdList', str)
+}
+
 const resetForm = () => {
   items.value.options.forEach(e => {
     if (e.key === 'industryIdList') e.value = ''
@@ -237,6 +269,7 @@ const resetForm = () => {
   editId.value = null
   query = {}
   currentSelect = []
+  areaSelect = []
 }
 
 const arr = ['payFrom', 'payTo', 'jobType', 'workAreaId']
@@ -263,6 +296,10 @@ const handleEdit = async (item) => {
       e.value = item[e.valueKey]
     } else e.value = item[e.key]
     if (e.key === 'industryIdList') e.value = item.industry.map(e => e.nameCn).join('、')
+    if (e.key === 'interestedAreaIdList') {
+      e.value = item.interestedArea && item.interestedArea.length ? item.interestedArea.map(e => e.name).join('、') : []
+      query.interestedAreaIdList = item.interestedAreaIdList && item.interestedAreaIdList.length ? item.interestedAreaIdList : []
+    }
     if (e.key === 'workAreaId' && item[e.key]) workAreaId = item[e.key]
   })
   if (workAreaId) { // 省份回显
@@ -275,6 +312,7 @@ const handleEdit = async (item) => {
     }
   }
   currentSelect = item.industry
+  areaSelect = item.interestedArea && item.interestedArea.length ? item.interestedArea : []
   isAdd.value = true
 }
 

+ 1 - 0
src/views/recruit/personal/remuse/components/vocationalSkills.vue

@@ -60,6 +60,7 @@ const formItems = ref({
       outlined: true,
       itemText: 'nameCn',
       itemValue: 'id',
+      closeOnContentClick: true,
       flexStyle: 'mr-3',
       col: 8,
       rules: [v => !!v || '请选择技能名称'],

+ 0 - 1
src/views/recruit/personal/remuse/components/workExperience.vue

@@ -3,7 +3,6 @@
     <div class="resume-header mb-3">
       <div class="resume-title">
         {{ $t('resume.workExperience') }}
-        <span class="color-warning font-size-14">({{ $t('resume.workExperienceTips')}})</span>
       </div>
       <v-btn  variant="text" color="primary" prepend-icon="mdi-plus-box" @click="handle(0)">{{ $t('common.add') }}</v-btn>
     </div>