Explorar o código

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

zhengnaiwen_citu hai 4 meses
pai
achega
51259f8c57
Modificáronse 83 ficheiros con 1153 adicións e 350 borrados
  1. 3 0
      components.d.ts
  2. 5 5
      src/api/mall/cart.js
  3. 12 4
      src/api/mall/index.js
  4. 57 0
      src/api/mall/prize.js
  5. 2 2
      src/api/mall/product.js
  6. 6 6
      src/api/mall/user.js
  7. 3 3
      src/components/Enterprise/hotPromoted.vue
  8. 2 2
      src/components/Enterprise/info.vue
  9. 2 2
      src/components/FormUI/TextInput/index.vue
  10. 3 3
      src/components/Position/item.vue
  11. 2 2
      src/components/Position/longCompany.vue
  12. 3 3
      src/components/Position/longStrip.vue
  13. 4 2
      src/components/Position/similarPositions.vue
  14. 3 3
      src/components/PositionLongStrip/item.vue
  15. 2 1
      src/components/Upload/img.vue
  16. 2 1
      src/components/Upload/imgs.vue
  17. 2 2
      src/layout/company/navBar.vue
  18. 70 4
      src/plugins/dialogExtend/components/infoForm.vue
  19. 85 0
      src/plugins/dialogExtend/components/upload.vue
  20. 9 0
      src/router/modules/common.js
  21. 8 0
      src/router/modules/recruit.js
  22. 8 0
      src/styles/index.scss
  23. 2 2
      src/utils/getText.js
  24. 7 6
      src/utils/statisticsHeaders.js
  25. 1 1
      src/version.js
  26. 12 0
      src/views/domainName/index.vue
  27. 2 2
      src/views/mall/cart/index.vue
  28. 58 31
      src/views/mall/components/details.vue
  29. 7 2
      src/views/mall/components/details/describe.vue
  30. 1 1
      src/views/mall/components/details/order/addressSelection.vue
  31. 1 1
      src/views/mall/components/details/order/confirm.vue
  32. 120 11
      src/views/mall/components/details/prizeDrawContent.vue
  33. 19 8
      src/views/mall/components/details/s-select-sku.vue
  34. 41 9
      src/views/mall/components/navbar.vue
  35. 45 91
      src/views/mall/components/prizeDraw.vue
  36. 97 0
      src/views/mall/components/prizeDraw/grid.vue
  37. 96 0
      src/views/mall/components/prizeDraw/slotMachine.vue
  38. 92 0
      src/views/mall/goodsList/index.vue
  39. 9 1
      src/views/mall/home/components/carousel.vue
  40. 1 1
      src/views/mall/home/components/hotGoods.vue
  41. 5 1
      src/views/mall/home/index.vue
  42. 2 2
      src/views/mall/payOver/components/show.vue
  43. 24 2
      src/views/mall/payOver/index.vue
  44. 2 2
      src/views/mall/user/index.vue
  45. 37 35
      src/views/mall/user/order/index.vue
  46. 65 23
      src/views/mall/user/prize/index.vue
  47. 3 3
      src/views/publicRecruitment/components/table.vue
  48. 6 6
      src/views/recruit/components/message/components/chatting.vue
  49. 3 3
      src/views/recruit/components/message/index.vue
  50. 2 1
      src/views/recruit/entRegister/register.vue
  51. 2 1
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/enterpriseAlbum.vue
  52. 3 2
      src/views/recruit/enterprise/interviewManagement/components/item.vue
  53. 2 1
      src/views/recruit/enterprise/interviewManagement/index.vue
  54. 2 1
      src/views/recruit/enterprise/jobFair/components/job.vue
  55. 2 1
      src/views/recruit/enterprise/jobFair/components/resume.vue
  56. 2 1
      src/views/recruit/enterprise/jobFair/job/item.vue
  57. 2 2
      src/views/recruit/enterprise/membershipPackage/dynamic/package.vue
  58. 4 2
      src/views/recruit/enterprise/positionManagement/components/item.vue
  59. 2 1
      src/views/recruit/enterprise/resume/components/invite.vue
  60. 2 1
      src/views/recruit/enterprise/resume/components/screen.vue
  61. 2 1
      src/views/recruit/enterprise/resume/components/table.vue
  62. 4 3
      src/views/recruit/enterprise/search/recommend/index.vue
  63. 2 1
      src/views/recruit/enterprise/staffInfoSetting/index.vue
  64. 5 1
      src/views/recruit/enterprise/statistics/overallAnalysis.vue
  65. 3 3
      src/views/recruit/enterprise/systemManagement/groupAccount/components/record.vue
  66. 6 5
      src/views/recruit/enterprise/systemManagement/groupAccount/index.vue
  67. 2 1
      src/views/recruit/enterprise/tradingOrder/components/trading/transaction.vue
  68. 2 1
      src/views/recruit/personal/PersonalCenter/components/communication.vue
  69. 3 3
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/interview/item.vue
  70. 2 2
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/seenMe.vue
  71. 11 0
      src/views/recruit/personal/PersonalCenter/resume/analysis/analyzeTestData.js
  72. 2 1
      src/views/recruit/personal/PersonalCenter/resume/analysis/components/avatar.vue
  73. 2 1
      src/views/recruit/personal/PersonalCenter/resume/online/analysis/avatar.vue
  74. 2 1
      src/views/recruit/personal/PersonalCenter/resume/online/components/basicInfo.vue
  75. 3 3
      src/views/recruit/personal/company/components/companyItem.vue
  76. 2 1
      src/views/recruit/personal/companyDetail/components/positions.vue
  77. 2 2
      src/views/recruit/personal/companyDetail/index.vue
  78. 3 2
      src/views/recruit/personal/home/components/advertisement/dynamic/intercontinental.vue
  79. 3 2
      src/views/recruit/personal/home/components/advertisement/dynamic/marriott.vue
  80. 7 6
      src/views/recruit/personal/position/components/details.vue
  81. 3 2
      src/views/recruit/personal/position/components/poster.vue
  82. 3 2
      src/views/recruit/personal/position/components/rightRecommend.vue
  83. 3 3
      src/views/recruit/personal/recommend/components/positionList.vue

+ 3 - 0
components.d.ts

@@ -72,4 +72,7 @@ declare module 'vue' {
     VerifySlide: typeof import('./src/components/Verifition/Verify/VerifySlide.vue')['default']
     WangEditor: typeof import('./src/components/FormUI/wangEditor/index.vue')['default']
   }
+  export interface ComponentCustomProperties {
+    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+  }
 }

+ 5 - 5
src/api/mall/cart.js

@@ -2,14 +2,14 @@ import request from '@/config/axios'
 
 // 获取购物车列表
 export const getMallUserCartList = async () => {
-  return request.get({
+  return await request.get({
     url: '/app-api/trade/cart/list'
   })
 }
 
 // 从购物车中删除商品
 export const deleteCartGoods = async (ids) => {
-  return request.delete({
+  return await request.delete({
     url: '/app-api/trade/cart/delete',
     params: { ids }
   })
@@ -17,7 +17,7 @@ export const deleteCartGoods = async (ids) => {
 
 // 更新购物车商品选中状态
 export const updateCartSelected = async (data) => {
-  return request.put({
+  return await request.put({
     url: '/app-api/trade/cart/update-selected',
     data
   })
@@ -25,7 +25,7 @@ export const updateCartSelected = async (data) => {
 
 // 更新购物车商品数量
 export const updateCartCount = async (data) => {
-  return request.put({
+  return await request.put({
     url: '/app-api/trade/cart/update-count',
     data
   })
@@ -33,7 +33,7 @@ export const updateCartCount = async (data) => {
 
 // 添加商品到购物车
 export const addCart = async (data) => {
-  return request.post({
+  return await request.post({
     url: '/app-api/trade/cart/add',
     data
   })

+ 12 - 4
src/api/mall/index.js

@@ -2,21 +2,29 @@ import request from '@/config/axios'
 
 // 获取装修模版
 export const getDiyTemplate = async () => {
-  return request.get({
+  return await request.get({
     url: '/app-api/promotion/diy-template/used'
   })
 }
 
 // 获取id获取商品列表
 export const getProductByIds = async (ids) => {
-  return request.get({
+  return await request.get({
     url: `/app-api/product/spu/list-by-ids?ids=${ids}`
   })
 }
 
+// 获取商品列表
+export const getGoodsList = async (params) => {
+  return request.get({
+    url: '/app-api/product/spu/page',
+    params
+  })
+}
+
 // 提交积分商品兑换
 export const redeemSubmit = async (data) => {
-  return request.post({
+  return await request.post({
     url: '/app-api/menduner/system/redeem/submit',
     openEncryption: true,
     data
@@ -25,7 +33,7 @@ export const redeemSubmit = async (data) => {
 
 // 获取积分兑换记录
 export const getRedeemPage = async (params) => {
-  return request.get({
+  return await request.get({
     url: '/app-api/menduner/system/redeem/page',
     params
   })

+ 57 - 0
src/api/mall/prize.js

@@ -0,0 +1,57 @@
+import request from '@/config/axios'
+
+// 根据商品id获取抽奖活动
+export const getPrizeByGoodsId = async (spuId) => {
+  return await request.get({
+		url: `/app-api/promotion/luck-lottery/get/by-spu-id`,
+		params: { spuId }
+	})
+}
+
+// 根据活动id获取奖品
+export const getPrizeByLotteryId = async (lotteryId) => {
+  return await request.get({
+		url: `/app-api/promotion/luck-prize/get`,
+		params: { lotteryId }
+	})
+}
+
+// 根据活动id获取用户抽奖次数
+export const getNumByLotteryId = async (lotteryId) => {
+  return await request.get({
+		url: `/app-api/promotion/luck-lottery/get/user-num`,
+		params: { lotteryId }
+	})
+}
+
+// 领取奖品
+export const luckyLotteryRecordReceive = async (data) => {
+  return await request.post({
+		url: `/app-api/promotion/luck-lottery-record/receive`,
+		data
+	})
+}
+
+// 根据商品id活动对应的奖品区域信息
+export const getPrizeAreaByGoodsId = async (params) => {
+  return await request.get({
+		url: '/app-api/promotion/luck-prize/get/extend/area',
+		params
+	})
+}
+
+// 抽奖记录分页
+export const getLuckLotteryRecordPage = async (params) => {
+  return await request.get({
+		url: '/app-api/promotion/luck-lottery-record/page',
+		params
+	})
+}
+
+// 根据订单id获取中奖记录
+export const getLuckLotteryRecordByOrderId = async (orderId) => {
+  return await request.get({
+		url: '/app-api/promotion/luck-lottery-record/get/by-order-id',
+		params: { orderId }
+	})
+}

+ 2 - 2
src/api/mall/product.js

@@ -2,7 +2,7 @@ import request from '@/config/axios'
 
 // 获取商品详情
 export const getProductDetail = async (params) => {
-  return request.get({
+  return await request.get({
     url: '/app-api/product/spu/get-detail',
     params
   })
@@ -10,7 +10,7 @@ export const getProductDetail = async (params) => {
 
 // 获得商品评价分页
 export const getCommentPage = async (spuId, pageNo, pageSize, type) => {
-  return request.get({
+  return await request.get({
     url: '/app-api/product/comment/page',
     params: {
       spuId,

+ 6 - 6
src/api/mall/user.js

@@ -2,7 +2,7 @@ import request from '@/config/axios'
 
 // 获取订单分页
 export const getMallOrderPage = async (params) => {
-  return request.get({
+  return await request.get({
     url: '/app-api/trade/order/page',
     params
   })
@@ -10,7 +10,7 @@ export const getMallOrderPage = async (params) => {
 
 // 获取订单详情
 export const getMallOrderDetail = async (id) => {
-  return request.get({
+  return await request.get({
     url: '/app-api/trade/order/get-detail',
     params: {
       id
@@ -20,7 +20,7 @@ export const getMallOrderDetail = async (id) => {
 
 // 确认收货
 export const receiveOrder = async (id) => {
-  return request.put({
+  return await request.put({
     url: '/app-api/trade/order/receive',
     params: {
       id
@@ -30,7 +30,7 @@ export const receiveOrder = async (id) => {
 
 // 删除订单
 export const deleteTradeOrder = async (id) => {
-  return request.delete({
+  return await request.delete({
     url: '/app-api/trade/order/delete',
     params: { id }
   })
@@ -38,7 +38,7 @@ export const deleteTradeOrder = async (id) => {
 
 // 取消订单
 export const cancelTradeOrder = async (id) => {
-  return request.delete({
+  return await request.delete({
     url: '/app-api/trade/order/cancel',
     params: { id }
   })
@@ -46,7 +46,7 @@ export const cancelTradeOrder = async (id) => {
 
 // 创建单个商品评论
 export const createOrderItemComment = async (data) => {
-  return request.post({
+  return await request.post({
     url: '/app-api/trade/order/item/create-comment',
     data
   })

+ 3 - 3
src/components/Enterprise/hotPromoted.vue

@@ -8,7 +8,7 @@
             <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 class="company-info cursor-pointer">
-            <h3>{{ dealEnterpriseName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
+            <h3>{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
             <p>
               {{ item?.enterprise.scaleName }}
               <span class="septal-line" v-if="item.enterprise.industryName"></span>
@@ -24,7 +24,7 @@
           <li class="company-job-item" v-for="(k, i) in item.jobList" :key="i" :class="{'company-job-item-hover': k.active}" @mouseenter="k.active = true" @mouseleave="k.active = false" @click="handleClickPosition(k)">
             <div class="job-info" @mouseenter="k.active = true" @mouseleave="k.active = false" @click="handleClickPosition(k)">
               <div class="mb-2 d-flex">
-                <p :class="['name', 'cursor-pointer', {'default-active': k.active }]" :style="{'max-width': !k.payFrom && !k.payTo ? '290px' : '200px'}">{{ k.name }}</p>
+                <p :class="['name', 'cursor-pointer', {'default-active': k.active }]" :style="{'max-width': !k.payFrom && !k.payTo ? '290px' : '200px'}">{{ formatName(k.name) }}</p>
                 <span v-if="!k.payFrom && !k.payTo" class="salary">面议</span>
                 <span v-else class="salary">{{ k.payFrom ? k.payFrom + '-' : '' }}{{ k.payTo }}{{ k.payName ? '/' + k.payName : '' }}</span>
               </div>
@@ -50,7 +50,7 @@
 <script setup name="hotPromoted">
 import { ref, watch } from 'vue'
 import { timesTampChange } from '@/utils/date'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const props = defineProps({
   items: {

+ 2 - 2
src/components/Enterprise/info.vue

@@ -4,7 +4,7 @@
     <div style="height: 50px; line-height: 50px;">
       <v-img class="float-left" :src="props.info.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" :width="45" height="45"></v-img>
       <div class="ml-3 float-left">
-        <p class="enterprise-name cursor-pointer" @click="handleEnterprise(0)">{{ dealEnterpriseName(props.info.enterprise.anotherName || props.info.enterprise.name) }}</p>
+        <p class="enterprise-name cursor-pointer" @click="handleEnterprise(0)">{{ formatName(props.info.enterprise.anotherName || props.info.enterprise.name) }}</p>
         <!-- <v-icon :color="statusInfo.color" size="20">{{ statusInfo.mdi }}</v-icon>
         <span :style="{'color': statusInfo.color,'font-size': '14px'}">{{ statusInfo.label }}</span> -->
       </div>
@@ -25,7 +25,7 @@
 defineOptions({ name: 'enterprise-info' })
 import { ref } from 'vue'
 import { dealDictObjData } from '@/utils/position'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 // import { getEnterpriseAuthDetails } from '@/api/position'
 
 const props = defineProps({

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

@@ -48,7 +48,7 @@ const item = props.item
 const inputType = ref(item.type === 'phoneNumber' ? 'number' : item.type)
 
 const value = ref('')
-if (props.modelValue) value.value = props.modelValue.replace(/&amp;/g, '&')
+if (props.modelValue && typeof props.modelValue === 'string') value.value = props.modelValue.replace(/&amp;/g, '&')
 
 const searchDebouncedTime = item?.searchDebouncedTime === 0 ? ref(0) : ref(500)
 if (inputType.value === 'number' && item.integer) searchDebouncedTime.value = 0
@@ -65,7 +65,7 @@ const valueDeal = (val) => {
 
 watch(() => props.modelValue, (newVal) => {
   const dealData = valueDeal(newVal)
-  value.value = dealData ? dealData.replace(/&amp;/g, '&') : ''
+  value.value = dealData ? typeof dealData === 'string' ? dealData.replace(/&amp;/g, '&') : dealData : ''
 })
 
 const modelValueUpDate = (val) => {

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

@@ -5,7 +5,7 @@
         <div class="job-info" @click="handlePosition(item)" @mouseenter="item.active = true" @mouseleave="item.active = false">
           <div class="sub-li-top">
             <div class="sub-li-info">
-              <p :class="['name', {'default-active': item.active }]">{{ item.name }}</p>
+              <p :class="['name', {'default-active': item.active }]">{{ formatName(item.name) }}</p>
               <svg-icon v-if="tab === 3 && item.hire" name="pin" size="30"></svg-icon>
             </div>
           </div>
@@ -37,7 +37,7 @@
                 <v-img :src="item.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" />
               </v-avatar>
               <span class="names ml-2 font-size-14 ellipsis" style="max-width: 88%;">
-                {{ dealEnterpriseName(item.anotherName || item.enterpriseName) }}
+                {{ formatName(item.anotherName || item.enterpriseName) }}
                 <span class="color-999 font-size-13 ml-3">
                   <span>{{ item.industryName }}</span>
                   <span class="septal-line" v-if="item.industryName && item.scaleName"></span>
@@ -57,7 +57,7 @@ defineOptions({ name: 'position-card-item' })
 import { ref, watch } from 'vue'
 import { commissionCalculation } from '@/utils/position'
 import { timesTampChange } from '@/utils/date'
-import { dealEnterpriseName } from '@/utils/getText';
+import { formatName } from '@/utils/getText';
 
 const props = defineProps({
   items: {

+ 2 - 2
src/components/Position/longCompany.vue

@@ -6,7 +6,7 @@
           <div class="float-left mr-5">
             <v-img :src="item.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" :alt="item.anotherName" :width="40" style="height: 40px;border-radius: 4px;"/>
           </div>
-          <h3 :class="{'default-active': item.active }" class="cursor-pointer" @click="handleClickEnterprise(item, 'briefIntroduction')">{{ dealEnterpriseName(item.anotherName || item.name) }}</h3>
+          <h3 :class="{'default-active': item.active }" class="cursor-pointer" @click="handleClickEnterprise(item, 'briefIntroduction')">{{ formatName(item.anotherName || item.name) }}</h3>
           <p>{{ item.industryName }}<span v-if="item.industryName && item.scaleName" class="mx-2">|</span>{{ item.scaleName }}</p>
         </div>
         <div v-if="item.active">
@@ -33,7 +33,7 @@
 defineOptions({ name: 'long-company-card'})
 import Snackbar from '@/plugins/snackbar'
 import { useI18n } from '@/hooks/web/useI18n'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 import { getEnterpriseUnsubscribe } from '@/api/enterprise'
 
 const emits = defineEmits(['refresh'])

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

@@ -20,7 +20,7 @@
       <div class="info-content" >
         <div class="job-info">
           <div class="job-name ellipsis" :class="{'cursor-pointer': val.job.status === '0'}">
-            <span class="mr-3" :class="{'info-name': val.job.status === '0'}" @click="handleToPositionDetails(val)">{{ val.job.name }}</span>
+            <span class="mr-3" :class="{'info-name': val.job.status === '0'}" @click="handleToPositionDetails(val)">{{ formatName(val.job.name) }}</span>
             <span v-if="val?.job?.areaName || !val.job.areaId">[{{ !val.job.areaId ? '全国' : val.job.areaName }}]</span>
           </div>
           <div class="job-other">
@@ -35,7 +35,7 @@
             <v-img width="50" height="50" :src="val.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/7.png'"></v-img>
           </div>
           <div class="ml-3">
-            <div class="cursor-pointer info-name" @click="handleToEnterprise(val)">{{ dealEnterpriseName(val.enterprise.anotherName || val.enterprise.name) }}</div>
+            <div class="cursor-pointer info-name" @click="handleToEnterprise(val)">{{ formatName(val.enterprise.anotherName || val.enterprise.name) }}</div>
             <div class="mt-3 ellipsis color-666 font-size-13" style="max-width: 260px;">
               <span v-for="(k, i) in desc" :key="k">
                 {{ val.enterprise[k] }}
@@ -65,7 +65,7 @@ import loginPage from '@/views/common/loginDialog.vue'
 import { getToken } from '@/utils/auth'
 import { checkPersonBaseInfo } from '@/utils/check'
 import dialogExtend from '@/plugins/dialogExtend'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const emits = defineEmits(['refresh'])
 const { t } = useI18n()

+ 4 - 2
src/components/Position/similarPositions.vue

@@ -2,12 +2,12 @@
   <div class="position-box">
     <h4 class="mb-3">{{ $t('position.similarPosition') }}</h4>
     <div v-for="(item, index) in props.list" :key="index" class="mb-2 cursor-pointer" @click="handlePosition(item)">
-      <p class="recruit-name" :style="{'max-width': !item.payFrom && !item.payTo ? '230px' : '140px'}">{{ item.name }}</p>
+      <p class="recruit-name" :style="{'max-width': !item.payFrom && !item.payTo ? '230px' : '140px'}">{{ formatName(item.name) }}</p>
       <span v-if="!item.payFrom && !item.payTo" class="recruit-salary">面议</span>
       <span v-else class="recruit-salary">{{ item.payFrom ? item.payFrom + '-' : '' }}{{ item.payTo }}{{ item.payName ? '/' + item.payName :'' }}</span>
       <div :class="['enterprise', {'border-bottom-dashed': index !== list.length - 1}]">
         <v-img class="float-left" :src="item.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" :width="30" :height="30"></v-img>
-        <span class="float-left enterprise-name">{{ item.anotherName }}</span>
+        <span class="float-left enterprise-name">{{ formatName(item.anotherName) }}</span>
         <span class="float-right enterprise-address">{{ !item.areaId ? '全国' : item.areaName }}</span>
       </div>
     </div>
@@ -15,6 +15,8 @@
 </template>
 
 <script setup name="similarPositions">
+import { formatName } from '@/utils/getText'
+
 const props = defineProps({
   list: {
     type: Array,

+ 3 - 3
src/components/PositionLongStrip/item.vue

@@ -12,7 +12,7 @@
           <div>
             <div class="d-flex">
               <p v-if="item.job.name.indexOf('style')" v-html="item.job.name" :class="['title1', {'default-active': item.positionActive }]"></p>
-              <p v-else :class="['title1', {'default-active': item.positionActive }]">{{ item.job.name }}{{ item.job.pos ? ' [' + item.job.pos + '] ' : '' }}</p>
+              <p v-else :class="['title1', {'default-active': item.positionActive }]">{{ formatName(item.job.name) }}{{ item.job.pos ? ' [' + item.job.pos + '] ' : '' }}</p>
               <p v-if="!item.job.payFrom && !item.job.payTo" class="salary ml-1">面议</p>
               <p v-else class="salary ml-1">{{ item.job.payFrom ? item.job.payFrom + '-' : '' }}{{ item.job.payTo }}{{ item.job.payName ? '/' + item.job.payName : '' }}</p>
               <div v-if="item?.job?.hire">
@@ -38,7 +38,7 @@
         <div class="company-info">
           <v-hover>
             <template v-slot:default="{ isHovering, props }">
-              <h3 v-bind="props" :class="{'default-active': isHovering }" class="title1">{{ dealEnterpriseName(item.enterprise.anotherName, item.enterprise.name) }}</h3>
+              <h3 v-bind="props" :class="{'default-active': isHovering }" class="title1">{{ formatName(item.enterprise.anotherName, item.enterprise.name) }}</h3>
             </template>
           </v-hover>
           <p class="mt-2">
@@ -74,7 +74,7 @@ import { commissionCalculation } from '@/utils/position'
 defineOptions({ name: 'long-strip-position-card-item' })
 import { ref, watch } from 'vue'
 import { getUserAvatar } from '@/utils/avatar'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const props = defineProps({
   items: {

+ 2 - 1
src/components/Upload/img.vue

@@ -63,7 +63,8 @@ const handleUploadFile = async (e) => {
     return
   }
 
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式')
 
   const formData = new FormData()

+ 2 - 1
src/components/Upload/imgs.vue

@@ -71,7 +71,8 @@ const handleUploadFile = async (e) => {
     return
   }
 
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式')
 
   const formData = new FormData()

+ 2 - 2
src/layout/company/navBar.vue

@@ -15,7 +15,7 @@
         <div class="d-flex user-nav align-center">
           <div class="d-flex align-center cursor-pointer">
             <v-img @click="enterpriseClick(2)" rounded width="40" height="40" :src="baseInfo?.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" ></v-img>
-            <span @click="enterpriseClick(1)" class="ml-3 commonHover">{{ dealEnterpriseName(baseInfo?.enterpriseAnotherName || baseInfo?.enterpriseName) }}</span>
+            <span @click="enterpriseClick(1)" class="ml-3 commonHover">{{ formatName(baseInfo?.enterpriseAnotherName || baseInfo?.enterpriseName) }}</span>
           </div>
           <div class="ml-3 cursor-pointer border-left border-right px-3 commonHover" @click="handleLogout(false)">我要求职</div>
           <div class="d-flex align-center px-3 border-right cursor-pointer commonHover" @click="router.push('/recruit/enterprise/membershipPackage?key=1')">
@@ -92,7 +92,7 @@ import { useRouter } from 'vue-router'; const router = useRouter()
 import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
 import MessageNotification from '../message.vue'
 import { getUserAvatar } from '@/utils/avatar'
-import { dealEnterpriseName } from '@/utils/getText';
+import { formatName } from '@/utils/getText';
 defineOptions({ name: 'personal-navbar' })
 
 defineProps({

+ 70 - 4
src/plugins/dialogExtend/components/infoForm.vue

@@ -22,9 +22,28 @@
         </div>
         <div style="font-size: 14px; color: var(--color-999);">只支持JPG、JPEG、PNG类型的图片,大小不超过20M</div>
       </template>
+      <template #analysis>
+        <div style="text-align: right; width: 100%;">
+          <v-btn variant="text" color="primary" :loading="analyzeLoading" @click="handleImportAttachment">导入简历解析</v-btn>
+        </div>
+      </template>
     </CtForm>
   </div>
   <ImgCropper :visible="isShowCopper" :image="selectPic" :cropBoxResizable="true" @submit="handleHideCopper" :aspectRatio="1 / 1" @close="isShowCopper = false"></ImgCropper>
+  
+  <!-- 选择本地简历 -->
+  <CtDialog
+    :visible="openUploadDialog"
+    :widthType="2"
+    titleClass="text-h6"
+    @close="openUploadDialog = false"
+    title="附件简历上传"
+    @submit="uploadFileSubmit"
+  >
+  <uploadForm ref="uploadFormRef"></uploadForm>
+  <div class="color-warning" style="font-size: 14px;">提示:上传成功后将自动解析,导入解析简历尝试不得超过5次,请确认好简历后上传!</div>
+  </CtDialog>
+  <Loading :visible="analyzeLoading"></Loading>
 </template>
 
 <script setup>
@@ -32,11 +51,18 @@ import { getDict } from '@/hooks/web/useDictionaries'
 defineOptions({name: 'dialogExtend-InfoForm'})
 import { reactive, ref } from 'vue'
 import { checkEmail } from '@/utils/validate'
-import { enterpriseSearchByName } from '@/api/recruit/personal/resume'
+import {
+  resumeParser2,
+  getPersonResumeCv,
+  enterpriseSearchByName,
+  savePersonResumeCv
+} from '@/api/recruit/personal/resume'
 import { getUserAvatar } from '@/utils/avatar'
 import { uploadFile } from '@/api/common'
 import Snackbar from '@/plugins/snackbar'
 import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
+import uploadForm from './upload.vue'
+// import { analyzeTestData } from './analyzeTestData.js'
 
 const props = defineProps({
   option: {
@@ -79,6 +105,9 @@ const items = ref({
       value: '',
       flexStyle: 'align-center'
     },
+    {
+      slotName: 'analysis',
+    },
     {
       type: 'text',
       key: 'name',
@@ -254,10 +283,12 @@ const openFileInput = () => {
 // 上传头像
 const accept = ['jpg', 'png', 'jpeg']
 const handleUploadFile = async (e) => {
+  console.log('handleUploadFile:', e)
   const file = e.target.files[0]
   if (!file) return
 
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式文件')
 
   const size = file.size
@@ -351,6 +382,40 @@ const getQuery = async () => {
   return query
 }
 
+// 填充
+const handleAnalyzeFill = (data) => {
+  const person = data?.person || null
+  if (!person && !Object.keys(person).length) return Snackbar.warning('无可用内容!')
+  if (person.enterpriseName) getEnterpriseData(person.enterpriseName)
+  items.value.options.forEach((e) => {
+    if (person[e.key]) e.value = person[e.key]
+  })
+}
+
+const analyzeLoading = ref(false)
+const uploadFormRef = ref()
+const openUploadDialog = ref(false)
+// 上传附件-提交
+const uploadFileSubmit = async () => {
+  const obj = await uploadFormRef.value.getQuery()
+  if (!obj?.url || !obj?.title) return Snackbar.warning(t('resume.selectResumeToSubmit'))
+  const query = { title: obj.title, url: obj.url }
+  analyzeLoading.value = true
+  await savePersonResumeCv(query)
+  openUploadDialog.value = false
+  const data = await resumeParser2({ fileUrl: obj.url })
+  // const data = JSON.parse(JSON.stringify(analyzeTestData))
+  console.log('resumeParser2:', data)
+  handleAnalyzeFill(data)
+  analyzeLoading.value = false
+}
+
+const handleImportAttachment = async () => {
+  const data = await getPersonResumeCv() // 获取附件
+  if (data?.length >= 5) return Snackbar.warning('导入解析简历尝试不得超过5次!')
+  openUploadDialog.value = true
+}
+
 defineExpose({
   getQuery
 })
@@ -361,8 +426,9 @@ defineExpose({
   width: 80px;
   position: relative;
   cursor: pointer;
-  margin: 32px;
-  margin-right: 40px;
+  // margin: 32px;
+  // margin-right: 40px;
+  margin: 0 40px 0 32px;
   .img {
     width: 100%;
     height: 100%;

+ 85 - 0
src/plugins/dialogExtend/components/upload.vue

@@ -0,0 +1,85 @@
+<template>
+  <div style="width: 100%;">
+    <CtForm ref="formPageRef" :items="items"></CtForm>
+    <div class="color-666 mb-3" style="font-size: 13px;">* 仅支持.doc, .docx, .pdf文件且大小不能超过20MB</div>
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'shareJob-form-upload'})
+import { reactive, ref } from 'vue'
+import { useI18n } from '@/hooks/web/useI18n'
+import { uploadFile } from '@/api/common'
+import Snackbar from '@/plugins/snackbar'
+
+const { t }  = useI18n()
+const formPageRef = ref()
+let query = reactive({})
+
+// 上传简历
+const typeList = ['pdf', 'doc', 'docx']
+const handleUpload = async (e) => {
+  const file = e
+  const size = file.size
+  if (size / (1024*1024) > 20) {
+    Snackbar.warning(t('common.fileSizeExceed'))
+    return
+  }
+  const arr = file.name.split('.')
+  if (typeList.indexOf(arr[arr.length - 1]) < 0) {
+    Snackbar.warning(t('common.fileFormatIncorrect'))
+    return
+  }
+  const formData = new FormData()
+  formData.append('file', file)
+  formData.append('path', 'attachment')
+  const { data } = await uploadFile(formData)
+  if (!data) return
+  const urlItem = items.value.options.find(e => e.key === 'url')
+  if (urlItem) urlItem.data = data
+  query.fileName = file.name
+  // const titleItem = items.value.options.find(e => e.key === 'title')
+  // if (titleItem && !titleItem.value) titleItem.value = query.fileName
+}
+
+const items = ref({
+  options: [
+    {
+      type: 'text',
+      key: 'title',
+      value: null,
+      label: '附件简历名称 *',
+      rules: [v => !!v || '请填写附件简历名称']
+    },
+    {
+      type: 'upload',
+      key: 'url',
+      value: null,
+      data: '',
+      label: '附件简历 *',
+      placeholder: '请上传附件简历',
+      accept: '.doc, .docx, .pdf',
+      prependInnerIcon: 'mdi-file-document-outline',
+      rules: [v => !!v || '请上传附件简历'],
+      change: handleUpload
+    }
+  ]
+})
+
+
+const getQuery = async () => {
+  const { valid } = await formPageRef.value.formRef.validate()
+  if (!valid) return
+  const obj = {}
+  items.value.options.forEach(e => {
+    if (Object.prototype.hasOwnProperty.call(e, 'data')) return obj[e.key] = e.data
+    obj[e.key] = e.value
+  })
+  query = Object.assign(query, obj)
+  return query
+}
+
+defineExpose({
+  getQuery
+})
+</script>

+ 9 - 0
src/router/modules/common.js

@@ -104,6 +104,15 @@ const common = [
       hideSide: true
     }
   },
+  {
+    path: '/domainNameTest',
+    component: () => import('@/views/domainName'),
+    name: 'domainName',
+    meta: {
+      title: '访问配置业务域名',
+      hideSide: true
+    }
+  },
   ...headhunting
 ]
 

+ 8 - 0
src/router/modules/recruit.js

@@ -43,6 +43,14 @@ const recruit = [
           title: '门墩儿商城'
         }
       },
+      {
+        path: '/mall/goodsList',
+        component: () => import('@/views/mall/goodsList/index'),
+        name: 'goodsList',
+        meta: {
+          title: '商品列表'
+        }
+      },
       {
         path: '/mall/goodsDetail/:id',
         component: () => import('@/views/mall/components/details.vue'),

+ 8 - 0
src/styles/index.scss

@@ -111,6 +111,14 @@
   overflow: hidden;
 }
 
+// 超出2行显示省略号
+.ellipsis-2 {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  overflow: hidden;
+}
+
 // 分隔线
 .septal-line {
   display: inline-block;

+ 2 - 2
src/utils/getText.js

@@ -53,7 +53,7 @@ export const dealCanBeInputtedSave = (formItem, params) => {
   else { params[formItem.key] = formItem.value; params[formItem.itemTextName] = formItem[formItem.itemTextName] }
 }
 
-// 企业名称处理
-export const dealEnterpriseName = (text) => {
+// 格式化企业名称、职位名称
+export const formatName = (text) => {
   return text ? text.replace(/&amp;/g, '&') : ''
 }

+ 7 - 6
src/utils/statisticsHeaders.js

@@ -1,5 +1,6 @@
 import { timesTampChange } from './date'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { formatName } from '@/utils/getText'
 
 // 求职状态
 let jobStatus = []
@@ -11,7 +12,7 @@ export default {
   // 发布职位数量
   0: [
     { title: '职位名称', key: 'name', sortable: false },
-    { title: '职位类型', key: 'positionName', sortable: false },
+    { title: '职位类型', key: 'positionName', sortable: false, value: item => formatName(item.positionName) },
     { title: '薪酬', key: 'payFrom', sortable: false, value: item => item.payFrom && item.payTo ? `${item.payFrom ? item.payFrom + '-' : ''}${item.payTo}${item.payName ? '/' + item.payName : ''}` : '面议' },
     { title: '工作地区', key: 'areaName', sortable: false },
     { title: '工作经验', key: 'expName', sortable: false },
@@ -20,7 +21,7 @@ export default {
   ],
   // 职位浏览量
   1: [
-    { title: '招聘职位', key: 'name', sortable: false },
+    { title: '招聘职位', key: 'name', sortable: false, value: item => formatName(item.name) },
     { title: '薪酬', key: 'payFrom', sortable: false, value: item => item.payFrom && item.payTo ? `${item.payFrom ? item.payFrom + '-' : ''}${item.payTo}${item.payName ? '/' + item.payName : ''}` : '面议' },
     { title: '工作地区', key: 'areaName', sortable: false },
     { title: '工作经验', key: 'expName', sortable: false },
@@ -31,7 +32,7 @@ export default {
   2: [
     { title: '投递人', key: 'person.name', sortable: false },
     { title: '求职状态', key: 'person.jobStatus', sortable: false, value: item => jobStatus.find(i => i.value === item.person.jobStatus)?.label },
-    { title: '投递岗位', key: 'job.name', sortable: false },
+    { title: '投递岗位', key: 'job.name', sortable: false, value: item => formatName(item.job.name) },
     { title: '薪酬', key: 'job.payFrom', sortable: false, value: item => item.job.payFrom && item.job.payTo ? `${item.job.payFrom ? item.job.payFrom + '-' : ''}${item.job.payTo}${item.job.payName ? '/' + item.job.payName : ''}` : '面议' },
     { title: '工作地区', key: 'job.areaName', sortable: false },
     { title: '工作经验', key: 'job.expName', sortable: false },
@@ -40,7 +41,7 @@ export default {
   // 已查看简历
   3: [
     { title: '投递人', key: 'person.name', sortable: false },
-    { title: '投递岗位', key: 'job.name', sortable: false },
+    { title: '投递岗位', key: 'job.name', sortable: false, value: item => formatName(item.job.name) },
     { title: '投递类型', key: 'type', sortable: false, value: item => item.type === 0 ? '平台投递': '赏金投递' },
     { title: '推荐人', key: 'recommendPerson.name', sortable: false },
     { title: '简历标题', key: 'title', sortable: false },
@@ -48,7 +49,7 @@ export default {
   // 已邀面试
   4: [
     { title: '求职者', key: 'person.name', sortable: false },
-    { title: '面试岗位', key: 'job.name', sortable: false },
+    { title: '面试岗位', key: 'job.name', sortable: false, value: item => formatName(item.job.name) },
     { title: '面试类型', key: 'type', sortable: false, value: item => item.type === 0 ? '线上面试': '线下面试' },
     { title: '面试时间', key: 'time', sortable: false, value: item => timesTampChange(item.time, 'Y-M-D h:m') },
     { title: '面试地点', key: 'address', sortable: false },
@@ -56,7 +57,7 @@ export default {
   // 面试完成
   5: [
     { title: '求职者', key: 'person.name', sortable: false },
-    { title: '面试岗位', key: 'job.name', sortable: false },
+    { title: '面试岗位', key: 'job.name', sortable: false, value: item => formatName(item.job.name) },
     { title: '面试类型', key: 'type', sortable: false, value: item => item.type === 0 ? '线上面试': '线下面试' },
     { title: '面试时间', key: 'time', sortable: false, value: item => timesTampChange(item.time, 'Y-M-D h:m') },
     { title: '面试地点', key: 'address', sortable: false },

+ 1 - 1
src/version.js

@@ -1,2 +1,2 @@
 // 版本号
-export const vue_version = 'v24.12.26.1233'
+export const vue_version = 'v24.12.30.1500'

+ 12 - 0
src/views/domainName/index.vue

@@ -0,0 +1,12 @@
+<!--  -->
+<template>
+  <div></div>
+</template>
+
+<script setup>
+defineOptions({name: 'domainName-index'})
+window.location.href = 'https://minio.menduner.com/dev/34b1e846f19d86cd1a805dc52e121904632c4d80daac64a74be87c1b0778f7da.txt'
+
+</script>
+<style lang="scss" scoped>
+</style>

+ 2 - 2
src/views/mall/cart/index.vue

@@ -1,6 +1,6 @@
 <template>
-  <Navbar v-if="props.showNavbar" class="mb-3" />
-  <v-card class="card-box mb-5 pa-5 resume-box" :class="props.defaultWidth ? 'default-width' : '100%'" :elevation="props.elevation">
+  <Navbar v-if="props.showNavbar" />
+  <v-card class="card-box mb-5 pa-5 resume-box mt-3" :class="props.defaultWidth ? 'default-width' : '100%'" :elevation="props.elevation">
     <div class="resume-header">
       <div class="resume-title">我的购物车</div>
       <div>

+ 58 - 31
src/views/mall/components/details.vue

@@ -1,17 +1,12 @@
 <!-- 商品详情 -->
 <template>
-  <div class="default-width py-5" v-if="state.goodsInfo && Object.keys(state.goodsInfo).length">
-    <div class="d-flex justify-space-between">
-      <v-btn class="mb-3" size="large" color="primary" variant="text" @click="goBack"><v-icon size="24" class="mt-1 mr-1">mdi-chevron-triple-left</v-icon>返回商城</v-btn>
-      <div v-if="getToken()">
-        <v-btn class="mb-3" size="large" color="primary" variant="text" prepend-icon="mdi-account-circle-outline" to="/mall/user/order">我的订单</v-btn>
-        <v-btn class="mb-3 ml-1" size="large" color="primary" variant="text" prepend-icon="mdi-cart-outline" to="/mall/cart">购物车</v-btn>
-      </div>
-    </div>
+<div>
+  <Navbar />
+  <div class="default-width pb-5 mt-3" v-if="state.goodsInfo && Object.keys(state.goodsInfo).length">
     <v-card class="carousel border-radius-8 white-bgc pa-5" style="width: 100%;">
       <div class=" d-flex">
         <!-- 图片展示-轮播 -->
-        <div style="width: 500px; height: 500px;">
+        <div style="width: 400px; height: 400px;">
           <div v-if="selectedSkuPicUrl" class="selectedSkuImgBox" @mouseover="showSelectedSkuImg = true" @mouseleave="showSelectedSkuImg = false">
             <v-img :src="selectedSkuPicUrl" :aspect-ratio="1" style="border-radius: 8px;"></v-img>
             <v-btn
@@ -34,9 +29,12 @@
           <!-- 小标题 -->
           <div class="title-introduction">{{ state.goodsInfo?.introduction || '--' }}</div>
           <!-- 价格 -->
-          <div class="prices my-5">
-            <div class="price mr-5"><span>¥</span>{{ selectedSkuPrice}}</div>
-            <div class="marketPrice" v-if="selectedSkuMarketPrice && selectedSkuMarketPrice !== selectedSkuPrice">优惠前¥{{ selectedSkuMarketPrice}}</div>
+          <div class="prices py-4 px-5 my-3" :class="{'activePrices': showActivePrices}">
+            <div class="left">
+              <div class="price mr-5"><span>¥</span>{{ selectedSkuPrice}}</div>
+              <div class="marketPrice" v-if="selectedSkuMarketPrice && selectedSkuMarketPrice !== selectedSkuPrice">优惠前¥{{ selectedSkuMarketPrice}}</div>
+            </div>
+            <div v-if="showActivePrices" class="right">下单即可参与房券抽奖活动,百分百中奖,快来下单参与抽奖吧~</div>
           </div>
           <!-- 销量 -->
           <div class="salesCount mb-5 parameterColor"><span class="l-s-10">已售</span>:{{ state.goodsInfo?.salesCount || 0 }}</div>
@@ -55,39 +53,44 @@
     <!-- 详情描述 detail-content-card -->
     <v-card class="carousel border-radius-8 white-bgc pa-5 mt-3" style="width: 100%;">
       <div>
-        <div class="mb-3">
+        <!-- <div class="mb-3">
           <v-tabs v-model="describeTab" align-tabs="start" color="primary" bg-color="#f7f8fa" @update:model-value="null">
             <v-tab :value="0">商品介绍</v-tab>
             <v-tab :value="1">商品评价</v-tab>
-            <v-tab :value="2" v-if="(id-0)=== 648">房券抽奖活动</v-tab>
+            <v-tab :value="2" v-if="showPrize">房券抽奖活动</v-tab>
           </v-tabs>
-        </div>
+        </div> -->
         <describe v-if="describeTab === 0 && state.goodsInfo?.description" :content="state.goodsInfo.description"></describe>
-        <commentCard v-if="describeTab === 1 && state.goodsId" class="detail-comment-selector" :goodsId="state.goodsId" />
-        <prizeDrawContent v-if="describeTab === 2" />
+        <!-- <commentCard v-if="describeTab === 1 && state.goodsId" class="detail-comment-selector" :goodsId="state.goodsId" />
+        <prizeDrawContent v-if="describeTab === 2 && lotteryId" :lotteryId="lotteryId" /> -->
       </div>
     </v-card>
   </div>
+  
   <!-- 快速登录 -->
   <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
+
   <!-- 结算 -->
-  <CtDialog :visible="showSettlement" titleClass="text-h6" :widthType="3" title="订单信息" @submit="handleSubmit" @close="handleClose">
+  <CtDialog :visible="showSettlement" titleClass="text-h6" :widthType="3" title="订单提交" submitText="提交支付" @submit="handleSubmit" @close="handleClose">
     <confirm ref="confirmRef" :data="skuInfo" @orderCreated="orderCreated"></confirm>
   </CtDialog>
+  
   <!-- 支付 -->
   <CtDialog :visible="showPay" titleClass="text-h6" :widthType="3" title="收银台" :footer="false" @close="payCancel">
     <pay ref="payRef" :id="payOrderId" @paySuccess="paySuccess"></pay>
   </CtDialog>
+</div>
 </template>
 
 <script setup>
 defineOptions({name: 'goods-details'})
+import Navbar from '@/views/mall/components/navbar.vue'
 import { getProductDetail } from '@/api/mall/product'
 import { addCart } from '@/api/mall/cart'
 import selectSku from './details/s-select-sku.vue'
 import describe from './details/describe.vue'
-import commentCard from './details/detail-comment-card.vue'
-import prizeDrawContent from './details/prizeDrawContent.vue'
+// import commentCard from './details/detail-comment-card.vue'
+// import prizeDrawContent from './details/prizeDrawContent.vue'
 import confirm from './details/order/confirm.vue'
 import { ref, reactive } from 'vue'
 import { useRouter } from 'vue-router'
@@ -95,6 +98,7 @@ import Snackbar from '@/plugins/snackbar'
 import { getToken } from '@/utils/auth'
 import loginPage from '@/views/common/loginDialog.vue'
 import pay from '@/views/mall/components/details/order/pay.vue'
+import { getPrizeByGoodsId } from '@/api/mall/prize'
 
 const router = useRouter()
 const { id } = router.currentRoute.value.params
@@ -106,6 +110,10 @@ const selectedSkuMarketPrice = ref('')
 const showSelectSku = ref(false)
 const carouselHover = ref(false)
 const showSelectedSkuImg = ref(false)
+
+const showPrize = ref(false)
+const showActivePrices = ref(false) // 下单送房券
+const lotteryId = ref('')
 // 获取商品详情
 const getData = async () => {
   const obj = await getProductDetail({ id })
@@ -116,6 +124,13 @@ const getData = async () => {
   state.skeletonLoading = false;
   state.goodsInfo = obj
   showSelectSku.value = true
+
+  // 查询当前商品是否参与抽奖活动
+  const data = await getPrizeByGoodsId(id)
+  showPrize.value = data && Object.keys(data).length > 0
+  showActivePrices.value = data && Object.keys(data).length > 0
+  
+  lotteryId.value = data.id
 }
 getData()
 
@@ -163,9 +178,11 @@ const onBuy = async (e) => {
 const payRef = ref()
 const showPay = ref(false)
 const payOrderId = ref('')
-const orderCreated = (id) => {
+const orderId = ref('')
+const orderCreated = (id, order) => {
   showSettlement.value = false
   payOrderId.value = id
+  orderId.value = order
   showPay.value = true
 }
 // 
@@ -177,7 +194,7 @@ const payCancel = () => {
 const paySuccess = (e) => {
   // Snackbar.success('支付成功,请前往我的订单查看!')
   // showPay.value = false
-  router.push({ path: '/mall/payOver', query: { price: e.price }})
+  router.push({ path: '/mall/payOver', query: { price: e.price, spuId: id, orderId: orderId.value } })
 }
 
 // 添加购物车
@@ -218,12 +235,8 @@ const loginClose = () => {
   Snackbar.warning('您已取消登录')
 }
 
-const goBack = () => {
-  // router.go(-1)
-  router.push('/mall')
-}
-
 </script>
+
 <style lang="scss" scoped>
 .border-radius-8 {
   border-radius: 8px;
@@ -244,11 +257,25 @@ const goBack = () => {
   color: #7a7a7a;
 }
 .prices {
-  display: flex;
-  align-items: flex-end;
-  color: #ff5000;
+  // display: flex;
+  // justify-content: space-between;
   font-size: 28px;
-  margin: 8px 0;
+  border-radius: 8px;
+  width: 80%;
+  color: #ff5000;
+  .left {
+    display: flex;
+    align-items: flex-end;
+  }
+  .right {
+    font-size: 18px;
+    padding-top: 10px;
+    font-weight: 400;
+  }
+}
+.activePrices {
+  color: #fff;
+  background-color: #fb0037;
 }
 .price {
   font-weight: 600;

+ 7 - 2
src/views/mall/components/details/describe.vue

@@ -1,7 +1,12 @@
 <!--  -->
 <template>
-  <div class="detailsBox">
-    <span v-if="props.content.indexOf('style')" v-html="props.content"></span>
+  <div>
+    <div class="resume-header">
+      <div class="resume-title">商品详情</div>
+    </div>
+    <div class="detailsBox">
+      <span v-if="props.content.indexOf('style')" v-html="props.content"></span>
+    </div>
   </div>
 </template>
 

+ 1 - 1
src/views/mall/components/details/order/addressSelection.vue

@@ -28,7 +28,7 @@
         </div>
       </div>
     </v-card>
-    <CtDialog :visible="selectAddress" titleClass="text-h6" :footer="true" :widthType="1" title="修改收货地址" @submit="handleSubmit" @close="selectAddress = false">
+    <CtDialog :visible="selectAddress" titleClass="text-h6" :footer="true" :widthType="1" title="选择收货地址" @submit="handleSubmit" @close="selectAddress = false">
       <div style="min-height: 60vh;">
         <addressPage ref="addressPageRef" showSelect></addressPage>
       </div>

+ 1 - 1
src/views/mall/components/details/order/confirm.vue

@@ -175,7 +175,7 @@
       pointActivityId: state.orderPayload.pointActivityId,
     });
     if (!data.payOrderId && data.payOrderId > 0) return
-    emit('orderCreated', data.payOrderId) // 更新购物车列表,如果来自购物车
+    emit('orderCreated', data.payOrderId, data.id) // 更新购物车列表,如果来自购物车
     // payImmediately(data.payOrderId)
   }
 

+ 120 - 11
src/views/mall/components/details/prizeDrawContent.vue

@@ -1,22 +1,131 @@
 <!--  -->
 <template>
-  <div class=" px-15">
-    <div style="font-size: 28px;" class="my-5">房券列表:</div>
-    <div v-for="(item, index) of list" :key="index" class="mb-5">
-      <v-img :src="item" style="border-radius: 8px;"></v-img>
+  <div class="d-flex">
+    <!-- <div style="width: 200px; border-right: 1px dashed #b7b7b7;">
+      <v-treeview
+        :items="treeData"
+        activatable
+        color="primary"
+        item-value="id"
+        open-all
+        open-strategy="single"
+        density="compact"
+        @update:activated="handleClick"
+        @update:opened="handleClick"
+      >
+        <template v-slot:title="{ item }">
+          <div class="treeTitle font-size-15">
+            {{ item.title }}
+            <v-tooltip activator="parent" location="top">{{ item.title }}</v-tooltip>
+          </div>
+        </template>
+      </v-treeview>
+    </div> -->
+    <div class="ml-5" style="width: 100%;">
+      <!-- <div class="d-flex justify-space-between color-666 mb-5">
+        <div class="pt-2" style="font-size: 25px;">房券列表</div>
+        <div style="width: 200px;" class="mt-2">
+          <v-text-field
+            v-model="content"
+            variant="outlined" 
+            label="关键字查找"
+            hide-details
+            color="primary"
+            density="compact"
+            append-inner-icon="mdi-magnify"
+            @click:append-inner="handleSearch"
+            @keyup.enter="handleSearch"
+          >
+          </v-text-field>
+        </div>
+      </div> -->
+      <div class="goods-box">
+        <v-card v-for="val in dataList" :key="val.id" class="goods-box-item" elevation="2" @click="null">
+          <div style="width: 100%; height: 200px;">
+            <v-img :src="val.image" :aspect-ratio="1" style="border-radius: 8px;"></v-img>
+          </div>
+          <div class=" pa-3 pb-2 mt-5">
+            <div class="ellipsis-2 text-left">{{ val.name }}</div>
+            <div class="font-size-12 mt-2">{{ val.time }}</div>
+            <div class="font-size-12 mt-2" v-if="val.extend">
+              <span class="mr-1">地区:</span>
+              <span class="mr-1">{{ val.extend.provinceName }}</span>
+              <span class="mr-1">{{ val.extend.cityName }}</span>
+              <span class="mr-1">{{ val.extend.districtName }}</span>
+            </div>
+          </div>
+        </v-card>
+      </div>
     </div>
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
-
 defineOptions({name: 'GoodsItem-prizeDrawContent'})
+import { ref } from 'vue'
+// import { useRouter } from 'vue-router'; const router = useRouter()
+import { getPrizeByLotteryId } from '@/api/mall/prize'
+const props = defineProps({ lotteryId: [Number, String] })
+
+// const { id } = router.currentRoute.value.params
+
+const loading = ref(false)
+// const content = ref('')
+// const handleSearch = () => {}
+
+// 数据
+const dataList = ref([])
+
+// 获取房券列表
+const getDataList = async () => {
+  loading.value = true
+  try {
+    const data = await getPrizeByLotteryId(props.lotteryId)
+    dataList.value = data || []
+    // console.log('获取房券列表:', data)
+  } finally {
+    loading.value = false
+  }
+}
+getDataList()
+
+// // 树形click
+// const handleClick = (e) => {
+//   if (!e.length) return
+//   // getDataList()
+// }
+
+// const treeData = ref([])
+// // 根据商品id活动对应的奖品区域信息
+// const getTreeData = async () => {
+//   const params = {
+//     spuId: id
+//   }
+//   const data = await getPrizeAreaByGoodsId(params)
+//   console.log('getPrizeAreaByGoodsId:', data)
+//   getDataList()
+// }
+// getTreeData()
 
-const list = ref([
-  'https://img1.baidu.com/it/u=2343227867,4040084608&fm=253&fmt=auto&app=138&f=JPEG?w=499&h=248',
-  'https://img1.baidu.com/it/u=2343227867,4040084608&fm=253&fmt=auto&app=138&f=JPEG?w=499&h=248',
-])
 </script>
-<style lang="scss" scoped>
+
+<style scoped lang="scss">
+.active:hover {
+  color: var(--v-primary-base) !important;
+}
+.goods-box {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  &-item {
+    // height: 330px;
+    padding: 12px;
+    width: calc((100% - 48px) / 4);
+    margin: 0 12px 12px 0;
+    &:nth-child(4n) {
+      margin-right: 0;
+    }
+  }
+}
 </style>
+

+ 19 - 8
src/views/mall/components/details/s-select-sku.vue

@@ -8,15 +8,14 @@
         <v-chip
           class="spec-btn mb-1 mr-3"
           :class="[
-            { 'ui-BG-Main-Gradient': state.currentPropertyArray[property.id] === value.id, },
+            state.currentPropertyArray[property.id] === value.id ? 'ui-BG-Main-Gradient' : 'ui-BG-Main-Normal',
             { 'disabled-btn': value.disabled === true, },
           ]"
           v-for="value in property.values"
           :key="value.id"
-          size="small"
           label
           density="comfortable"
-          color="primary"
+          color="#777"
           variant="outlined"
           :disabled="value.disabled === true"
           @click="onSelectSku(property.id, value.id)"
@@ -44,8 +43,8 @@
     </div>
     <!-- 操作区 -->
     <div>
-      <v-btn class="buttons" color="primary" @click="onBuy">立即购买</v-btn>
-      <v-btn class="ml-3 px-8" color="warning" @click="onAddCart">加入购物车</v-btn>
+      <v-btn color="primary" width="200" @click="onBuy">立即购买</v-btn>
+      <v-btn class="ml-3" color="warning" width="200" @click="onAddCart">加入购物车</v-btn>
     </div>
   </div>
 </template>
@@ -72,6 +71,7 @@ const props = defineProps({
   });
 
   const propertyList = convertProductPropertyList(props.goodsInfo.skus);
+
   // SKU 列表
   const skuList = computed(() => {
     let skuPrices = props.goodsInfo.skus;
@@ -263,15 +263,26 @@ const props = defineProps({
   }
 
   changeDisabled(false);
-  // TODO 芋艿:待讨论的优化点:1)单规格,要不要默认选中;2)默认要不要选中第一个规格
+
+  // 默认选中第一个规格
+  if (propertyList && propertyList.length) {
+    propertyList.forEach((e) => {
+      if (e.values && e.values.length) onSelectSku(e.id, e.values[0].id)
+    })
+  }
 </script>
 
 <style lang="scss" scoped>
   // 主题色渐变,横向
   .ui-BG-Main-Gradient {
     // background: linear-gradient(90deg, #ff3000, #ff300099);
-    background: var(--v-primary-base);
-    color: #fff !important;
+    // background: var(--v-primary-base);
+    border: 1px solid #ff5000;
+    color:  #ff5000 !important;
+  }
+  .ui-BG-Main-Normal {
+    border: 1px solid #dadde0;
+    color: #11192d !important;
   }
   .disabled-btn {
     color: #c6c6c6;

+ 41 - 9
src/views/mall/components/navbar.vue

@@ -1,4 +1,5 @@
 <template>
+<div>
   <div class="stickyBox py-5">
     <div class="default-width d-flex align-center justify-space-between">
       <div class="header-link d-flex">
@@ -23,10 +24,10 @@
           购物车
         </span>
       </div>
-      <div class="search d-flex align-center">
+      <div v-if="!props.hideSearch" class="search d-flex align-center">
         <v-text-field
           v-model="inputVal"
-          placeholder="请输入关键词"
+          placeholder="请输入商品关键词"
           color="primary"
           variant="plain"
           density="compact"
@@ -40,33 +41,64 @@
       </div>
     </div>
   </div>
+  <!-- 快速登录 -->
+  <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
+</div>
 </template>
 
 <script setup>
-defineOptions({ name: 'formPage'})
+defineOptions({ name: 'mall-navbar'})
 import { computed, ref } from 'vue'
-import { useRouter } from 'vue-router'
+import { useRoute } from 'vue-router'; const route = useRoute()
+import { useRouter } from 'vue-router'; const router = useRouter()
 import { getToken } from '@/utils/auth'
 import Snackbar from '@/plugins/snackbar'
+import loginPage from '@/views/common/loginDialog.vue'
+import { getPrizeByGoodsId } from '@/api/mall/prize'
+
+const emit = defineEmits(['login', 'pointExchange', 'search'])
+const props = defineProps({
+  hideSearch: {
+    type: Boolean,
+    default: false,
+  },
+})
 
-const emit = defineEmits(['login', 'pointExchange'])
-const router = useRouter()
 const isActive = computed(() => (path, hasChild) => {
   const currentPath = router.currentRoute.value.path
   return hasChild ? currentPath.includes(path) : currentPath === path
 })
 
+const showLogin = ref(false)
 const handleTo = (path) => {
   if (!getToken()) {
     Snackbar.warning('请先登录')
-    emit('login', path)
+    showLogin.value = true // 打开快速登录弹窗
     return
   }
   router.push(path)
 }
 
-const inputVal = ref('')
-const handleSearch = () => {}
+const open = false
+// 更新路由进行搜素
+const inputVal = ref(route?.query?.keyWord || '')
+const handleSearch = () => {
+  if (!open) return
+  const path = '/mall/goodsList'
+  router.push({ path, query: { keyWord: inputVal.value } })
+  emit('search', inputVal.value)
+}
+
+// 快速登录
+const loginSuccess = () => {
+  showLogin.value = false
+  Snackbar.success('登录成功')
+}
+
+const loginClose = () => {
+  showLogin.value = false
+  Snackbar.warning('您已取消登录')
+}
 </script>
 
 <style scoped lang="scss">

+ 45 - 91
src/views/mall/components/prizeDraw.vue

@@ -1,117 +1,71 @@
 <template>
   <div class="prizeDrawBox">
-    <city @inputChange="null"></city>
-    <LuckyGrid
-      ref="myLucky"
-      width="300px"
-      height="300px"
-      :prizes="prizes"
-      :blocks="blocks"
-      :buttons="buttons"
-      :default-config="defaultConfig"
-      :disabled="true"
-      class="prizeDraw"
-      @start="startCallback"
-      @end="endCallback"
-    />
-    <div class="numberBox mt-5">您还剩余<span class="colorBase">{{ number }}</span>次抽奖机会</div>
+    <div class="text-end cursor-pointer color-666" @click="emit('success')">
+      <v-btn color="primary" variant="tonal" append-icon="mdi-pan-right">我的奖品</v-btn>
+    </div>
+    <div class="d-flex flex-column align-center">
+      <div class="numberBox mb-5">恭喜您获得房券抽奖机会</div>
+      <gridPage v-if="props.type === '1'" :lotteryId="props.lotteryId" :disabled="disabled" @end="endCallback"></gridPage>
+      <slotMachinePage v-if="props.type === '2'" :lotteryId="props.lotteryId" height="120" :disabled="disabled" @end="endCallback"></slotMachinePage>
+
+      <CtDialog :visible="showDialog" titleClass="text-h6" :footer="false" :widthType="3" title="抽奖详情" @close="showDialog = false">
+        <div class="d-flex align-center flex-column">
+          <svg-icon name="submit" size="300"></svg-icon>
+          <p v-for="(k, i) in prizeData" :key="i" class="mb-3">{{ k.prize.prompt }}</p>
+          <div class="my-10">
+            <v-btn color="primary" variant="outlined" width="120" @click="showDialog = false">取 消</v-btn>
+            <v-btn color="primary" width="120" class="ml-5" @click.stop="emit('success')">前往领取</v-btn>
+          </div>
+        </div>
+      </CtDialog>
+    </div>
   </div>
 </template>
 
 <script setup>
 defineOptions({ name: 'prizeDraw'})
-import Snackbar from '@/plugins/snackbar'
-import city from './prizeDraw/city.vue'
+import gridPage from './prizeDraw/grid.vue'
+import slotMachinePage from './prizeDraw/slotMachine.vue'
 import { ref } from 'vue'
-// const props = defineProps({
-//   number: {
-//     type: [String, Number],
-//     default: 0,
-//   }
-// })
-
-// const blocksImg1 = { src: 'https://img1.baidu.com/it/u=681765036,1809656907&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400', width: '100%', height: '100%' }
+import { getLuckLotteryRecordByOrderId } from '@/api/mall/prize'
+import Snackbar from '@/plugins/snackbar'
 
-const myLucky = ref()
-const blocks = [
-  // { padding: '10px', background: '#fff', imgs:[] },
-  { padding: '10px', background: '#00897B', borderRadius: 6 },
-]
-const prizeImg = {
-  src: 'https://img1.baidu.com/it/u=681765036,1809656907&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400',
-  activeSrc: 'https://bpic.588ku.com/element_origin_min_pic/19/11/15/a6f8bd3b208aca40e3de49209ab309ca.jpg',
-  width: '100%',
-  top: '0%'
-}
-const prizes = [
-  { x: 0, y: 0, imgs: [prizeImg] },
-  { x: 1, y: 0, imgs: [prizeImg] },
-  { x: 2, y: 0, imgs: [prizeImg] },
-  { x: 2, y: 1, imgs: [prizeImg] },
-  { x: 2, y: 2, imgs: [prizeImg] },
-  { x: 1, y: 2, imgs: [prizeImg] },
-  { x: 0, y: 2, imgs: [prizeImg] },
-  { x: 0, y: 1, imgs: [prizeImg] }
-]
-const buttons = [
-  {
-    x: 1, y: 1,
-    background: '#fe920200',
-    borderRadius: '10px',
-    imgs: [{
-      src: 'https://img1.baidu.com/it/u=3949019928,2138080900&fm=253&fmt=auto&app=138&f=PNG?w=300&h=300',
-      width: '100%',
-      height: '100%',
-    }],
+const emit = defineEmits(['success'])
+const props = defineProps({
+  lotteryId: [Number, String],
+  orderId: [Number, String],
+  type: {
+    type: String,
+    default: '1'
   }
-]
-const defaultConfig = {
-  gutter: 10, // 格子之间的间隙
-  speed: 10 // 旋转速度的峰值
-}
+})
 
-const startCallback = () => {
-  if (!number.value) return Snackbar.warning('抽奖次数已用完!')
-  // 调用抽奖组件的play方法开始游戏
-  myLucky.value.play()
-  // 模拟调用接口异步抽奖
-  setTimeout(() => {
-    // 假设后端返回的中奖索引是0
-    const index = 3
-    // 调用stop停止旋转并传递中奖索引
-    myLucky.value.stop(index)
-  }, 1500)
-}
+const disabled = ref(false)
 
-const endCallback  = (prize) => {
-  console.log(prize, 'end')
-  getData()
+// 获取中奖记录
+const prizeData = ref({})
+const getRecord = async () => {
+  const data = await getLuckLotteryRecordByOrderId(props.orderId)
+  prizeData.value = data || []
+  if (!data || !data.length) disabled.value = true
 }
+if (props.orderId) getRecord()
 
-
-// 获取抽奖次数
-const number = ref(10)
-const getData = async () => {
-  number.value--
-  // const data = await getProductDetail()
-  // number.value = data || 0
+const showDialog = ref(false)
+const endCallback = () => {
+  if (!prizeData.value.length) return Snackbar.warning('您已经抽过奖了哦')
+  showDialog.value = true
+  disabled.value = true
 }
-getData()
-
 </script>
 
 <style scoped lang="scss">
 .prizeDrawBox {
-  padding: 40px;
+  padding: 20px 40px;
   background-color: var(--default-bgc);
-  display: flex;
-  flex-direction: column;
-  // justify-content: center;
-  align-items: center;
 }
 .prizeDraw {
   margin: 0 auto; 
-  cursor: pointer;
 }
 .numberBox {
   font-size: 20px;

+ 97 - 0
src/views/mall/components/prizeDraw/grid.vue

@@ -0,0 +1,97 @@
+<!-- 九宫格 -->
+<template>
+  <div>
+    <LuckyGrid
+      ref="myLucky"
+      width="300px"
+      height="300px"
+      :prizes="prizes"
+      :blocks="blocks"
+      :buttons="buttons"
+      :default-config="defaultConfig"
+      class="prizeDraw"
+      @start="startCallback"
+      @end="endCallback"
+    />
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'prizeDraw-LuckyGrid'})
+import { getPrizeByLotteryId } from '@/api/mall/prize'
+import Snackbar from '@/plugins/snackbar'
+import { ref } from 'vue'
+
+const emit = defineEmits(['start', 'end'])
+const props = defineProps({ lotteryId: [Number, String], disabled: Boolean })
+
+const myLucky = ref()
+// 背景样式
+const blocks = [
+  { padding: '10px', background: '#00897B', borderRadius: 6 }
+]
+const prizes = ref([
+  { x: 0, y: 0, imgs: [] },
+  { x: 1, y: 0, imgs: [] },
+  { x: 2, y: 0, imgs: [] },
+  { x: 2, y: 1, imgs: [] },
+  { x: 2, y: 2, imgs: [] },
+  { x: 1, y: 2, imgs: [] },
+  { x: 0, y: 2, imgs: [] },
+  { x: 0, y: 1, imgs: [] }
+])
+const buttons = [
+  {
+    x: 1, y: 1,
+    background: '#fe920200',
+    borderRadius: '10px',
+    imgs: [{
+      src: 'https://img1.baidu.com/it/u=3949019928,2138080900&fm=253&fmt=auto&app=138&f=PNG?w=300&h=300',
+      width: '100%',
+      height: '100%'
+    }]
+  }
+]
+const defaultConfig = {
+  gutter: 10, // 格子之间的间隙
+  speed: 10 // 旋转速度的峰值
+}
+
+// 根据活动id获取奖品列表
+const getPrizeData = async (lotteryId) => {
+  let id = lotteryId || props.lotteryId
+  const data = await getPrizeByLotteryId(id)
+
+  data.forEach((item, index) => {
+    prizes.value[index].prize = item
+    prizes.value[index].imgs = [{
+      src: item.image,
+      activeSrc: 'https://bpic.588ku.com/element_origin_min_pic/19/11/15/a6f8bd3b208aca40e3de49209ab309ca.jpg',
+      width: '100%',
+      top: '0%'
+    }]
+  })
+}
+if (props.lotteryId) getPrizeData()
+
+const startCallback = () => {
+  if (props.disabled) return Snackbar.warning('您已经参与过该抽奖活动了哦')
+  emit('start')
+  // 调用抽奖组件的play方法开始游戏
+  myLucky.value.play()
+  // 模拟调用接口异步抽奖
+  setTimeout(() => {
+    // 假设后端返回的中奖索引是0
+    const index = 3
+    // 调用stop停止旋转并传递中奖索引
+    myLucky.value.stop(index)
+  }, 1500)
+}
+
+const endCallback  = (value) => {
+  emit('end', value)
+}
+
+</script>
+<style lang="scss" scoped>
+</style>

+ 96 - 0
src/views/mall/components/prizeDraw/slotMachine.vue

@@ -0,0 +1,96 @@
+<!-- 老虎机 -->
+<template>
+  <div class="mb-n5" v-if="prizes?.length">
+    <SlotMachine
+      ref="myLucky"
+      width="300px"
+      :height="height + 'px'"
+      :prizes="prizes"
+      :blocks="blocks"
+      :slots="slots"
+      accelerationTime="1000"
+      decelerationTime="10000"
+      :default-config="defaultConfig"
+      class="prizeDraw"
+      @start="startCallback"
+      @end="endCallback"
+    />
+    <v-img
+      class="cursor-pointer"
+      src="https://img1.baidu.com/it/u=3949019928,2138080900&fm=253&fmt=auto&app=138&f=PNG?w=300&h=300"
+      :width="100"
+      style="margin: 0 auto;"
+      @click="startCallback"
+    />
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'prizeDraw-LuckyGrid'})
+import { getPrizeByLotteryId } from '@/api/mall/prize'
+import Snackbar from '@/plugins/snackbar'
+import { ref } from 'vue'
+
+const emit = defineEmits(['start', 'end'])
+const props = defineProps({ lotteryId: [Number, String], height: [Number, String], disabled: Boolean })
+
+const myLucky = ref()
+// 背景样式
+const blocks = [
+  { padding: '10px', background: '#00897B', borderRadius: 6 },
+]
+// 转速与方向
+const slots = [
+  { speed: 15, direction: -1 },
+  { speed: 15, direction: 1 },
+  { speed: 15, direction: -1 },
+]
+const prizes = ref([])
+const defaultConfig = {
+  rowSpacing: '10px',
+  colSpacing: '10px',
+  accelerationTime: 1000, // 开始旋转时间
+  decelerationTime: 5000, // 缓慢停止时间
+}
+
+// 根据活动id获取奖品列表
+const getPrizeData = async (lotteryId) => {
+  let id = lotteryId || props.lotteryId
+  const data = await getPrizeByLotteryId(id)
+  prizes.value = []
+  data.forEach(item => {
+    prizes.value.push({
+      prize: item,
+      background: '#fe920200',
+      borderRadius: '10px',
+      imgs: [{
+        width: '100%',
+        top: '0%',
+        src: item.image
+      }]
+    })
+  })
+}
+if (props.lotteryId) getPrizeData()
+
+const startCallback = () => {
+  if (props.disabled) return Snackbar.warning('您已经参与过该抽奖活动了哦')
+  emit('start')
+  // 调用抽奖组件的play方法开始游戏
+  myLucky.value.play()
+  // 模拟调用接口异步抽奖
+  setTimeout(() => {
+    // 假设后端返回的中奖索引是0
+    const index = 3
+    // 调用stop停止旋转并传递中奖索引
+    myLucky.value.stop(index)
+  }, 1500)
+}
+
+const endCallback  = (value) => {
+  emit('end', value)
+}
+
+</script>
+<style lang="scss" scoped>
+</style>

+ 92 - 0
src/views/mall/goodsList/index.vue

@@ -0,0 +1,92 @@
+<!--  -->
+<template>
+  <div>
+    <Navbar style="min-width: 1184px;" @search="keyword=> getData(keyword)" />
+    <div class="white-bgc py-3" style="border-top: 1px solid #eee;">
+      <div class="default-width my-3" :loading="loading">
+        <div v-if="goodList.length">
+          <div class="goods-box mt-5">
+            <v-card v-for="val in goodList" :key="val.id" class="goods-box-item" hover elevation="2" @click="handleClickGood(val)">
+              <v-img :src="val.picUrl" width="100%" height="68%" cover></v-img>
+              <div class="px-3 pt-3">
+                <p class="ellipsis color-333">{{ val.name }}</p>
+                <p class="color-999 ellipsis font-size-14 mt-1">{{ val.introduction }}</p>
+                <div class="mt-1 d-flex justify-space-between">
+                  <div class="goods-box-item-price">¥{{ isArray(val.price) ? fen2yuan(val.price[0]) : fen2yuan(val.price) }}</div>
+                  <div class="font-size-15 mt-1" style="color: #c4c4c4">{{ salesAndStock(val) }}</div>
+                </div>
+              </div>
+            </v-card>
+          </div>
+          <CtPagination :total="total" :page="page.pageNo" :limit="page.pageSize" @handleChange="handleChangePage"></CtPagination>
+        </div>
+        <Empty v-else :elevation="false" message="没有找到相关商品~"></Empty>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'mall-goodsList-index'})
+import Navbar from '@/views/mall/components/navbar.vue'
+import { useRoute } from 'vue-router'; const route = useRoute()
+import { getGoodsList } from '@/api/mall/index'
+import { isArray } from 'lodash-es'
+import { formatSales, fen2yuan } from '@/hooks/web/useGoods'
+import { ref, computed } from 'vue'
+
+const page = ref({
+  pageNo: 1,
+  pageSize: 10
+})
+
+// 根据id获取商品列表
+const loading = ref(false)
+const total = ref(0)
+const goodList = ref([])
+const getData = async (keyword) => {
+  const params = {
+    ...page.value
+  }
+  console.log('keyword:', keyword)
+  console.log('route.query.keyWord:', route.query.keyWord)
+  if (route?.query?.keyWord || keyword) params.keyword = keyword || route.query.keyWord
+  const { list, total: number } = await getGoodsList(params)
+  goodList.value = list
+  total.value = number || 0
+}
+getData()
+
+// 分页
+const handleChangePage = (e) => {
+  page.value.pageNo = e
+  getData()
+}
+
+// 格式化销量、库存信息
+const salesAndStock = computed(() => (data) => {
+  let text = []
+  text.push(formatSales(undefined, data.salesCount))
+  return text.join(' | ')
+})
+
+</script>
+<style lang="scss" scoped>
+.goods-box {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  &-item {
+    height: 330px;
+    width: calc((100% - 48px) / 5);
+    margin: 0 12px 12px 0;
+    &:nth-child(5n) {
+      margin-right: 0;
+    }
+    &-price {
+      color: #ff3000;
+      font-size: 20px;
+    }
+  }
+}
+</style>

+ 9 - 1
src/views/mall/home/components/carousel.vue

@@ -10,8 +10,16 @@
       </v-img> -->
 
       <!-- <figure> -->
-        <img :src="item.imgUrl" :lazy-src="item.imgUrl" style="width: 100%;" />
+        <!-- <img :src="item.imgUrl" :lazy-src="item.imgUrl" style="width: 100%;" /> -->
       <!-- </figure> -->
+      
+      <v-img :src="item.imgUrl" :lazy-src="item.imgUrl" style="width: 100%">
+        <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>
     </v-carousel-item>
   </v-carousel>
 </template>

+ 1 - 1
src/views/mall/home/components/hotGoods.vue

@@ -2,7 +2,7 @@
   <div>
     <div class="d-flex justify-space-between color-666">
       <div class="color-primary" style="font-size: 25px;">热门商品</div>
-      <div class="cursor-pointer">查看更多</div>
+      <!-- <div class="cursor-pointer" @click="router.push('/mall/goodsList')">查看更多</div> -->
     </div>
     <div v-if="goodList.length" class="goods-box mt-5">
       <v-card v-for="val in goodList" :key="val.id" class="goods-box-item" hover elevation="2" @click="handleClickGood(val)">

+ 5 - 1
src/views/mall/home/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div style="min-width: 1184px;" class="white-bgc">
     <!-- 导航栏 -->
-    <Navbar @login="handleLogin" />
+    <Navbar />
 
     <div id="contentBox" ref="scrollBox">
       <!-- 轮播图 -->
@@ -76,6 +76,10 @@ const loginClose = () => {
   showLogin.value = false
   Snackbar.warning('您已取消登录')
 }
+
+const handleSearch = (val) => {
+  
+}
 </script>
 
 <style scoped lang="scss">

+ 2 - 2
src/views/mall/payOver/components/show.vue

@@ -2,8 +2,8 @@
 <template>
   <div class="d-flex flex-column align-center">
     <div style="color: #37ad1e; font-size: 60px;" class="mdi mdi-check-circle mt-5"></div>
-    <div style="font-weight: 600; color: #777;">支付成功</div>
-    <div style="font-weight: 500; color: #777;" class="mt-3">¥{{ price || 0.00 }}</div>
+    <div style="font-weight: 600; color: #777;">支付成功 ¥{{ price || 0.00 }}</div>
+    <!-- <div style="font-weight: 500; color: #777;" class="mt-3"></div> -->
     <div class="mt-3">
       <v-btn class="mx-3" color="primary" variant="outlined" @click="router.push('/mall')">商城首页</v-btn>
       <v-btn class="mx-3" color="primary" variant="outlined" to="/mall/user/order">查看订单</v-btn>

+ 24 - 2
src/views/mall/payOver/index.vue

@@ -2,18 +2,40 @@
 <template>
   <Navbar class="mb-3" />
   <v-card class="default-width my-3">
-    <showText></showText>
+    <showText :class="showPrizeDraw ? '' : 'mb-15'"></showText>
+
     <!-- 抽奖 -->
-    <prizeDraw class="prizeDraw mx-15 my-7" ></prizeDraw>
+    <prizeDraw v-if="showPrizeDraw" type="2" :orderId="orderId" :lotteryId="lotteryId" class="prizeDraw mx-15 my-7" @success="handleReceive"></prizeDraw>
   </v-card>
 </template>
 
 <script setup>
 defineOptions({name: 'payOver-index'})
+import { ref } from 'vue'
 import Navbar from '../components/navbar.vue'
 import showText from './components/show.vue'
 import prizeDraw from '@/views/mall/components/prizeDraw.vue'
+import { useRoute, useRouter } from 'vue-router'
+import { getPrizeByGoodsId } from '@/api/mall/prize'
+
+const { spuId, orderId } = useRoute().query
+const showPrizeDraw = ref(false)
+const lotteryId = ref('')
+const getLottery = async () => {
+  if (!spuId) return
+  const data = await getPrizeByGoodsId(spuId)
+  showPrizeDraw.value = data && Object.keys(data).length > 0
 
+  lotteryId.value = data.id
+}
+getLottery()
+
+// 前往我的奖品
+const router = useRouter()
+const handleReceive = () => {
+  router.push('/mall/user/prize')
+}
 </script>
+
 <style lang="scss" scoped>
 </style>

+ 2 - 2
src/views/mall/user/index.vue

@@ -1,6 +1,6 @@
 <template>
-  <Navbar class="mb-3" />
-  <div class="d-flex parent default-width mb-5">
+  <Navbar />
+  <div class="d-flex parent default-width mb-5 mt-3">
     <v-card class="left">
       <v-list color="primary">
         <div class="text-center my-3">

+ 37 - 35
src/views/mall/user/order/index.vue

@@ -19,13 +19,13 @@
         <!-- 操作按钮 -->
         <div class="text-end pa-3 font-size-13 color-666">
           <div>共{{ val.productCount }}件商品,合计:¥{{ fen2yuan(val.payPrice) }}</div>
-          <v-btn v-if="val.buttons.length === 0" class="mt-2" variant="tonal" rounded="xl" @click.stop="handleDetail(val)">查看详情</v-btn>
-          <v-btn v-if="val.buttons.includes('confirm')" class="mt-2" variant="tonal" color="success" rounded="xl" @click.stop="handleConfirm(val)">确认收货</v-btn>
-          <v-btn v-if="val.buttons.includes('comment')" class="mt-2" variant="tonal" rounded="xl" @click.stop="handleComment(val)">评价</v-btn>
-          <v-btn v-if="val.buttons.includes('express')" class="mt-2" variant="tonal" rounded="xl">查看物流</v-btn>
-          <v-btn v-if="val.buttons.includes('cancel')" class="mt-2" variant="tonal" rounded="xl" @click.stop="handleCancel(val)">取消订单</v-btn>
-          <v-btn v-if="val.buttons.includes('delete')" class="mt-2" variant="tonal" color="error" rounded="xl" @click.stop="handleDelete(val)">删除订单</v-btn>
-          <v-btn v-if="val.buttons.includes('pay')" class="mt-2 ml-3" variant="tonal" rounded="xl" @click.stop="handlePay(val)">继续支付</v-btn>
+          <v-btn class="mt-2" variant="tonal" rounded="xl" @click.stop="handleDetail(val)">查看详情</v-btn>
+          <v-btn v-if="val.buttons.includes('confirm')" class="mt-2 ml-3" variant="tonal" color="success" rounded="xl" @click.stop="handleConfirm(val)">确认收货</v-btn>
+          <!-- <v-btn v-if="val.buttons.includes('comment')" class="mt-2" variant="tonal" rounded="xl" @click.stop="handleComment(val)">评价</v-btn> -->
+          <!-- <v-btn v-if="val.buttons.includes('express')" class="mt-2" variant="tonal" rounded="xl">查看物流</v-btn> -->
+          <v-btn v-if="val.buttons.includes('cancel')" class="mt-2 ml-3" variant="tonal" rounded="xl" @click.stop="handleCancel(val)">取消订单</v-btn>
+          <v-btn v-if="val.buttons.includes('delete')" class="mt-2 ml-3" variant="tonal" color="error" rounded="xl" @click.stop="handleDelete(val)">删除订单</v-btn>
+          <v-btn v-if="val.buttons.includes('pay')" class="mt-2 ml-3" variant="tonal" color="primary" rounded="xl" @click.stop="handlePay(val)">继续支付</v-btn>
         </div>
       </div>
       <CtPagination :total="total" :page="queryParams.pageNo" :limit="queryParams.pageSize" @handleChange="handleChangePage"></CtPagination>
@@ -69,7 +69,9 @@ const tabList = [
   { title: '待付款', value: 0 },
   { title: '待发货', value: 10 },
   { title: '待收货', value: 20 },
-  { title: '待评价', value: 30 }
+  { title: '已完成', value: 30 },
+  { title: '已取消', value: 40 },
+  // { title: '待评价', value: 30 }
 ]
 const total = ref(0)
 const queryParams = ref({
@@ -123,33 +125,33 @@ const handleCancel = async ({ id }) => {
 }
 
 // 商品评论
-const showDialog = ref(false)
-const commentOrderId = ref(null) // 订单id
-const commentFormRef = ref()
-const handleComment = (val) => {
-  commentOrderId.value = val.id
-  showDialog.value = true
-}
-const handleClose = () => {
-  commentOrderId.value = null
-  showDialog.value = false
-}
-const handleSubmit = async () => {
-  const commentList = commentFormRef.value.commentList
-  for (const comment of commentList) {
-    await createOrderItemComment(comment)
-  }
-  Snackbar.success('评论成功')
-  handleClose()
-  getOrderPage()
-}
-
-// 收货成功后提示去评论
-const handlePromptComment = (id) => {
-  Confirm('确认收货成功', '是否前往评价?', { sureText: '立即评价', cancelText: '关闭' }).then(() => {
-    handleComment({ id })
-  })
-}
+// const showDialog = ref(false)
+// const commentOrderId = ref(null) // 订单id
+// const commentFormRef = ref()
+// const handleComment = (val) => {
+//   commentOrderId.value = val.id
+//   showDialog.value = true
+// }
+// const handleClose = () => {
+//   commentOrderId.value = null
+//   showDialog.value = false
+// }
+// const handleSubmit = async () => {
+//   const commentList = commentFormRef.value.commentList
+//   for (const comment of commentList) {
+//     await createOrderItemComment(comment)
+//   }
+//   Snackbar.success('评论成功')
+//   handleClose()
+//   getOrderPage()
+// }
+
+// // 收货成功后提示去评论
+// const handlePromptComment = (id) => {
+//   Confirm('确认收货成功', '是否前往评价?', { sureText: '立即评价', cancelText: '关闭' }).then(() => {
+//     handleComment({ id })
+//   })
+// }
 
 // 确认收货
 const handleConfirm = ({ id }) => {

+ 65 - 23
src/views/mall/user/prize/index.vue

@@ -6,50 +6,92 @@
     :loading="false"
     :elevation="0"
     :isTools="false"
+    :total="total"
     :showPage="true"
     :showSelect="false"
 		:page-info="queryParams"
     itemKey="id"
   >
+    <template #prize="{ item }">
+      <div class="d-flex align-center my-1">
+        <v-img :src="item.prize.image" width="80px" height="80px"></v-img>
+        <div class="ml-1">{{ item.prize.name }}</div>
+      </div>
+    </template>
+    <template #deliverInfo="{ item }">
+      {{ item.record.deliverInfo ? JSON.parse(item.record.deliverInfo).name + '-' + JSON.parse(item.record.deliverInfo).no  : ''}}
+    </template>
+    <template #receiveInfo="{ item }">
+      {{ orderReceiveInfo(item) }}
+    </template>
     <template #actions="{ item }">
-      <v-btn color="primary" @click.stop="handleSelectAddress(item)" variant="text">选择收货地址</v-btn>
+      <v-btn v-if="!item.record.isReceive && !item.record.receiveInfo" color="primary" @click.stop="handleReceive(item)" variant="text">领取</v-btn>
     </template>
   </CtTable>
+
+  <CtDialog :visible="showDialog" titleClass="text-h6" :footer="true" :widthType="1" title="选择收货地址" @submit="handleSubmit" @close="showDialog = false">
+    <div style="min-height: 60vh;">
+      <SelectAddress ref="selectAddressRef" showSelect></SelectAddress>
+    </div>
+  </CtDialog>
 </template>
 
 <script setup>
 defineOptions({ name: 'mall-user-prize-index' })
-import { ref } from 'vue'
+import { ref, computed } from 'vue'
+import SelectAddress from '@/views/mall/user/address'
+import Snackbar from '@/plugins/snackbar'
+import { getLuckLotteryRecordPage, luckyLotteryRecordReceive } from '@/api/mall/prize'
 
 const queryParams = ref({
 	pageNo: 1,
 	pageSize: 10,
 })
-const items = ref([
-	{
-		lotteryName: '抽奖活动1',
-		name: '奖品1',
-		address: '收货地址1',
-		phone: '联系电话1',
-	},
-	{
-		lotteryName: '抽奖活动2',
-		name: '奖品2',
-		address: '收货地址2',
-		phone: '联系电话2',
-	}
-])
+const total = ref(0)
+const items = ref([])
+
 const headers = [
-  { title: '活动名称', key: 'lotteryName', sortable: false },
-  { title: '奖品信息', key: 'name', sortable: false },
-  { title: '收货地址', key: 'address', sortable: false },
-  { title: '联系电话', key: 'phone', sortable: false },
-  { title: '快递信息', key: 'deliveryInfo', sortable: false },
+  { title: '活动名称', key: 'lottery.name', sortable: false },
+  { title: '奖品信息', key: 'prize', sortable: false },
+  { title: '是否领取', key: 'isReceive', sortable: false, value: item => item.record.isReceive ? '是' : '否' },
+  { title: '收货信息', key: 'receiveInfo', sortable: false },
+  { title: '快递信息', key: 'deliverInfo', sortable: false },
   { title: '操作', key: 'actions', sortable: false }
 ]
 
-const handleSelectAddress = (item) => {
-	console.log(item, 'select')
+// 获取中奖记录
+const getLuckLotteryRecordList = async () => {
+  const result = await getLuckLotteryRecordPage(queryParams.value)
+  items.value = result?.list || []
+  total.value = result?.total || 0
+}
+getLuckLotteryRecordList()
+
+// 收货信息
+const orderReceiveInfo = computed(() => (item) => {
+  const info = item.record.receiveInfo ? JSON.parse(item.record.receiveInfo) : {}
+  if (!info || !Object.keys(info).length) return ''
+  return `${info.name},${info.mobile},${info.areaName} ${info.detailAddress}`
+})
+
+// 领取
+const selectAddressRef = ref()
+const showDialog = ref(false)
+const recordId = ref('')
+const handleReceive = (item) => {
+  recordId.value = item.record.id
+  showDialog.value = true
+}
+
+const handleSubmit = async () => {
+  const receive = selectAddressRef.value.getSelected() || {}
+  if (!receive || !Object.keys(receive).length) return Snackbar.warning('请选择您的收货地址')
+  // console.log(receive, '收货地址', recordId.value)
+  await luckyLotteryRecordReceive({ id: recordId.value, receiveInfo: JSON.stringify(receive) })
+  showDialog.value = false
+  recordId.value = null
+  Snackbar.success('领取成功,待商家发货')
+  getLuckLotteryRecordList()
 }
 </script>
 

+ 3 - 3
src/views/publicRecruitment/components/table.vue

@@ -27,7 +27,7 @@
 <script setup>
 defineOptions({ name: 'myPublicRecruitment-table-page'})
 import { timesTampChange } from '@/utils/date'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 import { commissionCalculation } from '@/utils/position'
 
 const emit = defineEmits(['page'])
@@ -40,8 +40,8 @@ defineProps({
 
 const headers = [
   { title: '牛人', value: 'sendPerson.name', key: 'name', sortable: false },
-  { title: '应聘公司', key: 'enterprise.anotherName', sortable: false, value: item => dealEnterpriseName(item.enterprise.anotherName || item.enterprise.name) },
-  { title: '应聘职位', key: 'job', value: item => item?.job?.name, sortable: false },
+  { title: '应聘公司', key: 'enterprise.anotherName', sortable: false, value: item => formatName(item.enterprise.anotherName || item.enterprise.name) },
+  { title: '应聘职位', key: 'job', value: item => formatName(item?.job?.name), sortable: false },
   { title: '赏金', key: 'hirePrice', sortable: false },
   { title: '岗位薪资', key: 'salary', value: item => item?.job?.payFrom && item?.job?.payTo ? `${item?.job?.payFrom ? item?.job?.payFrom + '-' : ''}${item?.job?.payTo}` : '面议', sortable: false },
   { title: '推荐时间', key: 'createTime', value: item => timesTampChange(item.createTime), sortable: false },

+ 6 - 6
src/views/recruit/components/message/components/chatting.vue

@@ -18,7 +18,7 @@
           <template v-if="info.enterpriseId">
             <span>{{ info.postNameCn }}</span>
             <span v-if="info.postNameCn && info.enterpriseAnotherName" class="septal-line"></span>
-            <span>{{ dealEnterpriseName(info.enterpriseAnotherName) }}</span>
+            <span>{{ formatName(info.enterpriseAnotherName) }}</span>
           </template>
         </p>
       </div>
@@ -28,7 +28,7 @@
       <div v-for="val in interview" :key="val.id" class="color-666">
         <div class="d-flex justify-space-between">
           <div class="font-weight-bold color-primary">
-            <span>{{ val.job.name }}</span>
+            <span>{{ formatName(val.job.name) }}</span>
             <span v-if="!val.job.payFrom && !val.job.payTo" class="ml-3">面议</span>
             <span v-else class="ml-3">{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}</span>
           </div>
@@ -69,7 +69,7 @@
               :elevation="3"
             >
               <div class="pa-3">
-                <div class="text-h6"> {{ val.payload?.content?.positionInfo?.name }}</div>
+                <div class="text-h6"> {{ formatName(val.payload?.content?.positionInfo?.name) }}</div>
                 <div v-if="!val.payload?.content?.positionInfo?.payFrom && !val.payload?.content?.positionInfo?.payTo" class="text-subtitle-2">薪酬待遇: 面议</div>
                 <div v-else class="text-subtitle-2">薪酬待遇: {{ val.payload?.content?.positionInfo?.payFrom ? val.payload?.content?.positionInfo?.payFrom + ' - ' : '' }}{{ val.payload?.content?.positionInfo?.payTo }}</div>
                 <div>
@@ -158,7 +158,7 @@
               </v-card>
             </div>
             <div v-else-if="val.payload.type === -1" class="message-text" :class="{ active: val.from_uid === IM.uid}">
-              {{ val.payload?.content.text }}
+              {{ formatName(val.payload?.content.text) }}
             </div>
             <div v-else class="message-text" :class="{ active: val.from_uid === IM.uid}">
               {{ val.payload?.content }}
@@ -181,7 +181,7 @@
                   </div>
                   <div class=" d-flex justify-space-between">
                     <div class="text-h6 mb-1">
-                      {{ val.payload?.content?.positionInfo?.data?.name }}
+                      {{ formatName(val.payload?.content?.positionInfo?.data?.name) }}
                     </div>
                     <div v-if="!val.payload?.content?.positionInfo?.data?.payFrom && !val.payload?.content?.positionInfo?.data?.payTo">面议</div>
                     <div v-else>
@@ -240,7 +240,7 @@ import { useI18n } from '@/hooks/web/useI18n'
 import { useRouter } from 'vue-router';
 import { getDict } from '@/hooks/web/useDictionaries'
 import { getUserAvatar } from '@/utils/avatar'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 import { useUserStore } from '@/store/user'
 const isEnterprise = inject('isEnterprise')

+ 3 - 3
src/views/recruit/components/message/index.vue

@@ -46,7 +46,7 @@
                 <div v-if="!isEnterprise" class="mt-2 d-flex align-center">
                   {{ title }}
                   <div class="ml-3 color-666 font-size-14 enterprise-name ellipsis" :style="{'color': val.channel.channelID === info?.channel?.channelID ? '#00897B' : '#666'}">
-                    {{ dealEnterpriseName(val.userInfoVo?.userInfoResp?.enterpriseAnotherName) }}
+                    {{ formatName(val.userInfoVo?.userInfoResp?.enterpriseAnotherName) }}
                     <span class="line" v-if="val.userInfoVo?.userInfoResp?.postNameCn && val.userInfoVo?.userInfoResp?.enterpriseAnotherName"></span>
                     {{ val.userInfoVo?.userInfoResp?.postNameCn }}
                   </div>
@@ -189,7 +189,7 @@ import { saveInterviewInvite } from '@/api/recruit/enterprise/interview'
 import { savePersonResumeCv } from '@/api/recruit/personal/resume'
 import { userInterviewInviteReject, userInterviewInviteConsent } from '@/api/recruit/personal/personalCenter'
 import { getPersonResumeCv } from '@/api/recruit/personal/resume'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 import { useIMStore } from '@/store/im'
 import { useUserStore } from '@/store/user'
@@ -663,7 +663,7 @@ const getPositionList = async () => {
   positionList.value = list.map(e => {
     const salary = e.payFrom && e.payTo ? `${e.payFrom ? e.payFrom + '-' : ''}${e.payTo}${e.payName ? '/' + e.payName : ''}` : '面议'
     return {
-      label: `${e.name}${e.areaName ? '_' + e.areaName : ''} ${salary}`,
+      label: `${formatName(e.name)}${e.areaName ? '_' + e.areaName : ''} ${salary}`,
       value: e.id,
       data: e
     }

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

@@ -208,8 +208,9 @@ const formItems = ref({
       type: 'text',
       key: 'anotherName',
       value: '',
-      label: '企业展示名称',
+      label: '企业对外显示名称 *',
       counter: 50,
+      rules: [v => !!v || '请输入企业对外显示名称'],
       blur: saveRegisterInfo
     },
     {

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

@@ -111,7 +111,8 @@ const handleUploadFile = async (e) => {
     return
   }
 
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('文件格式不正确')
   const isImage = ['jpg', 'png', 'jpeg'].includes(fileType)
 

+ 3 - 2
src/views/recruit/enterprise/interviewManagement/components/item.vue

@@ -3,9 +3,9 @@
     <div class="d-flex align-center">
       <div class="mr-5 font-size-16" style="color: orange; width: 96px;">{{ timesTampChange(item.time, 'Y-M-D h:m') }}</div>
       <v-avatar class="mr-2" size=40 :image="getUserAvatar(item?.person?.avatar, item?.person?.sex)"></v-avatar>
-      <div class="d-flex flex-column mr-3" style="width: 110px;">
+      <div class="d-flex flex-column mr-3" style="width: 120px;">
         <span class="ellipsis mb-1">{{ item?.person?.name || item?.phone }}</span>
-        <span class="ellipsis" style="color: var(--color-999);">{{ item?.job?.name }}</span>
+        <span class="ellipsis" style="color: var(--color-999);">{{ formatName(item?.job?.name) }}</span>
       </div>
     </div>
     <div class="d-flex align-center right-item">
@@ -91,6 +91,7 @@ import InvitePage from './invite.vue'
 import Snackbar from '@/plugins/snackbar'
 import Confirm from '@/plugins/confirm'
 import { getUserAvatar } from '@/utils/avatar'
+import { formatName } from '@/utils/getText'
 
 defineProps({
   items: Array,

+ 2 - 1
src/views/recruit/enterprise/interviewManagement/index.vue

@@ -65,6 +65,7 @@ import { dealDictArrayData } from '@/utils/position'
 import { timesTampChange, getStartAndEndOfDay } from '@/utils/date'
 import itemPage from './components/item.vue'
 import Snackbar from '@/plugins/snackbar'
+import { formatName } from '@/utils/getText'
 
 const items = ref([])
 const statusList = ref()
@@ -160,7 +161,7 @@ const getPositionList = async () => {
   const list = dealDictArrayData([], data)
   positionItems.value = list.map(e => {
     const salary = e.payFrom && e.payTo ? `${e.payFrom ? e.payFrom + '-' : ''}${e.payTo}${e.payName ? '/' + e.payName : ''}` : '面议'
-    return { label: `${e.name}${e.areaName ? '_' + e.areaName : ''} ${salary}_${e.status === 0 ? '招聘中' : '已关闭'}`, value: e.id }
+    return { label: `${formatName(e.name)}${e.areaName ? '_' + e.areaName : ''} ${salary}_${e.status === 0 ? '招聘中' : '已关闭'}`, value: e.id }
   })
 }
 getPositionList()

+ 2 - 1
src/views/recruit/enterprise/jobFair/components/job.vue

@@ -34,7 +34,7 @@
             <div class="position">
               <div class="d-flex align-center justify-space-between">
                 <!-- <span v-if="val.name.indexOf('style')" v-html="val.name" class="position-name"></span> -->
-                <span class="position-name">{{ val.name }}</span>
+                <span class="position-name">{{ formatName(val.name) }}</span>
                 <div>
                   <v-btn size="small" color="primary" @click="handleTo(val)">添加至双选会</v-btn>
                 </div>
@@ -79,6 +79,7 @@ import Snackbar from '@/plugins/snackbar'
 import { getEnterprisePubJobTypePermission } from '@/api/recruit/enterprise/position'
 import { getJobAdvertisedList } from '@/api/position'
 import download from '@/utils/download'
+import { formatName } from '@/utils/getText'
 // import Confirm from '@/plugins/confirm'
 
 const props = defineProps({ id: [String, Number]})

+ 2 - 1
src/views/recruit/enterprise/jobFair/components/resume.vue

@@ -123,6 +123,7 @@ import { previewFile } from '@/utils'
 import { getUserAvatar } from '@/utils/avatar'
 import DatePicker from '@/components/FormUI/datePicker'
 import { timesTampChange } from '@/utils/date'
+import { formatName } from '@/utils/getText'
 
 const userStore = useUserStore() 
 const route = useRoute()
@@ -196,7 +197,7 @@ const headers = computed(() => {
     { title: '姓名', value: 'studentId', sortable: false },
     { title: '学校', value: 'student.schoolName', sortable: false },
     { title: '专业', value: 'major', sortable: false },
-    { title: '应聘职位', value: 'enterpriseRecruit.enterpriseRecruitJobName', sortable: false },
+    { title: '应聘职位', key: 'enterpriseRecruit.enterpriseRecruitJobName', sortable: false, value: item => formatName(item?.enterpriseRecruit?.enterpriseRecruitJobName) },
     { title: '岗位薪资',
       key: 'pay',
       value: ({ enterpriseRecruit }) => {

+ 2 - 1
src/views/recruit/enterprise/jobFair/job/item.vue

@@ -5,7 +5,7 @@
         <div class="d-flex justify-space-between cursor-pointer" style="padding: 10px 20px;">
           <div class="position">
             <div class="d-flex align-center">
-              <span class="position-name">{{ val.name }}</span>
+              <span class="position-name">{{ formatName(val.name) }}</span>
             </div>
             <div :class="['mt-3', 'other-info', 'ellipsis']">
               <span>{{ !val.areaId ? '全国' : val.areaName }}</span>
@@ -46,6 +46,7 @@ import Snackbar from '@/plugins/snackbar'
 import { getEnterprisePubJobTypePermission } from '@/api/recruit/enterprise/position'
 import { quitJobFairPosition } from '@/api/recruit/enterprise/jobFair'
 import Confirm from '@/plugins/confirm'
+import { formatName } from '@/utils/getText'
 
 const emit = defineEmits(['refresh'])
 defineProps({

+ 2 - 2
src/views/recruit/enterprise/membershipPackage/dynamic/package.vue

@@ -1,7 +1,7 @@
 <template>
   <v-slide-group v-model="model" center-active show-arrows>
     <v-slide-group-item v-for="(val, index) in list" :key="index" v-slot="{ isSelected }">
-      <v-card :class="{'active': isSelected}" class="ma-4 list-item elevation-2 text-center" height="175" @click="handleClick(index, val)">
+      <v-card :class="{'active': isSelected}" class="ma-4 list-item elevation-2 text-center" height="155" @click="handleClick(index, val)">
         <template v-if="val.id === 'custom'">
           <div class="d-flex flex-column algin-center justify-center" style="height: 100%" :style="{'color': isSelected ? '#fff' : '#333'}">
             <div>需要发布更多职位</div>
@@ -17,7 +17,7 @@
             <span> 元</span>
           </div>
           <div class="text-decoration-line-through" :style="{'color': isSelected ? '#fff' : '#666'}">原价:{{ val.originalPrice / 100 }}元</div>
-          <div class="font-size-14 mt-3 py-2" :style="{'color': isSelected ? '#fff' : '#999'}">有效期:{{ val.day }}天</div>
+          <!-- <div class="font-size-14 mt-3 py-2" :style="{'color': isSelected ? '#fff' : '#999'}">有效期:{{ val.day }}天</div> -->
         </template>
       </v-card>
     </v-slide-group-item>

+ 4 - 2
src/views/recruit/enterprise/positionManagement/components/item.vue

@@ -21,7 +21,7 @@
           </div>
           <div class="d-flex align-center" :class="{'cursor-pointer': tab === 1, 'ml-15': tab === 1}" @click="handleDetail(val)">
             <span v-if="val.name.indexOf('style')" v-html="val.name" class="position-name"></span>
-            <span v-else class="position-name">{{ val.name }}</span>
+            <span v-else class="position-name">{{ formatName(val.name) }}</span>
           </div>
           <div :class="['mt-3', 'other-info', 'ellipsis', {'ml-10': tab === 1}]">
             <span>{{ !val.areaId ? '全国' : val.areaName }}</span>
@@ -107,6 +107,7 @@ import Snackbar from '@/plugins/snackbar'
 import { useUserStore } from '@/store/user'
 import Confirm from '@/plugins/confirm'
 import { getUnpaidOrder } from '@/api/common'
+import { formatName } from '@/utils/getText'
 
 const store = useUserStore()
 const { t } = useI18n()
@@ -222,7 +223,8 @@ const handleAction = async (index, type, { id }, item) => {
 
   // 关闭职位提醒
   if (index === 0) {
-    Confirm('系统提示', '是否确认关闭所选职位?关闭后再激活需重新收取费用!').then(async () => {
+    const text = baseInfo.value?.entitlement?.publishJobCount && baseInfo.value?.entitlement?.publishJobCount > 0 ? '将消耗一个发布点数' : '将重新收取费用'
+    Confirm('系统提示', `是否确认关闭所选职位?关闭后再激活,${text}`).then(async () => {
       await apiList[index](ids)
       Snackbar.success(t('common.operationSuccessful'))
       // 清空选项

+ 2 - 1
src/views/recruit/enterprise/resume/components/invite.vue

@@ -6,6 +6,7 @@
 <script setup>
 defineOptions({ name: 'formPage'})
 import { ref } from 'vue'
+import { formatName } from '@/utils/getText'
 
 const props = defineProps({
   itemData: {
@@ -83,7 +84,7 @@ const formItems = ref({
 if (Object.keys(props.itemData).length) {
   const obj = formItems.value.options.find(e => e.key === 'position')
   const salary = props.itemData?.job?.payFrom && props.itemData?.job?.payTo ? `${props.itemData?.job?.payFrom ? props.itemData?.job?.payFrom + '-' : ''}${props.itemData?.job?.payTo}${props.itemData?.job?.payName ? '/' + props.itemData?.job?.payName : ''}` : '面议'
-  obj.value = `${props.itemData?.job?.name}${props.itemData?.job?.areaName ? '_' + props.itemData?.job?.areaName : ''} ${salary}`
+  obj.value = `${formatName(props.itemData?.job?.name)}${props.itemData?.job?.areaName ? '_' + props.itemData?.job?.areaName : ''} ${salary}`
   formItems.value.options.find(e => e.key === 'address').value = props.itemData.job?.address
 
   const baseInfo = localStorage.getItem('entBaseInfo')

+ 2 - 1
src/views/recruit/enterprise/resume/components/screen.vue

@@ -37,6 +37,7 @@ import { getJobAdvertised } from '@/api/enterprise'
 import { getDict } from '@/hooks/web/useDictionaries'
 import { dealDictArrayData } from '@/utils/position'
 import CommonStyle from './commonStyle.vue'
+import { formatName } from '@/utils/getText'
 
 const emit = defineEmits(['search', 'reset', 'select', 'change'])
 const props = defineProps({
@@ -88,7 +89,7 @@ const getJobList = async (k) => {
   const list = dealDictArrayData([], data)
   k.items = list.map(e => {
     const salary = e.payFrom && e.payTo ? `${e.payFrom}-${e.payTo}${e.payName ? '/' + e.payName : ''}` : '面议'
-    return { label: `${e.name}${e.areaName ? '_' + e.areaName : ''} ${salary}_${e.status === 0 ? '招聘中' : '已关闭'}`, value: e.id }
+    return { label: `${formatName(e.name)}${e.areaName ? '_' + e.areaName : ''} ${salary}_${e.status === '0' ? '招聘中' : '已关闭'}`, value: e.id }
   })
   return k.items
 }

+ 2 - 1
src/views/recruit/enterprise/resume/components/table.vue

@@ -92,6 +92,7 @@ import { getUserAvatar } from '@/utils/avatar'
 import { getBlob, saveAs } from '@/utils'
 import { talkToUser, defaultTextEnt } from '@/hooks/web/useIM'
 import { useRouter } from 'vue-router'; const router = useRouter()
+import { formatName } from '@/utils/getText'
 
 const showTip = ref(false)
 const { t } = useI18n()
@@ -119,7 +120,7 @@ const headers = ref([
   { title: '求职状态', key: 'person.jobStatusName', sortable: false },
   { title: '工作经验', key: 'person.expName', sortable: false },
   { title: '最高学历', key: 'person.eduName', sortable: false },
-  { title: '应聘职位', value: 'job.name', sortable: false },
+  { title: '应聘职位', key: 'job.name', sortable: false, value: item => formatName(item.job.name) },
   { title: '投递简历时间', key: 'createTime', sortable: false },
   { title: '状态', key: 'status', sortable: false },
   { title: '操作', value: 'actions', sortable: false }

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

@@ -58,6 +58,7 @@ import Snackbar from '@/plugins/snackbar'
 import { saveInterviewInvite } from '@/api/recruit/enterprise/interview'
 import { useRouter } from 'vue-router'; const router = useRouter()
 import { talkToUser, defaultTextEnt } from '@/hooks/web/useIM'
+import { formatName } from '@/utils/getText'
 
 const query = ref({
   pageNo: 1,
@@ -65,8 +66,8 @@ const query = ref({
   jobId: null
 })
 const selectItems = ref({
-  label: '已发布职位',
-  placeholder: '请选择已发布职位',
+  label: '招聘中职位',
+  placeholder: '请选择招聘中职位',
   clearable: true,
   width: 600,
   items: []
@@ -96,7 +97,7 @@ const getJobList = async () => {
     const list = dealDictArrayData([], data)
     selectItems.value.items = list.map(e => {
       const salary = e.payFrom && e.payTo ? `${e.payFrom}-${e.payTo}${e.payName ? '/' + e.payName : ''}` : '面议'
-      return { label: `${e.name}${e.areaName ? '_' + e.areaName : ''} ${salary}_${e.status === 0 ? '招聘中' : '已关闭'}`, value: e.id, data: e }
+      return { label: `${formatName(e.name)}${e.areaName ? '_' + e.areaName : ''} ${salary}_${e.status === '0' ? '招聘中' : '已关闭'}`, value: e.id, data: e }
     })
   }
 }

+ 2 - 1
src/views/recruit/enterprise/staffInfoSetting/index.vue

@@ -137,7 +137,8 @@ const handleUploadFile = async (e) => {
   const file = e.target.files[0]
   if (!file) return
 
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式文件')
 
   const size = file.size

+ 5 - 1
src/views/recruit/enterprise/statistics/overallAnalysis.vue

@@ -45,6 +45,7 @@ import { convertTimestampsToDayRange } from '@/utils/date'
 import { analysisExport } from '@/api/recruit/enterprise/statistics'
 import download from '@/utils/download'
 import DatePicker from '@/components/FormUI/datePicker'
+import { formatName } from '@/utils/getText'
 
 const tab = ref(1)
 const date = ref(null)
@@ -77,7 +78,10 @@ const selectItems = ref({
 // 获取职位列表
 const getJobList = async () => {
   const data = await getJobAdvertised()
-  selectItems.value.items = data
+  selectItems.value.items = data.map(e => {
+    e.name = formatName(e.name)
+    return e
+  })
 }
 getJobList()
 

+ 3 - 3
src/views/recruit/enterprise/systemManagement/groupAccount/components/record.vue

@@ -23,7 +23,7 @@ import { ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
 import { timesTampChange } from '@/utils/date'
 import { enterpriseInviteRecordPage } from '@/api/recruit/enterprise/enterpriseInvite.js'
-import { dealEnterpriseName } from '@/utils/getText';
+import { formatName } from '@/utils/getText';
 defineOptions({name: 'groupAccount-component-record'})
 
 const props = defineProps({
@@ -60,9 +60,9 @@ const getData = async () => {
     const { list, total: number } = await enterpriseInviteRecordPage(query.value)
     tableData.value = list.map(e => {
       const showInfo = {
-        currentAccountEnterpriseAnotherName: dealEnterpriseName(info?.enterpriseAnotherName) || '--',
+        currentAccountEnterpriseAnotherName: formatName(info?.enterpriseAnotherName) || '--',
         currentAccountUserName: info?.name || '--',
-        name: props.inviteType - 0 ? dealEnterpriseName(e?.enterpriseUser?.enterpriseName) : e?.enterpriseUser?.name,
+        name: props.inviteType - 0 ? formatName(e?.enterpriseUser?.enterpriseName) : e?.enterpriseUser?.name,
         time: e.createTime ? timesTampChange(e.createTime) : '--',
       }
       return { showInfo, ...e }

+ 6 - 5
src/views/recruit/enterprise/systemManagement/groupAccount/index.vue

@@ -18,8 +18,8 @@
         >
           <template v-slot:title="{ item }">
             <div class="treeTitle font-size-15">
-              {{ dealEnterpriseName(item.anotherName || item.name) }}
-              <v-tooltip activator="parent" location="end">{{ dealEnterpriseName(item.anotherName || item.name) }}</v-tooltip>
+              {{ formatName(item.anotherName || item.name) }}
+              <v-tooltip activator="parent" location="end">{{ formatName(item.anotherName || item.name) }}</v-tooltip>
             </div>
           </template>
         </v-treeview>
@@ -110,7 +110,7 @@ import { updateGroupUserAccount } from '@/api/enterprise'
 import { getUserAvatar } from '@/utils/avatar'
 import { uploadFile } from '@/api/common'
 import { getToken } from '@/utils/auth'
-import { dealEnterpriseName } from '@/utils/getText';
+import { formatName } from '@/utils/getText';
 
 const { t } = useI18n()
 const showBadge = ref(false) // 性别设置甲方要求已去掉
@@ -126,7 +126,7 @@ const tableData = ref([])
 const treeData = ref([])
 const headers = [
   { title: t('login.username'), key: 'name', sortable: false },
-  { title: t('enterprise.userManagement.affiliatedEnterprise'), key: 'enterpriseAnotherName', sortable: false, value: item => dealEnterpriseName(item.enterpriseAnotherName || item.enterpriseName) },
+  { title: t('enterprise.userManagement.affiliatedEnterprise'), key: 'enterpriseAnotherName', sortable: false, value: item => formatName(item.enterpriseAnotherName || item.enterpriseName) },
   { title: t('enterprise.userManagement.post'), key: 'postName', sortable: false },
   { title: t('enterprise.userManagement.phone'), key: 'phone', sortable: false },
   { title: t('enterprise.userManagement.email'), key: 'email', sortable: false },
@@ -301,7 +301,8 @@ const handleUploadFile = async (e) => {
   const file = e.target.files[0]
   if (!file) return
 
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式文件')
 
   const reader = new FileReader()

+ 2 - 1
src/views/recruit/enterprise/tradingOrder/components/trading/transaction.vue

@@ -53,6 +53,7 @@ import { getInvoiceListPage, createInvoice, getInvoiceTitlePage } from '@/api/re
 import Snackbar from '@/plugins/snackbar'
 import { getBlob, saveAs } from '@/utils'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { formatName } from '@/utils/getText'
 
 // 支付渠道
 const channelData = ref([])
@@ -64,7 +65,7 @@ getPayChannelCode()
 
 const dataList = ref([])
 const headers = [
-  { title: '商品名称', key: 'spuName', sortable: false },
+  { title: '商品名称', key: 'spuName', sortable: false, value: item => formatName(item.spuName) },
   { title: '价格', key: 'price', sortable: false, value: item => item.price / 100 },
   { title: '是否已支付', key: 'payStatus', sortable: false, value: item => item.payStatus ? '已支付' : '未支付' },
   { title: '支付渠道', key: 'payChannelCode', value: item => channelData.value.find(e => e.value === item.payChannelCode)?.label, sortable: false },

+ 2 - 1
src/views/recruit/personal/PersonalCenter/components/communication.vue

@@ -18,7 +18,7 @@
         <div class="info-content">
           <div class="job-info">
             <div class="job-name cursor-pointer">
-              <span class="mr-3 info-name">{{ val.name }}</span>
+              <span class="mr-3 info-name">{{ formatName(val.name) }}</span>
               <span>[{{ val.areaName }}]</span>
             </div>
             <div class="job-other">
@@ -53,6 +53,7 @@
 defineOptions({ name: 'position-communication' })
 import { ref } from 'vue'
 import Empty from '@/components/Empty'
+import { formatName } from '@/utils/getText'
 
 const props = defineProps({
   tab: {

+ 3 - 3
src/views/recruit/personal/PersonalCenter/jobFeedback/components/interview/item.vue

@@ -30,7 +30,7 @@
         </div>
         <div class="job-info color-666">
           <div class="job-name ellipsis" style="max-width: 410px;">
-            <span class="mr-3" :class="{'cursor-pointer': val.job.status === '0', 'position-name': val.job.status === '0'}" @click="handleToPositionDetails(val)">{{ val.job.name }}</span>
+            <span class="mr-3" :class="{'cursor-pointer': val.job.status === '0', 'position-name': val.job.status === '0'}" @click="handleToPositionDetails(val)">{{ formatName(val.job.name) }}</span>
             <span v-if="!val.job.payFrom && !val.job.payTo">面议</span>
             <span v-else>{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}{{ val.job.payName ? '/' + val.job.payName : '' }}</span>
           </div>
@@ -39,7 +39,7 @@
               <v-img width="30" height="30" :src="val.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'"></v-img>
             </div>
             <div class="ellipsis" style="max-width: 400px;">
-              <span class="mx-2 enterprise-name" @click="handleToEnterprise(val)">{{ dealEnterpriseName(val.enterprise.anotherName || val.enterprise.name) }}</span>
+              <span class="mx-2 enterprise-name" @click="handleToEnterprise(val)">{{ formatName(val.enterprise.anotherName || val.enterprise.name) }}</span>
             [
               <span>{{ val.enterprise.industryName }}</span>
               <span>&nbsp;·&nbsp;{{ val.enterprise.scaleName }}</span>
@@ -60,7 +60,7 @@ import Snackbar from '@/plugins/snackbar'
 import Confirm from '@/plugins/confirm'
 import { getUserAvatar } from '@/utils/avatar'
 import { useRouter } from 'vue-router'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const { t } = useI18n()
 const emits = defineEmits(['refresh'])

+ 2 - 2
src/views/recruit/personal/PersonalCenter/jobFeedback/components/seenMe.vue

@@ -18,7 +18,7 @@
                 <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 class="company-info">
-                <h3 :class="{'default-active': item.active }" class="title1 cursor-pointer">{{ dealEnterpriseName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
+                <h3 :class="{'default-active': item.active }" class="title1 cursor-pointer">{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
                 <p class="mt-2">{{ item.enterprise.scaleName }}<span class="mx-2">|</span>{{ item.enterprise.industryName }}</p>
               </div>
             </div>
@@ -58,7 +58,7 @@ import Empty from '@/components/Empty'
 import { getUserAvatar } from '@/utils/avatar'
 import { useRouter } from 'vue-router'
 import { useUserStore } from '@/store/user'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const router = useRouter()
 const total = ref(0)

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 11 - 0
src/views/recruit/personal/PersonalCenter/resume/analysis/analyzeTestData.js


+ 2 - 1
src/views/recruit/personal/PersonalCenter/resume/analysis/components/avatar.vue

@@ -53,7 +53,8 @@ const isShowCopper = ref(false)
 const accept = ['jpg', 'png', 'jpeg']
 const handleUploadFile = async (e) => {
   const file = e.target.files[0]
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式')
   const reader = new FileReader()
   reader.readAsDataURL(file)

+ 2 - 1
src/views/recruit/personal/PersonalCenter/resume/online/analysis/avatar.vue

@@ -53,7 +53,8 @@ const isShowCopper = ref(false)
 const accept = ['jpg', 'png', 'jpeg']
 const handleUploadFile = async (e) => {
   const file = e.target.files[0]
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式')
   const reader = new FileReader()
   reader.readAsDataURL(file)

+ 2 - 1
src/views/recruit/personal/PersonalCenter/resume/online/components/basicInfo.vue

@@ -166,7 +166,8 @@ const isShowCopper = ref(false)
 const accept = ['jpg', 'png', 'jpeg']
 const handleUploadFile = async (e) => {
   const file = e.target.files[0]
-  const fileType = file.name.split('.')[1]
+  const arr = file.name.split('.')
+  const fileType = arr?.length ? arr[arr.length-1] : ''
   if (!accept.includes(fileType)) return Snackbar.warning('请上传图片格式')
   const reader = new FileReader()
   reader.readAsDataURL(file)

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

@@ -6,7 +6,7 @@
           <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 class="company-info">
-          <h3 :class="{'default-active': item.active }" style="width: 200px;">{{ dealEnterpriseName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
+          <h3 :class="{'default-active': item.active }" style="width: 200px;">{{ formatName(item.enterprise.anotherName || item.enterprise.name) }}</h3>
           <p>{{ item.enterprise.industryName }}</p>
         </div>
       </div>
@@ -14,7 +14,7 @@
       <div class="company-info-bottom">
         <div v-if="item?.job && Object.keys(item.job).length" class="job-hover" @click="handleClickPosition(item.job)">
           <div class="mb-1 d-flex">
-            <p :class="['mr-3', 'cursor-pointer', 'name']" :style="{'max-width': !item.job.payFrom && !item.job.payTo ? '200px' : '120px'}">{{ item.job.name }}</p>
+            <p :class="['mr-3', 'cursor-pointer', 'name']" :style="{'max-width': !item.job.payFrom && !item.job.payTo ? '200px' : '120px'}">{{ formatName(item.job.name) }}</p>
             <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>
           </div>
@@ -31,7 +31,7 @@
 </template>
 
 <script setup>
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 defineOptions({ name: 'company-item'})
 defineProps({

+ 2 - 1
src/views/recruit/personal/companyDetail/components/positions.vue

@@ -40,7 +40,7 @@
       >
         <div>
           <p v-if="val.job.name.includes('style')" :class="['name', {'default-active': val.active }]" v-html="val.job.name" @click="handlePosition(val)"></p>
-          <p v-else :class="['name', {'default-active': val.active }]" @click="handlePosition(val)">{{ val.job.name }}</p>
+          <p v-else :class="['name', {'default-active': val.active }]" @click="handlePosition(val)">{{ formatName(val.job.name) }}</p>
           <div style="line-height: 40px;">
             <span v-for="k in desc" :key="k.mdi">
               <span v-if="val.job[k.value] || (k.value === 'areaName' && !val.job.areaId)" class="mr-5">
@@ -94,6 +94,7 @@ import { getToken } from '@/utils/auth'
 import Snackbar from '@/plugins/snackbar'
 import { checkPersonBaseInfo } from '@/utils/check'
 import dialogExtend from '@/plugins/dialogExtend'
+import { formatName } from '@/utils/getText'
 
 const props = defineProps({
   info: {

+ 2 - 2
src/views/recruit/personal/companyDetail/index.vue

@@ -6,7 +6,7 @@
           <v-img width="60" height="60" :src="info.enterprise.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'"></v-img>
           <div class="ml-4">
             <div class="contact-name">
-              {{ dealEnterpriseName(info.enterprise.anotherName || info.enterprise.name) }}
+              {{ formatName(info.enterprise.anotherName || info.enterprise.name) }}
             </div>
             <div class="contact-info">
               {{ info.scaleName }}
@@ -81,7 +81,7 @@ import { useRoute, useRouter } from 'vue-router'
 import { getToken } from '@/utils/auth'
 import Snackbar from '@/plugins/snackbar'
 import loginPage from '@/views/common/loginDialog.vue'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const route = useRoute()
 const router = useRouter()

+ 3 - 2
src/views/recruit/personal/home/components/advertisement/dynamic/intercontinental.vue

@@ -41,9 +41,9 @@
       <div>
         <div class="position-item d-flex align-center" v-for="k in recruitPosition" :key="k.job.id">
           <div class="job-name">
-            {{ k.job.name }}
+            {{ formatName(k.job.name) }}
             <br>
-            {{ k.enterprise.name }}
+            {{ formatName(k.enterprise.name) }}
           </div>
           <div class="job-place">
             <div class="job-title">地点</div>
@@ -80,6 +80,7 @@ import { ref } from 'vue'
 import { getJobAdvertisedSearch } from '@/api/position'
 import { dealDictObjData } from '@/utils/position'
 import { timesTampChange } from '@/utils/date'
+import { formatName } from '@/utils/getText'
 
 const router = useRouter()
 const { id } = router.currentRoute.value.params

+ 3 - 2
src/views/recruit/personal/home/components/advertisement/dynamic/marriott.vue

@@ -28,9 +28,9 @@
       <div>
         <div class="position-item d-flex align-center" v-for="k in recruitPosition" :key="k.job.id">
           <div class="job-name">
-            {{ k.job.name }}
+            {{ formatName(k.job.name) }}
             <br>
-            {{ k.enterprise.name }}
+            {{ formatName(k.enterprise.name) }}
           </div>
           <div class="job-place">
             <div class="job-title">地点</div>
@@ -67,6 +67,7 @@ import { ref } from 'vue'
 import { getJobAdvertisedSearch } from '@/api/position'
 import { dealDictObjData } from '@/utils/position'
 import { timesTampChange } from '@/utils/date'
+import { formatName } from '@/utils/getText'
 
 const router = useRouter()
 const { id } = router.currentRoute.value.params

+ 7 - 6
src/views/recruit/personal/position/components/details.vue

@@ -3,13 +3,14 @@
     <div class="banner px-6" id="share" :class="{'default-width': defaultWidth}">
       <div class="banner-title d-flex justify-space-between">
         <div class="d-flex align-center">
-          <h1>{{ info.name }}</h1>
-          <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>
+          <h1>{{ formatName(info.name) }}</h1>
           <svg-icon v-if="info.hire" class="ml-5" name="pin" size="50"></svg-icon>
         </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">
@@ -64,7 +65,7 @@
                 <div class="ml-2">
                   <div class="contact-name">{{ info.contact.name }}</div>
                   <div class="contact-info">
-                    {{ dealEnterpriseName(info.enterprise.anotherName || info.enterprise.name) }}
+                    {{ formatName(info.enterprise.anotherName || info.enterprise.name) }}
                      <span v-if="info?.enterprise?.anotherName && info?.contact?.postNameCn">·</span>
                     {{ info.contact.postNameCn }}</div>
                 </div>
@@ -188,7 +189,7 @@ import { getToken } from '@/utils/auth'
 import { getUserAvatar } from '@/utils/avatar'
 import { checkPersonBaseInfo } from '@/utils/check'
 import dialogExtend from '@/plugins/dialogExtend'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const props = defineProps({
   defaultWidth: {

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

@@ -6,7 +6,7 @@
       <div v-else>
         <!-- 职位名称+薪资 -->
         <div class="d-flex justify-space-between mx-5">
-          <h2 class="JobName ellipsis">{{ 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>
@@ -24,7 +24,7 @@
           <v-avatar style="border: 2px solid #fff;" size="68">
             <img crossOrigin="anonymous" :src="info.enterprise.logoUrl" alt="" style="width: 68px; height: 68px;">
           </v-avatar>
-          <div class="enterprise-name ml-5 ellipsis" style="width: 65%;">{{ info.enterprise?.anotherName }}</div>
+          <div class="enterprise-name ml-5 ellipsis" style="width: 65%;">{{ formatName(info.enterprise?.anotherName || info.enterprise?.name) }}</div>
           <div style="flex: 1;" class="text-right enterprise-name">{{ info.areaName }}</div>
         </div>
         <div class="mx-5 mt-3">
@@ -69,6 +69,7 @@
 defineOptions({name: 'recruit-personal-shareJob-index'})
 import { ref } from 'vue'
 import { getJobAdvertisedShareQrcode, getJobAdvertisedShare } from '@/api/position'
+import { formatName } from '@/utils/getText'
 
 // 职位详情
 const props = defineProps({

+ 3 - 2
src/views/recruit/personal/position/components/rightRecommend.vue

@@ -3,12 +3,12 @@
     <h4 class="h4 mb-3">{{ $t('position.recommend') }}</h4>
     <div v-if="items.length">
       <div v-for="(item, index) in items" :key="index" class="mb-2 cursor-pointer" @click="handlePosition(item)">
-        <p class="recruit-name">{{ item.name }}</p>
+        <p class="recruit-name">{{ formatName(item.name) }}</p>
         <span v-if="!item.payFrom && !item.payTo" class="recruit-salary">面议</span>
         <span v-else class="recruit-salary">{{ item.payFrom ? item.payFrom + '-' : '' }}{{ item.payTo }}{{ item.payName ? '/' + item.payName : '' }}</span>
         <div :class="['enterprise', {'border-bottom-dashed': index !== items.length - 1}]" @click="handleEnterprise(item)">
           <v-img class="float-left" :src="item.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" :width="30" :height="30"></v-img>
-          <span class="float-left enterprise-name">{{ item.anotherName }}</span>
+          <span class="float-left enterprise-name">{{ formatName(item.anotherName) }}</span>
           <span class="float-right enterprise-address">{{ item.areaName }}</span>
         </div>
       </div>
@@ -22,6 +22,7 @@ defineOptions({name: 'retrieval-components-recommendedPositions'})
 import { ref } from 'vue'
 import { getPromotedPosition } from '@/api/position'
 import { dealDictArrayData } from '@/utils/position'
+import { formatName } from '@/utils/getText'
 
 const items = ref([])
 

+ 3 - 3
src/views/recruit/personal/recommend/components/positionList.vue

@@ -11,7 +11,7 @@
         <div class="job-info">
           <div class="sub-li-top">
             <div class="sub-li-info">
-              <p :class="['name', {'default-active': item.active }]">{{ item.name }}</p>
+              <p :class="['name', {'default-active': item.active }]">{{ formatName(item.name) }}</p>
               <svg-icon v-if="item.hire" name="pin" size="30"></svg-icon>
             </div>
           </div>
@@ -38,7 +38,7 @@
                 <v-img :src="item.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" />
               </v-avatar>
               <span class="names ml-2 font-size-14 ellipsis" style="max-width: 88%;">
-                {{ dealEnterpriseName(item.anotherName || item.name) }}
+                {{ formatName(item.anotherName || item.name) }}
                 <span class="color-999 font-size-13 ml-3">
                   <span>{{ item.industryName }}</span>
                   <span class="septal-line" v-if="item.industryName && item.scaleName"></span>
@@ -56,7 +56,7 @@
 <script setup>
 defineOptions({ name: 'position-card-item' })
 import { ref, watch } from 'vue'
-import { dealEnterpriseName } from '@/utils/getText'
+import { formatName } from '@/utils/getText'
 
 const emit = defineEmits([''])
 const props = defineProps({

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio