瀏覽代碼

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

zhengnaiwen_citu 4 月之前
父節點
當前提交
5fadfbb4e3
共有 39 個文件被更改,包括 903 次插入249 次删除
  1. 3 0
      components.d.ts
  2. 63 63
      src/components/CtTooltip/index.js
  3. 42 29
      src/components/Enterprise/hotPromoted.vue
  4. 4 3
      src/components/Position/item.vue
  5. 3 3
      src/components/Position/longStrip.vue
  6. 524 0
      src/components/PreviewImg/previewImage.vue
  7. 3 8
      src/components/headSearch/index.vue
  8. 104 0
      src/directives/previewImageDirective.js
  9. 7 3
      src/layout/personal/navBar.vue
  10. 2 0
      src/main.js
  11. 1 0
      src/styles/index.scss
  12. 4 6
      src/styles/recruit/company.css
  13. 1 1
      src/styles/recruit/company.min.css
  14. 6 6
      src/styles/recruit/company.scss
  15. 20 1
      src/utils/index.js
  16. 1 1
      src/version.js
  17. 1 1
      src/views/recruit/entRegister/register.vue
  18. 13 1
      src/views/recruit/enterprise/entInfoSetting/index.vue
  19. 1 1
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/basicInfo.vue
  20. 2 5
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/businessInformation.vue
  21. 3 12
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseAlbum.vue
  22. 1 1
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseLabel.vue
  23. 1 1
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseLogo.vue
  24. 1 1
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/welfareLabel.vue
  25. 4 3
      src/views/recruit/enterprise/invoiceManagement/index.vue
  26. 1 1
      src/views/recruit/enterprise/talentMap/index.vue
  27. 7 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/companyCollection.vue
  28. 1 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/interested.vue
  29. 7 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/positionCollection.vue
  30. 3 4
      src/views/recruit/personal/company/components/companyItem.vue
  31. 1 1
      src/views/recruit/personal/company/index.vue
  32. 4 4
      src/views/recruit/personal/companyDetail/components/introduction.vue
  33. 20 9
      src/views/recruit/personal/home/components/advertisement/preferred.vue
  34. 2 14
      src/views/recruit/personal/home/components/hotPromotedPositions.vue
  35. 1 1
      src/views/recruit/personal/home/components/popularEnterprises.vue
  36. 7 3
      src/views/recruit/personal/home/index.vue
  37. 23 49
      src/views/recruit/personal/position/components/details.vue
  38. 4 2
      src/views/recruit/personal/position/components/poster.vue
  39. 7 8
      src/views/recruit/personal/position/index.vue

+ 3 - 0
components.d.ts

@@ -31,8 +31,10 @@ declare module 'vue' {
     CtTextField: typeof import('./src/components/CtVuetify/CtTextField/index.vue')['default']
     CtTextField: typeof import('./src/components/CtVuetify/CtTextField/index.vue')['default']
     DatePicker: typeof import('./src/components/DatePicker/index.vue')['default']
     DatePicker: typeof import('./src/components/DatePicker/index.vue')['default']
     Echarts: typeof import('./src/components/Echarts/index.vue')['default']
     Echarts: typeof import('./src/components/Echarts/index.vue')['default']
+    ElCascader: typeof import('element-plus/es')['ElCascader']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElTree: typeof import('element-plus/es')['ElTree']
     ElTree: typeof import('element-plus/es')['ElTree']
+    ElImage: typeof import('element-plus/es')['ElImage']
     Empty: typeof import('./src/components/Empty/index.vue')['default']
     Empty: typeof import('./src/components/Empty/index.vue')['default']
     File: typeof import('./src/components/Upload/file.vue')['default']
     File: typeof import('./src/components/Upload/file.vue')['default']
     HeadSearch: typeof import('./src/components/headSearch/index.vue')['default']
     HeadSearch: typeof import('./src/components/headSearch/index.vue')['default']
@@ -54,6 +56,7 @@ declare module 'vue' {
     NestedListGroup: typeof import('./src/components/FormUI/nestedListGroup/index.vue')['default']
     NestedListGroup: typeof import('./src/components/FormUI/nestedListGroup/index.vue')['default']
     Pay: typeof import('./src/components/pay/index.vue')['default']
     Pay: typeof import('./src/components/pay/index.vue')['default']
     PersonalRecharge: typeof import('./src/components/personalRecharge/index.vue')['default']
     PersonalRecharge: typeof import('./src/components/personalRecharge/index.vue')['default']
+    PreviewImage: typeof import('./src/components/PreviewImg/previewImage.vue')['default']
     PreviewImg: typeof import('./src/components/PreviewImg/index.vue')['default']
     PreviewImg: typeof import('./src/components/PreviewImg/index.vue')['default']
     ProgressBar: typeof import('./src/components/ProgressBar/index.vue')['default']
     ProgressBar: typeof import('./src/components/ProgressBar/index.vue')['default']
     QrCode: typeof import('./src/components/QrCode/index.vue')['default']
     QrCode: typeof import('./src/components/QrCode/index.vue')['default']

+ 63 - 63
src/components/CtTooltip/index.js

@@ -57,68 +57,68 @@ const isOverflow = (target) => {
 }
 }
 
 
 export const ellipsisTooltip = {
 export const ellipsisTooltip = {
-  mounted(el, binding) {
-    //获取指令的参数
-    const {
-        value: {
-            placement, content, destroyOnLeave
-        } = {}
-    } = binding;
-    // 加上超出...样式
-    el.style.overflow = "hidden";
-    el.style.textOverflow = "ellipsis";
-    el.style.whiteSpace = "nowrap";
-    //鼠标移开时 清除元素
-    const onMouseLeave = () => {
-      if (el.w_tipInstance) {
-        el.w_tipInstance.hiddenTip()
-        el.w_tooltip.remove()
-        el.w_tipInstance = null
-        el.w_tooltip = null
-      }
-    };
-    const onMouseEnter = () => {
-      // 判断内容长度 需要展示
-      if (isOverflow(el)) {
-        // const positionXY = getPosition(el)
-        const directiveList = allPlacements.filter(placement => binding.modifiers[placement])
-        const placements = directiveList.length ? directiveList : allPlacements
-        if (!el.w_tooltip) {
-          // 创建tooltip实例
-          const vm = createApp(MyToolTip)
-          // 创建根元素
-          el.w_tooltip = document.createElement('div')
-          // 挂载到页面
-          document.body.appendChild(el.w_tooltip)
-          el.w_tooltip.id = `tooltip_${Math.floor(Math.random() * 10000)}`
-          el.w_tipInstance = vm.mount(el.w_tooltip)
-        }
-        // 设置 tooltip 显示方向
-        el.w_tipInstance.placements = placement || placements[0] || 'top'
-        // 设置显示内容
-        el.w_tipInstance.setContent(content || el.innerText)
-        // 使 tooltip 显示
-        el.w_tipInstance.showTip()
-        nextTick(() => {
-          // 计算 tooltip 在页面中的位置
-          calculationLocation(el.w_tipInstance, el, placements[0])
-        })
-        el._scrollHandler = () => {
-          // 重新定位位置
-          if (el.w_tipInstance && el.w_tipInstance.tooltipShow) calculationLocation(el.w_tipInstance, el, placements[0])
-        }
-        window.addEventListener('scroll', el._scrollHandler)
-        const _destroyOnLeave = destroyOnLeave || true
-        if (_destroyOnLeave) el.addEventListener("mouseleave", onMouseLeave);
-      }
-    };
-    el.addEventListener("mouseenter", onMouseEnter);
-  },
-  unmounted(el) {
-    if (el.w_tooltip) {
-      document.body.removeChild(el.w_tooltip)
-    }
-    window.removeEventListener('scroll', el._scrollHandler)
-  }
+  // mounted(el, binding) {
+  //   //获取指令的参数
+  //   const {
+  //       value: {
+  //           placement, content, destroyOnLeave
+  //       } = {}
+  //   } = binding;
+  //   // 加上超出...样式
+  //   el.style.overflow = "hidden";
+  //   el.style.textOverflow = "ellipsis";
+  //   el.style.whiteSpace = "nowrap";
+  //   //鼠标移开时 清除元素
+  //   const onMouseLeave = () => {
+  //     if (el.w_tipInstance) {
+  //       el.w_tipInstance.hiddenTip()
+  //       el.w_tooltip.remove()
+  //       el.w_tipInstance = null
+  //       el.w_tooltip = null
+  //     }
+  //   };
+  //   const onMouseEnter = () => {
+  //     // 判断内容长度 需要展示
+  //     if (isOverflow(el)) {
+  //       // const positionXY = getPosition(el)
+  //       const directiveList = allPlacements.filter(placement => binding.modifiers[placement])
+  //       const placements = directiveList.length ? directiveList : allPlacements
+  //       if (!el.w_tooltip) {
+  //         // 创建tooltip实例
+  //         const vm = createApp(MyToolTip)
+  //         // 创建根元素
+  //         el.w_tooltip = document.createElement('div')
+  //         // 挂载到页面
+  //         document.body.appendChild(el.w_tooltip)
+  //         el.w_tooltip.id = `tooltip_${Math.floor(Math.random() * 10000)}`
+  //         el.w_tipInstance = vm.mount(el.w_tooltip)
+  //       }
+  //       // 设置 tooltip 显示方向
+  //       el.w_tipInstance.placements = placement || placements[0] || 'top'
+  //       // 设置显示内容
+  //       el.w_tipInstance.setContent(content || el.innerText)
+  //       // 使 tooltip 显示
+  //       el.w_tipInstance.showTip()
+  //       nextTick(() => {
+  //         // 计算 tooltip 在页面中的位置
+  //         calculationLocation(el.w_tipInstance, el, placements[0])
+  //       })
+  //       el._scrollHandler = () => {
+  //         // 重新定位位置
+  //         if (el.w_tipInstance && el.w_tipInstance.tooltipShow) calculationLocation(el.w_tipInstance, el, placements[0])
+  //       }
+  //       window.addEventListener('scroll', el._scrollHandler)
+  //       const _destroyOnLeave = destroyOnLeave || true
+  //       if (_destroyOnLeave) el.addEventListener("mouseleave", onMouseLeave);
+  //     }
+  //   };
+  //   el.addEventListener("mouseenter", onMouseEnter);
+  // },
+  // unmounted(el) {
+  //   if (el.w_tooltip) {
+  //     document.body.removeChild(el.w_tooltip)
+  //   }
+  //   window.removeEventListener('scroll', el._scrollHandler)
+  // }
 }
 }
 
 

+ 42 - 29
src/components/Enterprise/hotPromoted.vue

@@ -3,16 +3,16 @@
     <div class="sub-li" v-for="(item, index) in list" :key="index">
     <div class="sub-li" v-for="(item, index) in list" :key="index">
       <div v-if="item">
       <div v-if="item">
         <!-- 公司信息 -->
         <!-- 公司信息 -->
-        <div class="company-info-top align-center" @click.stop="jumpToEnterpriseDetail(item.enterprise.id, false)">
+        <div class="company-info-top align-center" :class="{'elevation-5': item.active}" @click.stop="jumpToEnterpriseDetail(item.enterprise.id, false)" @mouseenter="item.active = true" @mouseleave="item.active = false">
           <div class="float-left">
           <div class="float-left">
             <v-img :src="item?.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" alt="" width="77" height="77" style="border-radius: 4px;"/>
             <v-img :src="item?.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" alt="" width="77" height="77" style="border-radius: 4px;"/>
           </div>
           </div>
           <div class="company-info cursor-pointer">
           <div class="company-info cursor-pointer">
-            <h3 v-ellipse-tooltip.top>{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
-            <!-- <h3 :ref="el => { if(el) companyNameRefs[index] = el }">
+            <!-- <h3 v-ellipse-tooltip.top>{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3> -->
+            <h3 :ref="el => { if(el) companyNameRefs[index] = el }">
               {{ formatName(item.enterprise.anotherName || item.enterprise.name) }}
               {{ formatName(item.enterprise.anotherName || item.enterprise.name) }}
               <v-tooltip v-if="isTextOverflow[index]" activator="parent" location="top">{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</v-tooltip>
               <v-tooltip v-if="isTextOverflow[index]" activator="parent" location="top">{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</v-tooltip>
-            </h3> -->
+            </h3>
             <p>
             <p>
               {{ item?.enterprise.scaleName }}
               {{ item?.enterprise.scaleName }}
               <span class="septal-line" v-if="item.enterprise.industryName"></span>
               <span class="septal-line" v-if="item.enterprise.industryName"></span>
@@ -21,11 +21,11 @@
           </div>
           </div>
         </div>
         </div>
         <div v-ellipse-tooltip.top class="px-5 py-1 ellipsis-tag" :style="{'height': '33px', 'border-bottom': item.enterprise.welfareList && item.enterprise.welfareList.length ? '1px solid #EBEBEB' : 'none'}">
         <div v-ellipse-tooltip.top class="px-5 py-1 ellipsis-tag" :style="{'height': '33px', 'border-bottom': item.enterprise.welfareList && item.enterprise.welfareList.length ? '1px solid #EBEBEB' : 'none'}">
-          <span class="welfareTag mr-5" v-for="(k, i) in item.enterprise.welfareList" :key="i">{{ k }}</span>
+          <span class="welfareTag" v-for="(k, i) in item.enterprise.welfareList" :key="i">{{ spaces(i ? 4 : 0) + k }}</span>
         </div>
         </div>
         <!-- 职位列表 -->
         <!-- 职位列表 -->
         <!-- :class="{'company-job-item-hover': k.active}" -->
         <!-- :class="{'company-job-item-hover': k.active}" -->
-        <ul class="company-job-list">
+        <ul class="company-job-list pt-3">
           <li v-for="(k, i) in item.jobList" :key="i" @mouseenter="k.active = true" @mouseleave="k.active = false" @click="handleClickPosition(k)">
           <li v-for="(k, i) in item.jobList" :key="i" @mouseenter="k.active = true" @mouseleave="k.active = false" @click="handleClickPosition(k)">
             <v-card :elevation="k.active ? 5 : 0" class="company-job-item cursor-pointer mb-3">
             <v-card :elevation="k.active ? 5 : 0" class="company-job-item cursor-pointer mb-3">
               <div class="mb-2 d-flex">
               <div class="mb-2 d-flex">
@@ -47,8 +47,8 @@
             </v-card>
             </v-card>
           </li>
           </li>
         </ul>
         </ul>
-        <div class="moreBtn d-flex align-center justify-center" @click.stop="handleMoreEnterprise(item)" @mouseenter="item.active = true" @mouseleave="item.active = false">
-          <span :style="{'border-bottom': item.active ? '1px solid #fff' : 'none'}">{{ $t('position.moreBtn') }}</span>
+        <div class="moreBtn d-flex align-center justify-center" @click.stop="handleMoreEnterprise(item)">
+          <span>{{ $t('position.moreBtn') }}</span>
           <v-icon>mdi-menu-right</v-icon>
           <v-icon>mdi-menu-right</v-icon>
         </div>
         </div>
       </div>
       </div>
@@ -57,11 +57,12 @@
 </template>
 </template>
 
 
 <script setup name="hotPromoted">
 <script setup name="hotPromoted">
-import { ref, watch } from 'vue'
+import { nextTick, ref, watch } from 'vue'
 import { timesTampChange } from '@/utils/date'
 import { timesTampChange } from '@/utils/date'
 import { formatName } from '@/utils/getText'
 import { formatName } from '@/utils/getText'
 import { jumpToEnterpriseDetail } from '@/utils/position'
 import { jumpToEnterpriseDetail } from '@/utils/position'
 import { useRouter } from 'vue-router'
 import { useRouter } from 'vue-router'
+  import { spaces } from '@/utils/index.js'
 
 
 const props = defineProps({
 const props = defineProps({
   items: {
   items: {
@@ -72,25 +73,25 @@ const props = defineProps({
 
 
 const router = useRouter()
 const router = useRouter()
 
 
-// const isTextOverflow = ref({})
-// const companyNameRefs = ref({})
+const isTextOverflow = ref({})
+const companyNameRefs = ref({})
 // 检查文本是否溢出
 // 检查文本是否溢出
-// const checkTextOverflow = () => {
-//   Object.entries(companyNameRefs.value).forEach(([index, element]) => {
-//     if (element) {
-//       isTextOverflow.value[index] = element.scrollWidth > element.clientWidth
-//     }
-//   })
-// }
+const checkTextOverflow = () => {
+  Object.entries(companyNameRefs.value).forEach(([index, element]) => {
+    if (element) {
+      isTextOverflow.value[index] = element.scrollWidth > element.clientWidth
+    }
+  })
+}
 
 
 const list = ref([])
 const list = ref([])
 watch(
 watch(
   () => props.items, 
   () => props.items, 
   (newVal) => {
   (newVal) => {
     list.value = newVal
     list.value = newVal
-    // nextTick(() => {
-    //   checkTextOverflow()
-    // })
+    nextTick(() => {
+      checkTextOverflow()
+    })
   },
   },
   { immediate: true },
   { immediate: true },
   { deep: true }
   { deep: true }
@@ -104,9 +105,10 @@ const handleClickPosition = (k) => {
 
 
 // 查看更多职位
 // 查看更多职位
 const handleMoreEnterprise = (item) => {
 const handleMoreEnterprise = (item) => {
-  // if (!item.enterprise.id) return
+  if (!item.enterprise.id) return
   // window.open(`/recruit/personal/company/details/${item.enterprise.id}?key=recruitmentPositions`)
   // window.open(`/recruit/personal/company/details/${item.enterprise.id}?key=recruitmentPositions`)
-  window.open(`/recruit/personal/position?content=${item.enterprise.anotherName || item.enterprise.name}`)
+  const name = formatName(item.enterprise.anotherName || item.enterprise.name)
+  window.open(`/recruit/personal/position?content=${name.includes('&') ? encodeURIComponent(name) : name}`)
 }
 }
 </script>
 </script>
 
 
@@ -121,7 +123,7 @@ const handleMoreEnterprise = (item) => {
   min-width: calc((100% - 24px) / 3);
   min-width: calc((100% - 24px) / 3);
   max-width: calc((100% - 24px) / 3);
   max-width: calc((100% - 24px) / 3);
   margin: 0 12px 12px 0;
   margin: 0 12px 12px 0;
-  height: 360px + 12px;
+  height: 370px;
   border-radius: 12px;
   border-radius: 12px;
   padding: 0;
   padding: 0;
   overflow: hidden;
   overflow: hidden;
@@ -145,13 +147,15 @@ const handleMoreEnterprise = (item) => {
 }
 }
 .company-info-top {
 .company-info-top {
   display: flex;
   display: flex;
-  height: 110px;
-  padding: 16px 20px;
+  height: 90px;
+  margin: 12px 12px 0 12px;
+  padding: 0 12px;
   overflow: hidden;
   overflow: hidden;
   border-bottom: 1px solid #EBEBEB;
   border-bottom: 1px solid #EBEBEB;
-  &:hover {
-    background-color: #f2f4f7;
-  }
+  border-radius: 8px;
+  // &:hover {
+  //   background-color: #f2f4f7;
+  // }
 }
 }
 .welfareTag {
 .welfareTag {
   color: #CEC149;
   color: #CEC149;
@@ -191,6 +195,7 @@ ul li {
   height: auto;
   height: auto;
   padding: 12px 10px;
   padding: 12px 10px;
   margin: 0;
   margin: 0;
+  border-radius: 8px;
   // &-hover {
   // &-hover {
   //   background-color: #f2f4f7;
   //   background-color: #f2f4f7;
   // }
   // }
@@ -226,5 +231,13 @@ ul li {
   cursor: pointer;
   cursor: pointer;
   font-size: 14px;
   font-size: 14px;
   background: linear-gradient(to right, #12ebb0, #427daa);
   background: linear-gradient(to right, #12ebb0, #427daa);
+  &:hover {
+    // color: #cec149;
+    font-size: 16px;
+    span {
+      font-weight: 700;
+      text-decoration: underline;
+    }
+  }
 }
 }
 </style>
 </style>

+ 4 - 3
src/components/Position/item.vue

@@ -128,7 +128,7 @@ const handlePosition = (item) => {
     margin-right: 0;
     margin-right: 0;
   }
   }
   &:hover {
   &:hover {
-    box-shadow: 0 16px 40px 0 rgba(153, 153, 153, .3);
+    box-shadow: 0 2px 12px 0 rgba(153, 153, 153, 1);
   }
   }
 }
 }
 .job-info {
 .job-info {
@@ -199,15 +199,16 @@ const handlePosition = (item) => {
 }
 }
 .user-info {
 .user-info {
   // display: flex;
   // display: flex;
-  padding: 12px 20px;
+  padding: 10px 20px 12px;
   // align-items: center;
   // align-items: center;
   // justify-content: space-between;
   // justify-content: space-between;
+  background-color: #b2dfdb2b;
 }
 }
 .names {
 .names {
   font-weight: 500;
   font-weight: 500;
   color: #404040;
   color: #404040;
   &:hover {
   &:hover {
-    color: var(--v-primary-base);
+    color: var(--v-error-base);
   }
   }
 }
 }
 </style>
 </style>

+ 3 - 3
src/components/Position/longStrip.vue

@@ -19,7 +19,7 @@
       </div>
       </div>
       <div class="info-content" >
       <div class="info-content" >
         <div class="job-info">
         <div class="job-info">
-          <div class="job-name ellipsis" :class="{'cursor-pointer': val.job.status === '0'}">
+          <div v-ellipse-tooltip.top class="job-name ellipsis" :class="{'cursor-pointer': val.job.status === '0'}">
             <span class="mr-3" :class="{'info-name': val.job.status === '0'}" @click.stop="handleToPositionDetails(val)">{{ formatName(val.job.name) }}</span>
             <span class="mr-3" :class="{'info-name': val.job.status === '0'}" @click.stop="handleToPositionDetails(val)">{{ formatName(val.job.name) }}</span>
             <span>
             <span>
               [{{ !val.job.areaId ? '全国' : val.job.area?.str }}]
               [{{ !val.job.areaId ? '全国' : val.job.area?.str }}]
@@ -37,8 +37,8 @@
             <v-img width="50" height="50" :src="val.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/7.png'"></v-img>
             <v-img width="50" height="50" :src="val.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/7.png'"></v-img>
           </div>
           </div>
           <div class="ml-3">
           <div class="ml-3">
-            <div class="cursor-pointer info-name" @click.stop="jumpToEnterpriseDetail(val.enterprise.id)">{{ formatName(val.enterprise.anotherName || val.enterprise.name) }}</div>
-            <div class="mt-3 ellipsis color-666 font-size-13" style="max-width: 260px;">
+            <div v-ellipse-tooltip.top class="cursor-pointer ellipsis info-name" style="max-width: 480px;" @click.stop="jumpToEnterpriseDetail(val.enterprise.id)">{{ formatName(val.enterprise.anotherName || val.enterprise.name) }}</div>
+            <div v-ellipse-tooltip.top class="mt-3 ellipsis color-666 font-size-13" style="max-width: 260px;">
               <span v-for="(k, i) in desc" :key="k">
               <span v-for="(k, i) in desc" :key="k">
                 {{ val.enterprise[k] }}
                 {{ val.enterprise[k] }}
                 <span v-if="i !== desc.length - 1 && val.enterprise[k] && val.enterprise[desc[i + 1]]" class="septal-line"></span>
                 <span v-if="i !== desc.length - 1 && val.enterprise[k] && val.enterprise[desc[i + 1]]" class="septal-line"></span>

+ 524 - 0
src/components/PreviewImg/previewImage.vue

@@ -0,0 +1,524 @@
+<template>
+  <transition name="viewer-fade">
+    <div
+      ref="wrapper"
+      :tabindex="-1"
+      class="el-image-viewer__wrapper"
+      :style="{'z-index': zIndex}"
+    >
+      <div class="el-image-viewer__mask"  @click.self="hideOnClickModal && hide()"></div>
+      <!-- CLOSE -->
+      <span class="el-image-viewer__btn el-image-viewer__close" @click="hide">
+        <i class="el-icon">
+          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+            <path
+              fill="currentColor"
+              d="M764.288 214.592 512 466.88 259.712 214.592a31.936 31.936 0 0 0-45.12 45.12L466.752 512 214.528 764.224a31.936 31.936 0 1 0 45.12 45.184L512 557.184l252.288 252.288a31.936 31.936 0 0 0 45.12-45.12L557.12 512.064l252.288-252.352a31.936 31.936 0 1 0-45.12-45.184z"
+            ></path>
+          </svg>
+        </i>
+      </span>
+      <!-- ARROW -->
+      <template v-if="!isSingle">
+        <span
+          class="el-image-viewer__btn el-image-viewer__prev"
+          :class="{ 'is-disabled': !infinite && isFirst }"
+          @click="prev"
+        >
+          <i class="el-icon">
+            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z"
+              ></path>
+            </svg>
+          </i>
+        </span>
+        <span
+          class="el-image-viewer__btn el-image-viewer__next"
+          :class="{ 'is-disabled': !infinite && isLast }"
+          @click="next"
+        >
+          <i class="el-icon">
+            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z"
+              ></path>
+            </svg>
+          </i>
+        </span>
+      </template>
+      <!-- ACTIONS -->
+      <div
+        class="el-image-viewer__btn el-image-viewer__actions"
+        v-if="!isVideo(urlList[index])"
+      >
+        <div class="el-image-viewer__actions__inner">
+          <i class="el-icon" @click="handleActions('zoomOut')"
+            ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704M352 448h256a32 32 0 0 1 0 64H352a32 32 0 0 1 0-64"
+              ></path></svg
+          ></i>
+          <i class="el-icon" @click="handleActions('zoomIn')"
+            ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704m-32-384v-96a32 32 0 0 1 64 0v96h96a32 32 0 0 1 0 64h-96v96a32 32 0 0 1-64 0v-96h-96a32 32 0 0 1 0-64z"
+              ></path></svg
+          ></i>
+          <i class="el-image-viewer__actions__divider"></i>
+ 
+          <i class="el-icon" @click="toggleMode"
+            ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="m160 96.064 192 .192a32 32 0 0 1 0 64l-192-.192V352a32 32 0 0 1-64 0V96h64zm0 831.872V928H96V672a32 32 0 1 1 64 0v191.936l192-.192a32 32 0 1 1 0 64zM864 96.064V96h64v256a32 32 0 1 1-64 0V160.064l-192 .192a32 32 0 1 1 0-64l192-.192zm0 831.872-192-.192a32 32 0 0 1 0-64l192 .192V672a32 32 0 1 1 64 0v256h-64z"
+              ></path></svg
+          ></i>
+          <i class="el-image-viewer__actions__divider"></i>
+          <i class="el-icon" @click="handleActions('anticlocelise')"
+            ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="M289.088 296.704h92.992a32 32 0 0 1 0 64H232.96a32 32 0 0 1-32-32V179.712a32 32 0 0 1 64 0v50.56a384 384 0 0 1 643.84 282.88 384 384 0 0 1-383.936 384 384 384 0 0 1-384-384h64a320 320 0 1 0 640 0 320 320 0 0 0-555.712-216.448z"
+              ></path></svg
+          ></i>
+          <i class="el-icon" @click="handleActions('clocelise')"
+            ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+              <path
+                fill="currentColor"
+                d="M784.512 230.272v-50.56a32 32 0 1 1 64 0v149.056a32 32 0 0 1-32 32H667.52a32 32 0 1 1 0-64h92.992A320 320 0 1 0 524.8 833.152a320 320 0 0 0 320-320h64a384 384 0 0 1-384 384 384 384 0 0 1-384-384 384 384 0 0 1 643.712-282.88z"
+              ></path></svg
+          ></i>
+					<i class="el-icon" @click="handleDownload">
+						<svg data-v-d2e47025="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+							<path fill="currentColor" d="M160 832h704a32 32 0 1 1 0 64H160a32 32 0 1 1 0-64m384-253.696 236.288-236.352 45.248 45.248L508.8 704 192 387.2l45.248-45.248L480 584.704V128h64z"></path>
+						</svg>
+					</i>
+        </div>
+      </div>
+      <!-- CANVAS -->
+      <div class="el-image-viewer__canvas">
+        <template v-for="(url, i) in urlList" :key="i">
+          <img
+            v-if="i == index && !isVideo(url)"
+            ref="media"
+            :src="url"
+            :style="mediaStyle"
+            class="el-image-viewer__img"
+            @load="handleMediaLoad"
+            @error="handleMediaError"
+            @mousedown="handleMouseDown"
+          />
+          <video
+						v-if="i == index && isVideo(url)"
+            ref="media"
+            :src="url"
+						:controls="true"
+						:autoplay="true"
+            :style="mediaStyle"
+            class="el-image-viewer__img"
+            @load="handleMediaLoad"
+            @error="handleMediaError"
+            @mousedown="handleMouseDown"
+          >
+          </video>
+        </template>
+      </div>
+    </div>
+  </transition>
+</template>
+ 
+<script>
+import { computed, ref, onMounted, watch, nextTick } from 'vue'
+import { downloadImgVideo, downloadBase64 } from '@/utils'
+ 
+const EVENT_CODE = {
+  tab: 'Tab',
+  enter: 'Enter',
+  space: 'Space',
+  left: 'ArrowLeft', // 37
+  up: 'ArrowUp', // 38
+  right: 'ArrowRight', // 39
+  down: 'ArrowDown', // 40
+  esc: 'Escape',
+  delete: 'Delete',
+  backspace: 'Backspace'
+}
+ 
+const isFirefox = function () {
+  return !!window.navigator.userAgent.match(/firefox/i)
+}
+ 
+const rafThrottle = function (fn) {
+  let locked = false
+  return function (...args) {
+    if (locked) return
+    locked = true
+    window.requestAnimationFrame(() => {
+      fn.apply(this, args)
+      locked = false
+    })
+  }
+}
+ 
+const Mode = {
+  CONTAIN: {
+    name: 'contain',
+    icon: 'el-icon-full-screen'
+  },
+  ORIGINAL: {
+    name: 'original',
+    icon: 'el-icon-c-scale-to-original'
+  }
+}
+ 
+const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
+const CLOSE_EVENT = 'close'
+const SWITCH_EVENT = 'switch'
+ 
+export default {
+  name: 'ElMediaViewer',
+  props: {
+    urlList: {
+      type: Array,
+      default: () => []
+    },
+    zIndex: {
+      type: Number,
+      default: 2016
+    },
+    initialIndex: {
+      type: Number,
+      default: 0
+    },
+    infinite: {
+      type: Boolean,
+      default: true
+    },
+    hideOnClickModal: {
+      type: Boolean,
+      default: true
+    },
+		// 下载文件名
+		fileName: {
+			type: String,
+			default: ''
+		}
+  },
+  emits: [CLOSE_EVENT, SWITCH_EVENT],
+  setup(props, { emit }) {
+    let _keyDownHandler = null
+    let _mouseWheelHandler = null
+    let _dragHandler = null
+ 
+    const loading = ref(true)
+    const index = ref(props.initialIndex)
+    const wrapper = ref(null)
+    const media = ref(null)
+    const mode = ref(Mode.CONTAIN)
+    const transform = ref({
+      scale: 1,
+      deg: 0,
+      offsetX: 0,
+      offsetY: 0,
+      enableTransition: false
+    })
+		const isVideo = computed(() => (url) => {
+			return /\.(mp4|webm|ogg)$/i.test(url)
+		})
+ 
+    // 处理 video 有video 时 字段
+    const isSingle = computed(() => {
+      // const { urlList } = props
+      // urlList.forEach((item) => {
+      //   if (!item.type) {
+      //     item.type = item.response.type
+      //     if (item.response.thumbnailUrl) {
+      //       item.videoUrl = item.response.thumbnailUrl
+      //     }
+      //   }
+      // })
+      // return urlList.length <= 1
+			return false
+    })
+ 
+    const isFirst = computed(() => {
+      return index.value === 0
+    })
+ 
+    const isLast = computed(() => {
+      return index.value === props.urlList.length - 1
+    })
+ 
+    const currentMedia = computed(() => {
+      return props.urlList[index.value]
+    })
+ 
+    const isImage = computed(() => {
+      const currentUrl = props.urlList[index.value]
+      return currentUrl.endsWith('.jpg') || currentUrl.endsWith('.png')
+    })
+ 
+    const mediaStyle = computed(() => {
+      const { scale, deg, offsetX, offsetY, enableTransition } = transform.value
+      const style = {
+        transform: `scale(${scale}) rotate(${deg}deg)`,
+        transition: enableTransition ? 'transform .3s' : '',
+        marginLeft: `${offsetX}px`,
+        marginTop: `${offsetY}px`
+      }
+      if (mode.value.name === Mode.CONTAIN.name) {
+        style.maxWidth = style.maxHeight = '100%'
+      }
+      return style
+    })
+ 
+    function hide() {
+      deviceSupportUninstall()
+      emit(CLOSE_EVENT)
+    }
+ 
+    function deviceSupportInstall() {
+      _keyDownHandler = rafThrottle((e) => {
+        switch (e.code) {
+          // ESC
+          case EVENT_CODE.esc:
+            hide()
+            break
+          // SPACE
+          case EVENT_CODE.space:
+            toggleMode()
+            break
+          // LEFT_ARROW
+          case EVENT_CODE.left:
+            prev()
+            break
+          // UP_ARROW
+          case EVENT_CODE.up:
+            handleActions('zoomIn')
+            break
+          // RIGHT_ARROW
+          case EVENT_CODE.right:
+            next()
+            break
+          // DOWN_ARROW
+          case EVENT_CODE.down:
+            handleActions('zoomOut')
+            break
+        }
+      })
+ 
+      _mouseWheelHandler = rafThrottle((e) => {
+        const delta = e.wheelDelta ? e.wheelDelta : -e.detail
+        if (delta > 0) {
+          handleActions('zoomIn', {
+            zoomRate: 0.015,
+            enableTransition: false
+          })
+        } else {
+          handleActions('zoomOut', {
+            zoomRate: 0.015,
+            enableTransition: false
+          })
+        }
+      })
+ 
+      document.addEventListener('keydown', _keyDownHandler, false)
+      document.addEventListener(mousewheelEventName, _mouseWheelHandler, false)
+    }
+ 
+    function deviceSupportUninstall() {
+      document.removeEventListener('keydown', _keyDownHandler, false)
+      document.removeEventListener(
+        mousewheelEventName,
+        _mouseWheelHandler,
+        false
+      )
+      _keyDownHandler = null
+      _mouseWheelHandler = null
+    }
+ 
+    function handleMediaLoad() {
+      loading.value = false
+    }
+ 
+    function handleMediaError(e) {
+      loading.value = false
+    }
+ 
+    function handleMouseDown(e) {
+      if (loading.value || e.button !== 0) return
+ 
+      const { offsetX, offsetY } = transform.value
+      const startX = e.pageX
+      const startY = e.pageY
+ 
+      const divLeft = wrapper.value.clientLeft
+      const divRight = wrapper.value.clientLeft + wrapper.value.clientWidth
+      const divTop = wrapper.value.clientTop
+      const divBottom = wrapper.value.clientTop + wrapper.value.clientHeight
+ 
+      _dragHandler = rafThrottle((ev) => {
+        transform.value = {
+          ...transform.value,
+          offsetX: offsetX + ev.pageX - startX,
+          offsetY: offsetY + ev.pageY - startY
+        }
+      })
+      document.addEventListener('mousemove', _dragHandler, false)
+      document.addEventListener(
+        'mouseup',
+        (e) => {
+          const mouseX = e.pageX
+          const mouseY = e.pageY
+          if (
+            mouseX < divLeft ||
+            mouseX > divRight ||
+            mouseY < divTop ||
+            mouseY > divBottom
+          ) {
+            reset()
+          }
+          document.removeEventListener('mousemove', _dragHandler, false)
+        },
+        false
+      )
+ 
+      e.preventDefault()
+    }
+ 
+    function reset() {
+      transform.value = {
+        scale: 1,
+        deg: 0,
+        offsetX: 0,
+        offsetY: 0,
+        enableTransition: false
+      }
+    }
+ 
+    function toggleMode() {
+      if (loading.value) return
+ 
+      const modeNames = Object.keys(Mode)
+      const modeValues = Object.values(Mode)
+      const currentMode = mode.value.name
+      const index = modeValues.findIndex((i) => i.name === currentMode)
+      const nextIndex = (index + 1) % modeNames.length
+      mode.value = Mode[modeNames[nextIndex]]
+      reset()
+    }
+ 
+    function prev() {
+      if (isFirst.value && !props.infinite) return
+      const len = props.urlList.length
+      index.value = (index.value - 1 + len) % len
+    }
+ 
+    function next() {
+      if (isLast.value && !props.infinite) return
+      const len = props.urlList.length
+      index.value = (index.value + 1) % len
+    }
+ 
+    function handleActions(action, options = {}) {
+      if (loading.value) return
+      const { zoomRate, rotateDeg, enableTransition } = {
+        zoomRate: 0.2,
+        rotateDeg: 90,
+        enableTransition: true,
+        ...options
+      }
+      switch (action) {
+        case 'zoomOut':
+          if (transform.value.scale > 0.2) {
+            transform.value.scale = parseFloat(
+              (transform.value.scale - zoomRate).toFixed(3)
+            )
+          }
+          break
+        case 'zoomIn':
+          transform.value.scale = parseFloat(
+            (transform.value.scale + zoomRate).toFixed(3)
+          )
+          break
+        case 'clocelise':
+          transform.value.deg += rotateDeg
+          break
+        case 'anticlocelise':
+          transform.value.deg -= rotateDeg
+          break
+      }
+      transform.value.enableTransition = enableTransition
+    }
+
+		function handleDownload () {
+			const url = props.urlList[index.value]
+			const isOnlineImage = url.startsWith('http://') || url.startsWith('https://') // 判断是否为在线地址
+			const date = new Date()
+			const filename = props.fileName || `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
+			isOnlineImage ? downloadImgVideo(url, filename) : downloadBase64(url, filename)
+		}
+ 
+    watch(currentMedia, () => {
+      nextTick(() => {
+        const $media = media.value
+        if (!$media.complete) {
+          loading.value = true
+        }
+      })
+    })
+ 
+    watch(index, (val) => {
+      reset()
+      emit(SWITCH_EVENT, val)
+    })
+ 
+    onMounted(() => {
+      deviceSupportInstall()
+      wrapper.value?.focus?.()
+    })
+ 
+    return {
+      index,
+      wrapper,
+      media,
+      isSingle,
+      isFirst,
+      isLast,
+      currentMedia,
+      isImage,
+      isVideo,
+      mediaStyle,
+      mode,
+      handleActions,
+      prev,
+      next,
+      hide,
+      toggleMode,
+      handleMediaLoad,
+      handleMediaError,
+			handleDownload,
+      handleMouseDown
+    }
+  }
+}
+</script>
+ 
+<style lang="scss" scoped>
+// .el-icon {
+//   z-index: 200;
+// }
+// .el-image-viewer__btn {
+//   overflow: hidden;
+//   border-radius: 100px;
+//   opacity: 1;
+//   text-align: center;
+//   line-height: 44px;
+//   background-color: rgba($color: #0d0d0d, $alpha: 0.5);
+// }
+</style>

+ 3 - 8
src/components/headSearch/index.vue

@@ -66,12 +66,11 @@ const defineProps = defineProps({
     default: ''
     default: ''
   }
   }
 })
 })
-
 // const value = ref('')
 // const value = ref('')
 const value = ref(defineProps.modelValue)
 const value = ref(defineProps.modelValue)
 let drawer = ref(false)
 let drawer = ref(false)
 
 
-if (route.query && route.query?.content) value.value = route.query.content
+if (route.query && route.query?.content) value.value = route.query.content.includes('%') ? decodeURIComponent(route.query.content) : route.query.content
 
 
 // 点击外部关闭职位下拉
 // 点击外部关闭职位下拉
 const sharedState = useSharedState()
 const sharedState = useSharedState()
@@ -81,12 +80,8 @@ watch(() => sharedState.layoutClickCount, () => {
 });
 });
 
 
 const handleSearch = () => {
 const handleSearch = () => {
-  // // 职位搜索页传参,其它的跳转到职位搜索页
-  // if (route.path !== '/recruit/personal/position') {
-  //   if (value.value) router.push(`/recruit/personal/position?content=${value.value}`)
-  //   else router.push('/recruit/personal/position')
-  // } else emits('handleSearch', value.value)
-  emits('handleSearch', value.value)
+  const name = value.value ? value.value.includes('&') ? encodeURIComponent(value.value) : value.value : ''
+  emits('handleSearch', name)
 }
 }
 
 
 const handleClickJob = (val) => {
 const handleClickJob = (val) => {

+ 104 - 0
src/directives/previewImageDirective.js

@@ -0,0 +1,104 @@
+import { h, render } from 'vue';
+import { ElImageViewer } from 'element-plus';
+import { downloadImgVideo } from '@/utils'
+
+export default function (app) {
+	app.directive('previewImage', {
+		mounted(el, binding) {
+			const previewBox = document.createElement('div');
+			previewBox.classList.add('preview-box');
+			let vnode;
+
+			let downloadIndex
+
+			// 判断是否为视频文件
+			const isVideo = (url) => /\.(mp4|webm|ogg)$/i.test(url);
+
+			// 创建混合媒体预览组件
+			const createMixedMediaViewer = (urls, initialIndex = 0) => {
+				const mediaList = urls.map(url => ({
+					url,
+					isVideo: isVideo(url)
+				}));
+
+				const _el = h(ElImageViewer, {
+					urlList: urls,
+					initialIndex,
+					hideOnClickModal: true,
+					onClose: () => {
+						render(null, previewBox);
+						document.body.removeChild(previewBox);
+					},
+					onSwitch: (index) => {
+						downloadIndex = index
+						const elAll = document.querySelectorAll('.el-image-viewer__img');
+						const el = elAll[index];
+					
+						if (!isVideo(el.src) || el.tagName !== 'VIDEO') { // 当前是 IMG
+							elAll.forEach((item, i) => {
+								if (item.tagName === 'VIDEO') {
+									item.style.display = 'none'
+								} 
+							})
+						} else {
+							el.style.display = 'block'
+						}
+
+						if (isVideo(el.src) && el.tagName === 'IMG') {
+							const currentMedia = mediaList[index];
+							const canvasElement = document.querySelector('.el-image-viewer__canvas');
+							// 如果是视频,替换img标签为video标签
+							setTimeout(() => {
+								if (canvasElement) {
+									const videoElement = document.createElement('video');
+									videoElement.src = currentMedia.url;
+									videoElement.controls = true;
+									videoElement.autoplay = true;
+									videoElement.className = el.className;
+									videoElement.style.maxWidth = '100%';
+									videoElement.style.maxHeight = '100%';
+									canvasElement.appendChild(videoElement);
+									el.remove()
+								}
+							}, 0);
+						}
+					}
+				});
+				return _el
+			};
+
+			el.addEventListener('click', () => {
+				el.style.cursor = 'pointer';
+				const urls = Array.isArray(binding.value[0]) ? binding.value[0] : [binding.value[0]];
+				const initialIndex = binding.value[1] || 0;
+				downloadIndex = initialIndex
+				vnode = createMixedMediaViewer(urls, initialIndex);
+				render(vnode, previewBox);
+				document.body.appendChild(previewBox);
+
+
+				// 添加下载按钮
+				const action_btn = previewBox.children[0].children[4].children[0]
+				const divider = document.createElement('i')
+				divider.className = 'el-image-viewer__actions__divider'
+				action_btn.appendChild(divider)
+
+				const download_btn = document.createElement('i')
+				download_btn.className = 'el-icon'
+				download_btn.innerHTML = `<svg data-v-d2e47025="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
+					<path fill="currentColor" d="M160 832h704a32 32 0 1 1 0 64H160a32 32 0 1 1 0-64m384-253.696 236.288-236.352 45.248 45.248L508.8 704 192 387.2l45.248-45.248L480 584.704V128h64z"></path>
+				</svg>`
+
+				const date = new Date()
+				download_btn.addEventListener('click', () => {
+					const fileName = binding.value[2] || `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
+					downloadImgVideo(urls[downloadIndex], fileName)
+				})
+				action_btn.appendChild(download_btn)
+			});
+		},
+		unmounted(el) {
+			el.removeEventListener('click', () => {});
+		}
+	});
+}

+ 7 - 3
src/layout/personal/navBar.vue

@@ -205,9 +205,13 @@ const position = [
   '/recruit/personal/company/details',
   '/recruit/personal/company/details',
   '/recruit/personal/position/details'
   '/recruit/personal/position/details'
 ]
 ]
-const menuActive = computed(() => (val)=> {
-  return val.dealActive ? position.indexOf(route.path) !== -1 : (route.path === val.path || route.path.includes(val.path))
-})
+const menuActive = (val) => {
+  let path
+  position.forEach(e => {
+    if (route.path.indexOf(e) !== -1) path = e
+  })
+  return val.dealActive ? position.indexOf(path) !== -1 : (route.path === val.path || route.path.includes(val.path))
+}
 
 
 const vip = computed(() => {
 const vip = computed(() => {
   return new Date().getTime() < userStore.userInfo?.vipExpireDate
   return new Date().getTime() < userStore.userInfo?.vipExpireDate

+ 2 - 0
src/main.js

@@ -32,6 +32,7 @@ import VueLuckyCanvas from '@lucky-canvas/vue'
 import router from './router'
 import router from './router'
 
 
 import { ellipsisTooltip } from '@/components/CtTooltip/index.js'
 import { ellipsisTooltip } from '@/components/CtTooltip/index.js'
+// import imageDirective from '@/directives/previewImageDirective'
 
 
 import './permission'
 import './permission'
 
 
@@ -47,6 +48,7 @@ app.use(pinia)
 app.use(router)
 app.use(router)
 app.use(Clipboard)
 app.use(Clipboard)
 app.use(VueLuckyCanvas)
 app.use(VueLuckyCanvas)
+// imageDirective(app)
 
 
 
 
 // app.config.globalProperties.$echarts = echarts
 // app.config.globalProperties.$echarts = echarts

+ 1 - 0
src/styles/index.scss

@@ -7,6 +7,7 @@
   --v-primary-lighten2: #4DB6AC;
   --v-primary-lighten2: #4DB6AC;
   --v-primary-lighten3: #80CBC4;
   --v-primary-lighten3: #80CBC4;
   --v-primary-lighten4: #B2DFDB;
   --v-primary-lighten4: #B2DFDB;
+  --v-primary-lighten5: #b2dfdb9c;
   --color-222: #222;
   --color-222: #222;
   --color-333: #333;
   --color-333: #333;
   --color-666: #666;
   --color-666: #666;

+ 4 - 6
src/styles/recruit/company.css

@@ -33,9 +33,9 @@
 
 
 .sub-li {
 .sub-li {
   position: relative;
   position: relative;
-  width: calc((100% - 36px) / 4);
-  min-width: calc((100% - 36px) / 4);
-  max-width: calc((100% - 36px) / 4);
+  width: calc((100% - 24px) / 3);
+  min-width: calc((100% - 24px) / 3);
+  max-width: calc((100% - 24px) / 3);
   margin: 0 12px 12px 0;
   margin: 0 12px 12px 0;
   height: 160px;
   height: 160px;
   border-radius: 12px;
   border-radius: 12px;
@@ -46,7 +46,7 @@
   cursor: pointer;
   cursor: pointer;
 }
 }
 
 
-.sub-li:nth-child(4n) {
+.sub-li:nth-child(3n) {
   margin-right: 0;
   margin-right: 0;
 }
 }
 
 
@@ -92,9 +92,7 @@
 }
 }
 
 
 .company-info-bottom {
 .company-info-bottom {
-  width: 100%;
   height: 70px;
   height: 70px;
-  padding: 10px 15px;
 }
 }
 
 
 .name {
 .name {

+ 1 - 1
src/styles/recruit/company.min.css

@@ -1 +1 @@
-.label-title{width:64px;font-weight:500;margin-right:24px;color:var(--color-222)}.label-content{flex:1}.label-color{color:var(--color-222);font-size:14px;margin-right:24px;display:inline-block;cursor:pointer}.label-color:hover{color:var(--v-primary-base)}.actives{color:var(--v-primary-base);font-weight:600}.company-box{display:flex;flex-wrap:wrap}.sub-li{position:relative;width:calc((100% - 36px) / 4);min-width:calc((100% - 36px) / 4);max-width:calc((100% - 36px) / 4);margin:0 12px 12px 0;height:160px;border-radius:12px;padding:0;overflow:hidden;transition:all .2s linear;background-color:#fff;cursor:pointer}.sub-li:nth-child(4n){margin-right:0}.sub-li:hover{box-shadow:0 16px 40px 0 rgba(153,153,153,0.3)}.company-info{float:left;margin-left:16px;width:282px}.company-info-top{display:flex;height:90px;line-height:90px;padding:0 20px;align-items:center;overflow:hidden}.company-info h3{height:22px;font-size:18px;font-weight:700;color:var(--color-333);line-height:22px;margin:0 0 4px 0;padding:0;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.company-info p{height:18px;font-size:13px;font-weight:400;color:var(--color-999);line-height:18px}.company-info-bottom{width:100%;height:70px;padding:10px 15px}.name{position:relative;line-height:22px;color:#404040;margin-right:8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:all linear .2s}.salary{font-size:16px;float:right;color:var(--v-error-base);line-height:22px;max-width:none;text-align:right;flex:1}.job-hover:hover{color:var(--v-primary-base);background-color:#f2f4f7}
+.label-title{width:64px;font-weight:500;margin-right:24px;color:var(--color-222)}.label-content{flex:1}.label-color{color:var(--color-222);font-size:14px;margin-right:24px;display:inline-block;cursor:pointer}.label-color:hover{color:var(--v-primary-base)}.actives{color:var(--v-primary-base);font-weight:600}.company-box{display:flex;flex-wrap:wrap}.sub-li{position:relative;width:calc((100% - 24px) / 3);min-width:calc((100% - 24px) / 3);max-width:calc((100% - 24px) / 3);margin:0 12px 12px 0;height:160px;border-radius:12px;padding:0;overflow:hidden;transition:all .2s linear;background-color:#fff;cursor:pointer}.sub-li:nth-child(3n){margin-right:0}.sub-li:hover{box-shadow:0 16px 40px 0 rgba(153,153,153,0.3)}.company-info{float:left;margin-left:16px;width:282px}.company-info-top{display:flex;height:90px;line-height:90px;padding:0 20px;align-items:center;overflow:hidden}.company-info h3{height:22px;font-size:18px;font-weight:700;color:var(--color-333);line-height:22px;margin:0 0 4px 0;padding:0;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.company-info p{height:18px;font-size:13px;font-weight:400;color:var(--color-999);line-height:18px}.company-info-bottom{height:70px}.name{position:relative;line-height:22px;color:#404040;margin-right:8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:all linear .2s}.salary{font-size:16px;float:right;color:var(--v-error-base);line-height:22px;max-width:none;text-align:right;flex:1}.job-hover:hover{color:var(--v-primary-base);background-color:#f2f4f7}

+ 6 - 6
src/styles/recruit/company.scss

@@ -32,9 +32,9 @@
 
 
 .sub-li {
 .sub-li {
   position: relative;
   position: relative;
-  width: calc((100% - 36px) / 4);
-  min-width: calc((100% - 36px) / 4);
-  max-width: calc((100% - 36px) / 4);
+  width: calc((100% - 24px) / 3);
+  min-width: calc((100% - 24px) / 3);
+  max-width: calc((100% - 24px) / 3);
   margin: 0 12px 12px 0;
   margin: 0 12px 12px 0;
   height: 160px;
   height: 160px;
   border-radius: 12px;
   border-radius: 12px;
@@ -43,7 +43,7 @@
   transition: all .2s linear;
   transition: all .2s linear;
   background-color: #fff;
   background-color: #fff;
   cursor: pointer;
   cursor: pointer;
-  &:nth-child(4n) {
+  &:nth-child(3n) {
     margin-right: 0;
     margin-right: 0;
   }
   }
   &:hover {
   &:hover {
@@ -84,9 +84,9 @@
   line-height: 18px;
   line-height: 18px;
 }
 }
 .company-info-bottom {
 .company-info-bottom {
-  width: 100%;
+  // width: 100%;
   height: 70px;
   height: 70px;
-  padding: 10px 15px;
+  // margin: 10px 15px;
 }
 }
 .name {
 .name {
   position: relative;
   position: relative;

+ 20 - 1
src/utils/index.js

@@ -73,7 +73,26 @@ export const base64ToBlob = (code) => {
   })
   })
 }
 }
 
 
-export const downloadBase64 = (content, fileName) => {
+import axios from 'axios'
+export const downloadImgVideo = async (content, fileName) => {
+  try {
+    const response = await axios.get(content, { responseType: 'blob' });
+    const suffix = content.split('.').pop()
+    const url = window.URL.createObjectURL(new Blob([response.data]));
+    const link = document.createElement('a');
+    link.style.display = 'none';
+    link.href = url;
+    link.download = fileName + `.${suffix}`
+    document.body.appendChild(link);
+    link.click();
+    window.URL.revokeObjectURL(url);
+  } catch (error) {
+    console.error('Error downloading file:', error);
+  }
+}
+
+
+export const downloadBase64 = async (content, fileName) => {
   let aLink = document.createElement('a')
   let aLink = document.createElement('a')
   let blob = base64ToBlob(content)
   let blob = base64ToBlob(content)
   aLink.download = fileName + '.png'
   aLink.download = fileName + '.png'

+ 1 - 1
src/version.js

@@ -1,2 +1,2 @@
 // 版本号
 // 版本号
-export const vue_version = 'v25.01.14.1833'
+export const vue_version = 'v25.01.17.1849'

+ 1 - 1
src/views/recruit/entRegister/register.vue

@@ -70,7 +70,7 @@
         </v-btn>
         </v-btn>
       </div>
       </div>
     </v-card>
     </v-card>
-    <PreviewImg v-if="showPreview" :current="current" :list="[licenseUrl]" @close="showPreview = !showPreview"></PreviewImg>
+    <PreviewImage v-if="showPreview" :initialIndex="current" :urlList="[licenseUrl]" @close="showPreview = !showPreview" />
 
 
     <Loading :visible="loading"></Loading>
     <Loading :visible="loading"></Loading>
     
     

+ 13 - 1
src/views/recruit/enterprise/entInfoSetting/index.vue

@@ -31,11 +31,14 @@
               ref="componentRef"
               ref="componentRef"
               :is="item.path"
               :is="item.path"
               @complete="handleComplete"
               @complete="handleComplete"
+              @preview="handlePreview"
             />
             />
           </div>
           </div>
         </template>
         </template>
       </div>
       </div>
     </v-card>
     </v-card>
+
+    <PreviewImage v-if="showPreview" :initialIndex="initialIndex" :urlList="urlsList" @close="showPreview = !showPreview" />
   </div>
   </div>
 </template>
 </template>
 
 
@@ -56,9 +59,9 @@ import { useI18n } from '@/hooks/web/useI18n'
 
 
 const componentRef = ref()
 const componentRef = ref()
 
 
+const showPreview = ref(false)
 const route = useRoute()
 const route = useRoute()
 const { t } = useI18n()
 const { t } = useI18n()
-// tab
 const tab = ref(1)
 const tab = ref(1)
 const tabList = [
 const tabList = [
   { label: t('enterprise.infoSetting.basicInfo'), value: 1, path: basicInfo, id: 'basicInfo' },
   { label: t('enterprise.infoSetting.basicInfo'), value: 1, path: basicInfo, id: 'basicInfo' },
@@ -77,6 +80,15 @@ const status = ref([
   { id: 'businessInformation', status: false }
   { id: 'businessInformation', status: false }
 ])
 ])
 
 
+// 图片预览
+const urlsList = ref([])
+const initialIndex = ref(0)
+const handlePreview = (urls, index) => {
+  urlsList.value = urls
+  initialIndex.value = index || 0
+  showPreview.value = true
+}
+
 watch(() => route?.query?.tabKey, (newVal) => {
 watch(() => route?.query?.tabKey, (newVal) => {
   if (newVal) tab.value = newVal - 0
   if (newVal) tab.value = newVal - 0
 }, { deep: true, immediate: true })
 }, { deep: true, immediate: true })

+ 1 - 1
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/basicInfo.vue

@@ -34,7 +34,7 @@ import { useI18n } from '@/hooks/web/useI18n'
 import industryTypeCard from '@/components/industryTypeCard'
 import industryTypeCard from '@/components/industryTypeCard'
 import Snackbar from '@/plugins/snackbar'
 import Snackbar from '@/plugins/snackbar'
 import { useUserStore } from '@/store/user'
 import { useUserStore } from '@/store/user'
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'preview'])
 
 
 const { t } = useI18n()
 const { t } = useI18n()
 const CtFormRef = ref()
 const CtFormRef = ref()

+ 2 - 5
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/businessInformation.vue

@@ -16,7 +16,7 @@
               tips="上传图片" 
               tips="上传图片" 
               :value="licenseUrl"
               :value="licenseUrl"
               :showSnackbar="false" 
               :showSnackbar="false" 
-              @imgClick="showPreview = !showPreview" 
+              @imgClick="emit('preview', [licenseUrl])" 
               :showCursor="true" 
               :showCursor="true" 
               @success="handleUploadImg" 
               @success="handleUploadImg" 
               @delete="handleDeleteImg"
               @delete="handleDeleteImg"
@@ -26,7 +26,6 @@
       </template>
       </template>
     </CtForm>
     </CtForm>
     <Loading :visible="loading"></Loading>
     <Loading :visible="loading"></Loading>
-    <PreviewImg v-if="showPreview" :current="current" :list="[licenseUrl]" @close="showPreview = !showPreview"></PreviewImg>
     <div class="text-center">
     <div class="text-center">
       <v-btn color="primary" class="buttons mt-3 mb-10" @click="handleSave">{{ $t('common.save') }}</v-btn>
       <v-btn color="primary" class="buttons mt-3 mb-10" @click="handleSave">{{ $t('common.save') }}</v-btn>
     </div>
     </div>
@@ -42,12 +41,10 @@ import { useI18n } from '@/hooks/web/useI18n'
 import { getBusinessLicenseOCR } from '@/api/common'
 import { getBusinessLicenseOCR } from '@/api/common'
 import Confirm from '@/plugins/confirm'
 import Confirm from '@/plugins/confirm'
 // import { getDict } from '@/hooks/web/useDictionaries'
 // import { getDict } from '@/hooks/web/useDictionaries'
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'preview'])
 
 
 defineOptions({name: 'informationSettingsComponents-businessInformation'})
 defineOptions({name: 'informationSettingsComponents-businessInformation'})
 const { t } = useI18n()
 const { t } = useI18n()
-const showPreview = ref(false)
-const current = ref(0)
 let licenseUrl = ref('')
 let licenseUrl = ref('')
 // 图片预览
 // 图片预览
 const loading = ref(false)
 const loading = ref(false)

+ 3 - 12
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseAlbum.vue

@@ -27,15 +27,14 @@
       </v-btn>
       </v-btn>
     </div>
     </div>
     <div class="imgItem" v-for="(item, index) in imgList" :key="index">
     <div class="imgItem" v-for="(item, index) in imgList" :key="index">
-      <v-img v-if="checkIsImage(item)" width="100%" height="100%" :src="item" @click="handleClick(index)"></v-img>
-      <video v-else class="videos-radius mr-3" :src="item" controls height="172" width="172" preload="preload" @click="handleClick(index)"></video>
+      <v-img v-if="checkIsImage(item)" width="100%" height="100%" :src="item" @click="emit('preview', imgList, index)"></v-img>
+      <video v-else class="videos-radius mr-3" :src="item" controls height="172" width="172" preload="preload" @click="emit('preview', imgList, index)"></video>
       <div class="operate">
       <div class="operate">
         <span></span>
         <span></span>
         <span class="mdi mdi-trash-can-outline" @click="handleDelete(item)"></span>
         <span class="mdi mdi-trash-can-outline" @click="handleDelete(item)"></span>
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>
-  <PreviewImg v-if="showPreview" :current="current" :list="imgList" @close="showPreview = !showPreview"></PreviewImg>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
@@ -49,7 +48,7 @@ import Snackbar from '@/plugins/snackbar'
 import Confirm from '@/plugins/confirm'
 import Confirm from '@/plugins/confirm'
 import cloneDeep from 'lodash/cloneDeep'
 import cloneDeep from 'lodash/cloneDeep'
 
 
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'preview'])
 
 
 const { t } = useI18n()
 const { t } = useI18n()
 const imgList = ref([])
 const imgList = ref([])
@@ -68,14 +67,6 @@ const getInfo = async () => {
 }
 }
 getInfo()
 getInfo()
 
 
-// 预览
-const showPreview = ref(false)
-const current = ref(0)
-const handleClick = (index) => {
-  showPreview.value = !showPreview.value
-  current.value = index
-}
-
 // 删除
 // 删除
 const handleDelete = async (url) => {
 const handleDelete = async (url) => {
   const index = imgList.value.indexOf(url)
   const index = imgList.value.indexOf(url)

+ 1 - 1
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseLabel.vue

@@ -48,7 +48,7 @@ import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
 import { getEnterpriseBaseInfo, updateEnterpriseTag, getTagTreeDataApi } from '@/api/enterprise'
 import { getEnterpriseBaseInfo, updateEnterpriseTag, getTagTreeDataApi } from '@/api/enterprise'
 import { ref } from 'vue';
 import { ref } from 'vue';
 defineOptions({name: 'informationSettingsComponents-enterpriseLabel'})
 defineOptions({name: 'informationSettingsComponents-enterpriseLabel'})
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'preview'])
 
 
 const customTag = ref(false)
 const customTag = ref(false)
 const limitNum = ref(10)
 const limitNum = ref(10)

+ 1 - 1
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseLogo.vue

@@ -49,7 +49,7 @@ import { uploadFile } from '@/api/common'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useI18n } from '@/hooks/web/useI18n'
 import { updateEnterpriseLogo, getEnterpriseBaseInfo } from '@/api/enterprise'
 import { updateEnterpriseLogo, getEnterpriseBaseInfo } from '@/api/enterprise'
 import Snackbar from '@/plugins/snackbar'
 import Snackbar from '@/plugins/snackbar'
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'preview'])
 
 
 const { t } = useI18n()
 const { t } = useI18n()
 let squareImageUrl = ref('')
 let squareImageUrl = ref('')

+ 1 - 1
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/welfareLabel.vue

@@ -48,7 +48,7 @@ import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
 import { getEnterpriseBaseInfo, updateEnterpriseWelfare, getTagTreeDataApi } from '@/api/enterprise'
 import { getEnterpriseBaseInfo, updateEnterpriseWelfare, getTagTreeDataApi } from '@/api/enterprise'
 import { ref } from 'vue';
 import { ref } from 'vue';
 defineOptions({name: 'informationSettingsComponents-welfareLabel'})
 defineOptions({name: 'informationSettingsComponents-welfareLabel'})
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'preview'])
 
 
 const customTag = ref(false)
 const customTag = ref(false)
 const limitNum = ref(10)
 const limitNum = ref(10)

+ 4 - 3
src/views/recruit/enterprise/invoiceManagement/index.vue

@@ -101,6 +101,8 @@ const handleChangeCategory = (categoryType = 0) => { // 0: 个人, 1: 企业
   })
   })
   nextTick(() => {
   nextTick(() => {
     formItems.value.options = arr
     formItems.value.options = arr
+    const typeItem = formItems.value.options.find(e => e.key === 'type')
+    handleChangeType(typeItem?.value || 0)
   })
   })
 }
 }
 
 
@@ -109,10 +111,10 @@ const handleChangeType = (isVerified) => {
   invoiceHeaderTip.value = isVerified
   invoiceHeaderTip.value = isVerified
   formItems.value.options.forEach(e => {
   formItems.value.options.forEach(e => {
     if (business.value[e.key]) e.value = business.value[e.key] // business.value
     if (business.value[e.key]) e.value = business.value[e.key] // business.value
-    if (e.key === 'title') e.disabled = isVerified
+    if (e.key === 'title') e.disabled = Boolean(isVerified)
     if (e.rulesBaseLabel) {
     if (e.rulesBaseLabel) {
       e.label = isVerified ? `${e.rulesBaseLabel} *` : e.rulesBaseLabel
       e.label = isVerified ? `${e.rulesBaseLabel} *` : e.rulesBaseLabel
-      e.rules = isVerified ? [v => !!v || `请输入${e.rulesBaseLabel}`, ...e.rules] : []
+      e.rules = isVerified ? e.rules ? [v => !!v || `请输入${e.rulesBaseLabel}`, ...e.rules] : [v => !!v || `请输入${e.rulesBaseLabel}`] : []
     }
     }
   })
   })
 }
 }
@@ -258,7 +260,6 @@ const handle = (item) => {
   editId.value = item?.id || null
   editId.value = item?.id || null
   editInfo.value = item || null
   editInfo.value = item || null
   handleChangeCategory(item?.category || 0)
   handleChangeCategory(item?.category || 0)
-  handleChangeType(item?.type || 0)
   show.value = true
   show.value = true
 }
 }
 
 

+ 1 - 1
src/views/recruit/enterprise/talentMap/index.vue

@@ -49,7 +49,7 @@
     </template>
     </template>
     <!-- 人员信息表单 -->
     <!-- 人员信息表单 -->
     <CtTable
     <CtTable
-      v-if="dataList?.length"
+      v-if="dataList?.length && (chosenLabels?.length || content)"
       class="mt-3"
       class="mt-3"
       :items="dataList"
       :items="dataList"
       :headers="headers"
       :headers="headers"

+ 7 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/companyCollection.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div>
   <div>
     <div v-if="items.length">
     <div v-if="items.length">
-      <LongCompany :list="items" @refresh="getPositionList"></LongCompany>
+      <LongCompany :list="items" @refresh="handleCancelCollect"></LongCompany>
       <CtPagination
       <CtPagination
         :total="total"
         :total="total"
         :page="page.pageNo"
         :page="page.pageNo"
@@ -20,6 +20,7 @@ import { ref } from 'vue'
 import { dealDictArrayData } from '@/utils/position'
 import { dealDictArrayData } from '@/utils/position'
 import { getSubscribeEnterprise } from '@/api/position'
 import { getSubscribeEnterprise } from '@/api/position'
 
 
+const emit = defineEmits(['cancelCollect'])
 const total = ref(0)
 const total = ref(0)
 const items = ref([])
 const items = ref([])
 const page = ref({
 const page = ref({
@@ -36,6 +37,11 @@ const getPositionList = async () => {
 }
 }
 getPositionList()
 getPositionList()
 
 
+const handleCancelCollect = () => {
+  emit('cancelCollect', 1)
+  getPositionList()
+}
+
 const handleChangePage = (index) => {
 const handleChangePage = (index) => {
   page.value.pageNo = index
   page.value.pageNo = index
   getPositionList()
   getPositionList()

+ 1 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/interested.vue

@@ -6,7 +6,7 @@
       <v-tab :value="1">{{ subscribeCount > 0 ? `${$t('position.companyCollection')}(${subscribeCount})` : $t('position.companyCollection') }}</v-tab>
       <v-tab :value="1">{{ subscribeCount > 0 ? `${$t('position.companyCollection')}(${subscribeCount})` : $t('position.companyCollection') }}</v-tab>
     </v-tabs>
     </v-tabs>
     <div class="mt-3">
     <div class="mt-3">
-      <component :is="tabVal === 0 ? positionCollection : companyCollection"></component>
+      <component :is="tabVal === 0 ? positionCollection : companyCollection" @cancelCollect="val => val ? getSubscribeCount() : getFavoriteCount()"></component>
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>

+ 7 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/positionCollection.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div>
   <div>
     <div v-if="items.length">
     <div v-if="items.length">
-      <LongStrip :items="items" :showCancelBtn="true" @refresh="getPositionList"></LongStrip>
+      <LongStrip :items="items" :showCancelBtn="true" @refresh="handleCancelCollect"></LongStrip>
       <CtPagination
       <CtPagination
         :total="total"
         :total="total"
         :page="page.pageNo"
         :page="page.pageNo"
@@ -20,6 +20,7 @@ import { ref } from 'vue'
 import { dealDictObjData } from '@/utils/position'
 import { dealDictObjData } from '@/utils/position'
 import { getJobFavoriteList } from '@/api/position'
 import { getJobFavoriteList } from '@/api/position'
 
 
+const emit = defineEmits(['cancelCollect'])
 const total = ref(0)
 const total = ref(0)
 const items = ref([])
 const items = ref([])
 const page = ref({
 const page = ref({
@@ -41,6 +42,11 @@ const getPositionList = async () => {
 }
 }
 getPositionList()
 getPositionList()
 
 
+const handleCancelCollect = () => {
+  emit('cancelCollect', 0)
+  getPositionList()
+}
+
 const handleChangePage = (index) => {
 const handleChangePage = (index) => {
   page.value.pageNo = index
   page.value.pageNo = index
   getPositionList()
   getPositionList()

+ 3 - 4
src/views/recruit/personal/company/components/companyItem.vue

@@ -6,15 +6,15 @@
           <v-img :src="item.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" :alt="item.enterprise.anotherName" :width="40" style="height: 40px;border-radius: 4px;"/>
           <v-img :src="item.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" :alt="item.enterprise.anotherName" :width="40" style="height: 40px;border-radius: 4px;"/>
         </div>
         </div>
         <div class="company-info">
         <div class="company-info">
-          <h3 :class="{'default-active': item.active }" style="width: 200px;">{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
+          <h3 :class="{'default-active': item.active }">{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
           <p>{{ item.enterprise.industryName }}</p>
           <p>{{ item.enterprise.industryName }}</p>
         </div>
         </div>
       </div>
       </div>
       <v-divider class="mx-4"></v-divider>
       <v-divider class="mx-4"></v-divider>
-      <div class="company-info-bottom">
+      <div class="company-info-bottom mx-4 mt-2">
         <div v-if="item?.job && Object.keys(item.job).length" class="job-hover" @click.stop="handleClickPosition(item.job)">
         <div v-if="item?.job && Object.keys(item.job).length" class="job-hover" @click.stop="handleClickPosition(item.job)">
           <div class="mb-1 d-flex">
           <div class="mb-1 d-flex">
-            <p :class="['mr-3', 'cursor-pointer', 'name']" :style="{'max-width': !item.job.payFrom && !item.job.payTo ? '200px' : '120px'}">{{ formatName(item.job.name) }}</p>
+            <p :class="['mr-3', 'cursor-pointer', 'name']" :style="{'max-width': !item.job.payFrom && !item.job.payTo ? '270px' : '220px'}">{{ formatName(item.job.name) }}</p>
             <span v-if="!item.job.payFrom && !item.job.payTo" class="salary">面议</span>
             <span v-if="!item.job.payFrom && !item.job.payTo" class="salary">面议</span>
             <span v-else class="salary">{{ item.job.payFrom ? item.job.payFrom + '-' : '' }}{{ item.job.payTo }}{{ item.job.payName ? '/' + item.job.payName : '' }}</span>
             <span v-else class="salary">{{ item.job.payFrom ? item.job.payFrom + '-' : '' }}{{ item.job.payTo }}{{ item.job.payName ? '/' + item.job.payName : '' }}</span>
           </div>
           </div>
@@ -22,7 +22,6 @@
             <span v-for="(j, index) in desc" :key="index">
             <span v-for="(j, index) in desc" :key="index">
               <span v-if="item.job[j] || j === 'areaName'" class="mr-1 font-size-13">
               <span v-if="item.job[j] || j === 'areaName'" class="mr-1 font-size-13">
                 {{ j === 'areaName' ? !item.job.areaId ? '全国' : item.job.area.str : item.job[j] }}
                 {{ j === 'areaName' ? !item.job.areaId ? '全国' : item.job.area.str : item.job[j] }}
-                <!-- {{ (j === 'areaName' && !item.job.areaId) ? '全国' : item.job[j] }} -->
               </span>
               </span>
               <span v-if="index !== desc.length - 1 && (item.job[desc[index + 1]] || j === 'areaName')" class="septal-line ml-1"></span>
               <span v-if="index !== desc.length - 1 && (item.job[desc[index + 1]] || j === 'areaName')" class="septal-line ml-1"></span>
             </span>
             </span>

+ 1 - 1
src/views/recruit/personal/company/index.vue

@@ -48,7 +48,7 @@ const total = ref(0)
 const items = ref([])
 const items = ref([])
 const pages = ref({
 const pages = ref({
   pageNo: 1,
   pageNo: 1,
-  pageSize: 12
+  pageSize: 9
 })
 })
 const query = ref({})
 const query = ref({})
 
 

+ 4 - 4
src/views/recruit/personal/companyDetail/components/introduction.vue

@@ -16,16 +16,16 @@
     <div>
     <div>
       <h4>公司相册</h4>
       <h4>公司相册</h4>
       <v-slide-group v-if="props.info.enterprise.albumList" :show-arrows="true" class="mt-3 img-box cursor-pointer">
       <v-slide-group v-if="props.info.enterprise.albumList" :show-arrows="true" class="mt-3 img-box cursor-pointer">
-        <v-slide-group-item v-for="(val, i) in props.info.enterprise.albumList" :key="val">
+        <v-slide-group-item v-for="(val, i) in props.info.enterprise.albumList" :key="i">
           <div>
           <div>
-            <v-img v-if="checkIsImage(val)" class="mr-3" width="200" height="115" :src="val" cover rounded @click="handleClick(i)"></v-img>
-            <video v-else class="videos-radius mr-3" :src="val" controls height="118" width="200" preload="preload" @click="handleClick(i)"></video>
+            <v-img v-if="checkIsImage(val)" class="mr-3" width="200" height="115" :src="val" cover rounded @click.stop="handleClick(i)"></v-img>
+            <video v-else class="videos-radius mr-3" :src="val" controls height="118" width="200" preload="preload" @click.stop="handleClick(i)"></video>
           </div>
           </div>
         </v-slide-group-item>
         </v-slide-group-item>
       </v-slide-group>
       </v-slide-group>
       <div v-else>暂无</div>
       <div v-else>暂无</div>
     </div>
     </div>
-    <PreviewImg v-if="showPreview" :current="current" :list="props.info.enterprise.albumList" @close="showPreview = !showPreview"></PreviewImg>
+    <PreviewImage v-if="showPreview" :initialIndex="current" :urlList="props.info.enterprise.albumList" @close="showPreview = !showPreview" />
   </div>
   </div>
 </template>
 </template>
 
 

+ 20 - 9
src/views/recruit/personal/home/components/advertisement/preferred.vue

@@ -21,15 +21,26 @@
       <div class="desc">
       <div class="desc">
         <p v-html="result?.introduce?.describe"></p>
         <p v-html="result?.introduce?.describe"></p>
       </div>
       </div>
-			<div v-if="result?.introduce?.thumbnail?.length" class="culture my-15">
-        <div v-for="(k, i) in result.introduce.thumbnail" :key="i" class="culture-item">
-          <v-img :src="k" :lazy-src="k" width="350" height="230" contain>
-						<template v-slot:placeholder>
-							<v-row align="center" class="fill-height ma-0" justify="center">
-								<v-progress-circular color="grey-lighten-5" indeterminate></v-progress-circular>
-							</v-row>
-						</template>
-					</v-img>
+			<div v-if="result?.introduce?.thumbnail?.length" class="my-15">
+        <div class="culture" v-if="result?.introduce?.thumbnail?.length > 1">
+          <div v-for="(k, i) in result.introduce.thumbnail" :key="i" class="culture-item">
+            <v-img :src="k" :lazy-src="k" width="350" height="230" contain>
+              <template v-slot:placeholder>
+                <v-row align="center" class="fill-height ma-0" justify="center">
+                  <v-progress-circular color="grey-lighten-5" indeterminate></v-progress-circular>
+                </v-row>
+              </template>
+            </v-img>
+          </div>
+        </div>
+        <div v-else>
+          <v-img :src="result.introduce.thumbnail[0]" :lazy-src="result.introduce.thumbnail[0]" width="1184" height="500" contain>
+            <template v-slot:placeholder>
+              <v-row align="center" class="fill-height ma-0" justify="center">
+                <v-progress-circular color="grey-lighten-5" indeterminate></v-progress-circular>
+              </v-row>
+            </template>
+          </v-img>
         </div>
         </div>
       </div>
       </div>
       <div v-if="result?.introduce?.bigPicture?.url">
       <div v-if="result?.introduce?.bigPicture?.url">

+ 2 - 14
src/views/recruit/personal/home/components/hotPromotedPositions.vue

@@ -16,21 +16,9 @@
         <PositionCard v-if="items.filter(Boolean) && items.length" :isOpenWindow="false" :items="items" :tab="tab" @position="handlePosition"></PositionCard>
         <PositionCard v-if="items.filter(Boolean) && items.length" :isOpenWindow="false" :items="items" :tab="tab" @position="handlePosition"></PositionCard>
         <Empty v-else class="mb-3" :elevation="false"></Empty>
         <Empty v-else class="mb-3" :elevation="false"></Empty>
       </v-window-item>
       </v-window-item>
-      <!-- <v-window-item :value="1">
-        <PositionCard v-if="items.filter(Boolean) && items.length" :items="items" :tab="tab" @position="handlePosition"></PositionCard>
-        <Empty v-else class="mb-3" :elevation="false"></Empty>
-      </v-window-item>
-      <v-window-item :value="2">
-        <PositionCard v-if="items.filter(Boolean) && items.length" :isOpenWindow="false" :items="items" :tab="tab" @position="handlePosition"></PositionCard>
-        <Empty v-else class="mb-3" :elevation="false"></Empty>
-      </v-window-item>
-      <v-window-item :value="3">
-        <PositionCard v-if="items.filter(Boolean) && items.length" :isOpenWindow="false" :items="items" :tab="tab" @position="handlePosition"></PositionCard>
-        <Empty v-else class="mb-3" :elevation="false"></Empty>
-      </v-window-item> -->
     </v-window>
     </v-window>
     <div class="text-center mt-5" style="border-top: 1px solid #ccc; padding-top: 30px;">
     <div class="text-center mt-5" style="border-top: 1px solid #ccc; padding-top: 30px;">
-      <v-btn class="buttons btnColor" @click.stop="handleToMore">{{ $t('position.moreBtn') }}</v-btn>
+      <v-btn class="buttons btnColor" elevation="5" @click.stop="handleToMore">{{ $t('position.moreBtn') }}</v-btn>
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>
@@ -62,7 +50,7 @@ const handlePosition = (item) => {
 }
 }
 
 
 const handleToMore = () => {
 const handleToMore = () => {
-  window.open('/recruit/personal/position')
+  window.open(tab.value === 1 ? '/recruit/personal/recommend' : '/recruit/personal/position')
 }
 }
 </script>
 </script>
 
 

+ 1 - 1
src/views/recruit/personal/home/components/popularEnterprises.vue

@@ -9,7 +9,7 @@
     <HotPromoted v-if="items.length" class="mt-5" :items="items"></HotPromoted>
     <HotPromoted v-if="items.length" class="mt-5" :items="items"></HotPromoted>
     <Empty v-else :elevation="false" class="mt-3" message="暂无精选企业"></Empty>
     <Empty v-else :elevation="false" class="mt-3" message="暂无精选企业"></Empty>
     <div v-if="items.length" class="text-center">
     <div v-if="items.length" class="text-center">
-      <v-btn class="buttons btnColor" color="primary" @click.stop="handleToMore">{{ $t('enterprise.moreBtn') }}</v-btn>
+      <v-btn class="buttons btnColor" elevation="5" color="primary" @click.stop="handleToMore">{{ $t('enterprise.moreBtn') }}</v-btn>
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>

+ 7 - 3
src/views/recruit/personal/home/index.vue

@@ -73,7 +73,11 @@ const preferredContent = ref({})
 const getSystemWebContent = async () => {
 const getSystemWebContent = async () => {
   const data = await getWebContent()
   const data = await getWebContent()
   // 优选集团
   // 优选集团
-  preferred.value = data.pcHomePreferred
+  preferred.value = data.pcHomePreferred ? data.pcHomePreferred.sort((a, b) => {
+    const sortA = a.sort || Infinity
+    const sortB = b.sort || Infinity
+    return sortA - sortB
+  }) : []
   preferredContent.value = data.appPreferredGroup
   preferredContent.value = data.appPreferredGroup
   // 顶部广告
   // 顶部广告
   topAdvertise.value = data.pcTop && data.pcTop.length ? data.pcTop[0].img : ''
   topAdvertise.value = data.pcTop && data.pcTop.length ? data.pcTop[0].img : ''
@@ -146,14 +150,14 @@ onMounted(async () => {
 .stickyBox {
 .stickyBox {
   position: sticky;
   position: sticky;
   top: 48px;
   top: 48px;
-  z-index: 999;
+  z-index: 998;
   background-color: var(--default-bgc);
   background-color: var(--default-bgc);
 }
 }
 .advertiseBox {
 .advertiseBox {
   position: sticky;
   position: sticky;
   top: 150px;
   top: 150px;
   left: 0;
   left: 0;
-  // z-index: 999;
+  z-index: 998;
   width: 15px;
   width: 15px;
   max-width: 180px;
   max-width: 180px;
   margin-left: -200px;
   margin-left: -200px;

+ 23 - 49
src/views/recruit/personal/position/components/details.vue

@@ -8,22 +8,24 @@
         </div>
         </div>
         <v-btn v-if="showContentRight" color="primary" variant="text" size="large" @click.stop="handleReturn" prepend-icon="mdi-chevron-triple-left">返回上一页</v-btn>
         <v-btn v-if="showContentRight" color="primary" variant="text" size="large" @click.stop="handleReturn" prepend-icon="mdi-chevron-triple-left">返回上一页</v-btn>
       </div>
       </div>
-      <div class="text-end">
-        <span v-if="!info.payFrom && !info.payTo" class="salary font-size-20">面议</span>
-        <span v-else class="salary font-size-20">{{ info.payFrom ? info.payFrom + '-' : ''}}{{ info.payTo }}{{ positionInfo.payName ? '/' + positionInfo.payName : '' }}</span>
-      </div>
-      <div class="refresh-time text-end">{{ timesTampChange(info.updateTime) }} {{ $t('common.refresh') }} <v-icon color="primary" size="20">mdi-circle-medium</v-icon></div>
-      <div class="banner-tags mt-4">
-        <span v-for="k in desc" :key="k.mdi">
-          <span v-if="positionInfo[k.value] || k.value === 'areaName'" class="mr-10">
-            <v-icon color="var(--color-666)" size="20">{{ k.mdi }}</v-icon>
-            <span class="ml-1">
-              {{ k.value === 'areaName' ? !positionInfo.areaId ? '全国' : positionInfo.area?.str : positionInfo[k.value] }}
-              <!-- {{ (k.value === 'areaName' && !positionInfo.areaId) ? '全国' : positionInfo[k.value] }} -->
+      <div class="d-flex mt-1 justify-space-between align-center">
+        <div class="banner-tags">
+          <span v-for="k in desc" :key="k.mdi">
+            <span v-if="positionInfo[k.value] || k.value === 'areaName'" class="mr-10">
+              <v-icon color="var(--color-666)" size="20">{{ k.mdi }}</v-icon>
+              <span class="ml-1">
+                {{ k.value === 'areaName' ? !positionInfo.areaId ? '全国' : positionInfo.area?.str : positionInfo[k.value] }}
+                <!-- {{ (k.value === 'areaName' && !positionInfo.areaId) ? '全国' : positionInfo[k.value] }} -->
+              </span>
             </span>
             </span>
           </span>
           </span>
-        </span>
+        </div>
+        <div>
+          <span v-if="!info.payFrom && !info.payTo" class="salary font-size-20">面议</span>
+          <span v-else class="salary font-size-20">{{ info.payFrom ? info.payFrom + '-' : ''}}{{ info.payTo }}{{ positionInfo.payName ? '/' + positionInfo.payName : '' }}</span>
+        </div>
       </div>
       </div>
+      <div class="refresh-time text-end">{{ timesTampChange(info.updateTime) }} {{ $t('common.refresh') }} <v-icon color="primary" size="20">mdi-circle-medium</v-icon></div>
       <div class="banner-tools my-4">
       <div class="banner-tools my-4">
         <v-chip size="small" label v-for="(k, i) in info.tagList" :key="i" class="mr-1" color="primary">{{ k }}</v-chip>
         <v-chip size="small" label v-for="(k, i) in info.tagList" :key="i" class="mr-1" color="primary">{{ k }}</v-chip>
       </div>
       </div>
@@ -126,34 +128,11 @@
     <!-- 选择简历 -->
     <!-- 选择简历 -->
     <selectResumeDialog v-model="showResume" :list="resumeList" @submit="handleSubmit" @close="handleClose"></selectResumeDialog>
     <selectResumeDialog v-model="showResume" :list="resumeList" @submit="handleSubmit" @close="handleClose"></selectResumeDialog>
 
 
-    <!-- 职位分享 -->
-    <Dialog
-      :visible="shareDialog" :widthType="2" :footer="false" titleClass="text-h6"
-      :title="$t('position.rewardsShared')"
-      @close="shareDialog = false"
-    >
-      <div>
-        <div class="mb-3 text-center">微信分享:保存图片分享给好友</div>
-        <div class="d-flex align-center flex-column">
-          <v-img :src="previewSrc" width="200" height="250"></v-img>
-          <div class="mt-5">
-            <v-btn color="primary" variant="outlined" prepend-icon="mdi-eye-outline" @click="showPreview = true" style="width: 133px">预 览</v-btn>
-            <v-btn class="ml-3" color="primary" variant="outlined" prepend-icon="mdi-arrow-down-bold-box-outline" @click="handleDownloadImage" style="width: 133px">保存到本地</v-btn>
-          </div>
-        </div>
-      </div>
-      <template #footer>
-        <v-divider></v-divider>
-        <div>
-          <v-btn class="float-right ma-2" color="primary" variant="text" @click="shareDialog = false">{{ $t('common.close') }}</v-btn>
-        </div>
-      </template>
-    </Dialog>
-    <PreviewImg v-if="showPreview" :list="[previewSrc]" @close="showPreview = false" @download="handleDownloadImage"   :isImage="true"></PreviewImg>
+    <!-- 图片预览 -->
+    <PreviewImage v-if="showPreview" :urlList="[previewSrc]" :fileName="fileName" @close="showPreview = !showPreview" />
 
 
     <Loading :visible="loading"></Loading>
     <Loading :visible="loading"></Loading>
     <div v-if="Object.keys(info).length && Object.keys(positionInfo).length" style="position: absolute; left: -9999px; bottom: 0">
     <div v-if="Object.keys(info).length && Object.keys(positionInfo).length" style="position: absolute; left: -9999px; bottom: 0">
-      
       <PosterPage :id="id" :info="info" :positionInfo="positionInfo" ref="share"></PosterPage>
       <PosterPage :id="id" :info="info" :positionInfo="positionInfo" ref="share"></PosterPage>
     </div>
     </div>
 
 
@@ -164,7 +143,7 @@
 
 
 <script setup>
 <script setup>
 defineOptions({ name: 'position-details' })
 defineOptions({ name: 'position-details' })
-import { ref } from 'vue'
+import { ref, computed } from 'vue'
 import { useRouter } from 'vue-router'
 import { useRouter } from 'vue-router'
 import Snackbar from '@/plugins/snackbar'
 import Snackbar from '@/plugins/snackbar'
 import html2canvas from 'html2canvas'
 import html2canvas from 'html2canvas'
@@ -174,7 +153,6 @@ import PosterPage from './poster.vue'
 import selectResumeDialog from './jobDetails/selectResumeDialog'
 import selectResumeDialog from './jobDetails/selectResumeDialog'
 import similarPositions from '@/components/Position/similarPositions.vue'
 import similarPositions from '@/components/Position/similarPositions.vue'
 import EnterpriseInfo from '@/components/Enterprise/info.vue'
 import EnterpriseInfo from '@/components/Enterprise/info.vue'
-import Dialog from '@/components/CtDialog'
 import loginPage from '@/views/common/loginDialog.vue'
 import loginPage from '@/views/common/loginDialog.vue'
 import {
 import {
   getPositionDetails,
   getPositionDetails,
@@ -187,7 +165,7 @@ import {
 } from '@/api/position'
 } from '@/api/position'
 import { getPersonResumeCv, savePersonResumeCv } from '@/api/recruit/personal/resume'
 import { getPersonResumeCv, savePersonResumeCv } from '@/api/recruit/personal/resume'
 
 
-import { downloadBase64, DPR } from '@/utils'
+import { DPR } from '@/utils'
 import { timesTampChange } from '@/utils/date'
 import { timesTampChange } from '@/utils/date'
 import { dealDictObjData, dealDictArrayData, commissionCalculation } from '@/utils/position'
 import { dealDictObjData, dealDictArrayData, commissionCalculation } from '@/utils/position'
 import { getToken } from '@/utils/auth'
 import { getToken } from '@/utils/auth'
@@ -298,15 +276,12 @@ const generateAndDownloadImage = async () => {
   }
   }
 }
 }
 
 
-// 保存图片到本地
-const handleDownloadImage = () => {
+// 职位详情分享图片下载文件名
+const fileName = computed(() => {
   const { name, areaName, payFrom, payTo } = info.value
   const { name, areaName, payFrom, payTo } = info.value
   const salary = payFrom && payTo ? `${payFrom ? '_' + payFrom + '-' : ''}${payTo}` : '-面议'
   const salary = payFrom && payTo ? `${payFrom ? '_' + payFrom + '-' : ''}${payTo}` : '-面议'
-  downloadBase64(previewSrc.value, `${name}${areaName ? '_' + areaName : ''}${salary}${positionInfo.value.payName ? '-' + positionInfo.value.payName : ''}`)
-  setTimeout(() => {
-    Snackbar.success('下载成功')
-  }, 500);
-}
+  return `${name}${areaName ? '_' + areaName : ''}${salary}${positionInfo.value.payName ? '-' + positionInfo.value.payName : ''}`
+})
 
 
 // 相似职位
 // 相似职位
 const similarList = ref([])
 const similarList = ref([])
@@ -352,7 +327,6 @@ const getCollectionStatus = async () => {
 getCollectionStatus()
 getCollectionStatus()
 
 
 // 分享有礼
 // 分享有礼
-const shareDialog = ref(false)
 const handleShare = async () => {
 const handleShare = async () => {
   nextFunc.value = handleShare // 登录成功或强制填写个人信息成功后回调
   nextFunc.value = handleShare // 登录成功或强制填写个人信息成功后回调
   if (!getToken()) {
   if (!getToken()) {

+ 4 - 2
src/views/recruit/personal/position/components/poster.vue

@@ -7,8 +7,6 @@
         <!-- 职位名称+薪资 -->
         <!-- 职位名称+薪资 -->
         <div class="d-flex justify-space-between mx-5">
         <div class="d-flex justify-space-between mx-5">
           <h2 class="JobName ellipsis">{{ formatName(info.name) }}</h2>
           <h2 class="JobName ellipsis">{{ formatName(info.name) }}</h2>
-          <span v-if="!info.payFrom && !info.payTo" class="salary">面议</span>
-          <span v-else class="salary">{{ info.payFrom ? info.payFrom + '-' : '' }}{{ info.payTo }}{{ positionInfo.payName ? '/' + positionInfo.payName : '' }}</span>
         </div>
         </div>
         <!-- 地区、工作经验、学历 -->
         <!-- 地区、工作经验、学历 -->
         <div class="d-flex justify-space-between mx-5">
         <div class="d-flex justify-space-between mx-5">
@@ -21,6 +19,10 @@
               <span v-if="i !== desc.length - 1 && (positionInfo[k.value] || k.value === 'areaName')" class="septal-line"></span>
               <span v-if="i !== desc.length - 1 && (positionInfo[k.value] || k.value === 'areaName')" class="septal-line"></span>
             </div>
             </div>
           </div>
           </div>
+          <div>
+            <span v-if="!info.payFrom && !info.payTo" class="salary">面议</span>
+            <span v-else class="salary">{{ info.payFrom ? info.payFrom + '-' : '' }}{{ info.payTo }}{{ positionInfo.payName ? '/' + positionInfo.payName : '' }}</span>
+          </div>
         </div>
         </div>
         <!-- 企业信息 -->
         <!-- 企业信息 -->
         <div class="radius pa-3 mx-5 mt-5 d-flex align-center" style="background-color: #5baea6;">
         <div class="radius pa-3 mx-5 mt-5 d-flex align-center" style="background-color: #5baea6;">

+ 7 - 8
src/views/recruit/personal/position/index.vue

@@ -45,7 +45,6 @@ import { dealDictObjData } from '@/utils/position'
 import { useRoute, useRouter } from 'vue-router'
 import { useRoute, useRouter } from 'vue-router'
 defineOptions({name: 'retrieval-position-page'})
 defineOptions({name: 'retrieval-position-page'})
 const route = useRoute(); const router = useRouter()
 const route = useRoute(); const router = useRouter()
-// const cityFilterRef = ref()
 const conditionFilterRef = ref()
 const conditionFilterRef = ref()
 const showFilterList = [
 const showFilterList = [
   { key: 'positionId', isSingle: true },
   { key: 'positionId', isSingle: true },
@@ -54,20 +53,16 @@ const showFilterList = [
   { key: 'eduType' },
   { key: 'eduType' },
   { key: 'jobType' },
   { key: 'jobType' },
   { key: 'scale' },
   { key: 'scale' },
-  { key: 'industryIds' },
-  // { key: 'financingStatus' },
+  { key: 'industryIds' }
 ]
 ]
 
 
 const pageInfo = { pageNo: 1, pageSize: 20}
 const pageInfo = { pageNo: 1, pageSize: 20}
 const items = ref([])
 const items = ref([])
 const total = ref(0)
 const total = ref(0)
 let routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? reactive(route.query) : reactive({})
 let routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? reactive(route.query) : reactive({})
-// routeQuery.date = new Date().getTime()
-// router.push({ path: route.path, routeQuery })
-// if (routeQuery?.length) router.replace({ path: route.path, routeQuery })
 
 
 const noParams = ref(true)
 const noParams = ref(true)
-const headSearchText = ref(routeQuery?.content || '')
+const headSearchText = ref(routeQuery?.content ? routeQuery?.content.includes('&') ? decodeURIComponent(routeQuery.content) : routeQuery.content : '')
 
 
 // 职位搜索
 // 职位搜索
 const getData = async () => {
 const getData = async () => {
@@ -79,7 +74,10 @@ const getData = async () => {
     const passingOneId = ['positionId'] // 单选且传递整型
     const passingOneId = ['positionId'] // 单选且传递整型
     Object.keys(routeQuery).forEach(key => {
     Object.keys(routeQuery).forEach(key => {
       if (routeQuery[key] === '' || key === 'date') return
       if (routeQuery[key] === '' || key === 'date') return
-      else if (passingStrings.includes(key)) routerParams[key] = routeQuery[key] // 传给后端字符串
+      else if (passingStrings.includes(key)) { // 传给后端字符串
+        if (key === 'content') routerParams[key] = decodeURIComponent(routeQuery[key])
+        else routerParams[key] = routeQuery[key]
+      }
       else if (passingOneId.includes(key)) routerParams[key] = +routeQuery[key] // 传给后端单选且传递整型
       else if (passingOneId.includes(key)) routerParams[key] = +routeQuery[key] // 传给后端单选且传递整型
       else routerParams[key] = routeQuery[key].split('_') // 传给后端Arr
       else routerParams[key] = routeQuery[key].split('_') // 传给后端Arr
     })
     })
@@ -117,6 +115,7 @@ const updateRouter = () => {
     }, {})
     }, {})
   }
   }
   query.date = new Date().getTime() // 用于前端刷新路由参数
   query.date = new Date().getTime() // 用于前端刷新路由参数
+  if (query?.content && query.content.includes('%')) query.content = decodeURIComponent(query.content)
   router.push({ path: route.path, query })
   router.push({ path: route.path, query })
   pageInfo.pageNo = 1
   pageInfo.pageNo = 1
   // getData()
   // getData()