Browse Source

Merge branch 'master' of https://git.citupro.com/zhengnaiwen_citu/menduner-uniapp

lifanagju_citu 6 tháng trước cách đây
mục cha
commit
4fe2fefc7d

+ 13 - 0
api/integral.js

@@ -22,4 +22,17 @@ export const rewardEventTrackClick = (url) => {
       auth: true
     }
   })
+}
+
+// 推荐任务
+export const getTaskList = (params) => {
+  return request({
+    url: '/admin-api/menduner/reward/event-track/get/mark/task',
+    method: 'GET',
+    params,
+    custom: {
+      showLoading: false,
+      auth: false
+    }
+  })
 }

+ 149 - 85
api/resume.js

@@ -21,20 +21,30 @@ export const saveResumeBasicInfo = async (data) => {
 //   })
 // }
 
-// // 保存培训经历
-// export const saveResumeTrainExp = async (data) => {
-//   return await request.post({
-//     url: '/app-api/menduner/system/person/resume/train/exp/save',
-//     data
-//   })
-// }
+// 保存培训经历
+export const saveResumeTrainExp = async (data) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/train/exp/save',
+    method: 'POST',
+    data,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
-// // 删除培训经历
-// export const deleteResumeTrainExp = async (id) => {
-//   return await request.delete({
-//     url: '/app-api/menduner/system/person/resume/train/exp/remove?id=' + id
-//   })
-// }
+// 删除培训经历
+export const deleteResumeTrainExp = async (id) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/train/exp/remove?id=' + id,
+    method: 'DELETE',
+    custom: {
+      auth: true,
+      showLoading: false
+    }
+  })
+}
 
 // 获取培训经历
 export const getResumeTrainExp = async () => {
@@ -60,20 +70,30 @@ export const getResumeEduExp = async () => {
   })
 }
 
-// // 删除-教育经历
-// export const deleteResumeEduExp = async (id) => {
-//   return await request.delete({
-//     url: '/app-api/menduner/system/person/resume/edu/exp/remove?id=' + id
-//   })
-// }
+// 删除-教育经历
+export const deleteResumeEduExp = async (id) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/edu/exp/remove?id=' + id,
+    method: 'DELETE',
+    custom: {
+      auth: true,
+      showLoading: false
+    }
+  })
+}
 
-// // 保存-教育经历
-// export const saveResumeEduExp = async (data) => {
-//   return await request.post({
-//     url: '/app-api/menduner/system/person/resume/edu/exp/save',
-//     data
-//   })
-// }
+// 保存-教育经历
+export const saveResumeEduExp = async (data) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/edu/exp/save',
+    method: 'POST',
+    data,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
 // 获取-工作经历
 export const getResumeWorkExp = async () => {
@@ -87,20 +107,30 @@ export const getResumeWorkExp = async () => {
   })
 }
 
-// // 删除-工作经历
-// export const deleteResumeWorkExp = async (id) => {
-//   return await request.delete({
-//     url: '/app-api/menduner/system/person/resume/work/exp/remove?id=' + id
-//   })
-// }
+// 删除-工作经历
+export const deleteResumeWorkExp = async (id) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/work/exp/remove?id=' + id,
+    method: 'DELETE',
+    custom: {
+      auth: true,
+      showLoading: false
+    }
+  })
+}
 
-// // 保存-工作经历
-// export const saveResumeWorkExp = async (data) => {
-//   return await request.post({
-//     url: '/app-api/menduner/system/person/resume/work/exp/save',
-//     data
-//   })
-// }
+// 保存-工作经历
+export const saveResumeWorkExp = async (data) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/work/exp/save',
+    method: 'POST',
+    data,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
 // // 保存项目经历
 // export const saveResumeProjectExp = async (data) => {
@@ -129,12 +159,17 @@ export const getResumeWorkExp = async () => {
 //   })
 // }
 
-// // 获取-技能树形
-// export const getSkillTree = async () => {
-//   return await request.get({
-//     url: '/app-api/menduner/system/skill/get/tree'
-//   })
-// }
+// 获取-技能树形
+export const getSkillTree = async () => {
+  return request({
+    url: '/app-api/menduner/system/skill/get/tree',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
 // 获取-职业技能
 export const getResumePersonSkill = async () => {
@@ -148,20 +183,30 @@ export const getResumePersonSkill = async () => {
   })
 }
 
-// // 删除-职业技能
-// export const deleteResumePersonSkill = async (id) => {
-//   return await request.delete({
-//     url: '/app-api/menduner/system/person/resume/person/skill/remove?id=' + id
-//   })
-// }
+// 删除-职业技能
+export const deleteResumePersonSkill = async (id) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/person/skill/remove?id=' + id,
+    method: 'DELETE',
+    custom: {
+      auth: true,
+      showLoading: false
+    }
+  })
+}
 
-// // 保存-职业技能
-// export const saveResumePersonSkill = async (data) => {
-//   return await request.post({
-//     url: '/app-api/menduner/system/person/resume/person/skill/save',
-//     data
-//   })
-// }
+// 保存-职业技能
+export const saveResumePersonSkill = async (data) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/person/skill/save',
+    method: 'POST',
+    data,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
 // 保存求职意向
 export const saveResumeJobInterested = async (data) => {
@@ -176,13 +221,17 @@ export const saveResumeJobInterested = async (data) => {
   })
 }
 
-
-// // 删除求职意向
-// export const deleteResumeJobInterested = async (id) => {
-//   return await request.delete({
-//     url: '/app-api/menduner/system/person/resume/job/interested/remove?id=' + id
-//   })
-// }
+// 删除求职意向
+export const deleteResumeJobInterested = async (id) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/job/interested/remove?id=' + id,
+    method: 'DELETE',
+    custom: {
+      auth: true,
+      showLoading: false
+    }
+  })
+}
 
 // // 获取求职意向
 export const getResumeJobInterested = async () => {
@@ -197,28 +246,43 @@ export const getResumeJobInterested = async () => {
 }
 
 // // 根据专业名称模糊搜索
-// export const schoolMajorByName = async (params) => {
-//   return await request.get({
-//     url: '/app-api/menduner/system/major/search/by/name',
-//     params
-//   })
-// }
+export const schoolMajorByName = async (params) => {
+  return request({
+    url: '/app-api/menduner/system/major/search/by/name',
+    params,
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
-// // 根据学校名称模糊搜索
-// export const schoolSearchByName = async (params) => {
-//   return await request.get({
-//     url: '/app-api/menduner/system/school/search/by/name',
-//     params
-//   })
-// }
+// 根据学校名称模糊搜索
+export const schoolSearchByName = async (params) => {
+  return request({
+    url: '/app-api/menduner/system/school/search/by/name',
+    params,
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
-// // 根据企业名称模糊搜索
-// export const enterpriseSearchByName = async (params) => {
-//   return await request.get({
-//     url: '/app-api/menduner/system/enterprise/search/by/name',
-//     params
-//   })
-// }
+// 根据企业名称模糊搜索
+export const enterpriseSearchByName = async (params) => {
+  return request({
+    url: '/app-api/menduner/system/enterprise/search/by/name',
+    params,
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
 
 // // 保存附件
 // export const savePersonResumeCv = async (data) => {

+ 6 - 3
components/Navbar/index.vue

@@ -16,20 +16,23 @@ defineProps({
 
 <style scoped lang="scss">
 .navbar-box {
-  height: 64px;
+  height: 80px;
   width: 100%;
   position: relative;
   background: linear-gradient(90deg, #66BB6A 0, #64FFDA 100%);
   &-logo {
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
     width: 100px;
     height: 42px;
-    margin: 10px 0 0 10px;
+    margin-left: 10px;
   }
   &-title {
     position: absolute;
     top: 50%;
     left: 50%;
-    transform: translate(-50%, -50%);
+    transform: translate(-30%, 0);
     color: #fff;
   }
 }

+ 1 - 1
components/SwiperAd/index.vue

@@ -32,7 +32,7 @@ const props = defineProps({
   duration: { type: Number, default: 500 }, // 滑动动画时长
   strType: { type: Boolean, default: true }, // 数组类型或者对象类型
   imgUrlKey: { type: String, default: 'src' },
-  mode: { type: String, default: 'aspectFill' }, // 图片裁剪、缩放的模式。aspectFill保持纵横比缩放图片,只保证图片的短边能完全显示出来
+  mode: { type: String, default: 'scaleToFill' }, // 图片裁剪、缩放的模式。aspectFill保持纵横比缩放图片,只保证图片的短边能完全显示出来
   hide: { type: Boolean, default: false }, // 隐藏
   width: { type: String, default: '100%' },
   height: { type: String, default: '150px' },

+ 30 - 0
pages.json

@@ -68,6 +68,36 @@
 						"navigationBarTitleText": "个人优势"
 					}
 				},
+				{
+					"path": "resumeOnline/jobIntention",
+					"style": {
+						"navigationBarTitleText": "求职意向"
+					}
+				},
+				{
+					"path": "resumeOnline/educationExp",
+					"style": {
+						"navigationBarTitleText": "教育经历"
+					}
+				},
+				{
+					"path": "resumeOnline/workExperience",
+					"style": {
+						"navigationBarTitleText": "工作经验"
+					}
+				},
+				{
+					"path": "resumeOnline/trainingExperience",
+					"style": {
+						"navigationBarTitleText": "培训经历"
+					}
+				},
+				{
+					"path": "resumeOnline/vocationalSkills",
+					"style": {
+						"navigationBarTitleText": "职业技能"
+					}
+				},
 				{
 					"path": "resume/index",
 					"style": {

+ 1 - 1
pages/index/position.vue

@@ -98,7 +98,7 @@ const gridList = [
 const handleGrid = (e) => {
   uni.showToast({
     icon: 'none',
-    title: '建设中...,敬请期待'
+    title: '请前往网页版门墩儿查看'
   })
 }
 

+ 93 - 208
pages/index/welfare.vue

@@ -1,7 +1,7 @@
 <template>
   <layout-page>
 		<view class="box defaultBgc">
-      <scroll-view class="scrollBox" scroll-y="true" @scrolltolower="loadingMore">
+      <scroll-view class="scrollBox" scroll-y="true">
         <view class="content">
           <!-- 钱包 -->
           <view class="wallet">
@@ -27,10 +27,6 @@
                 <text>{{ balance.balance > 0 ? (balance?.balance / 100.0).toFixed(2) : 0 }}</text>
                 <text class="title">余额</text>
               </view>
-              <view class="wallet-content-coupon wallet-content-item" @tap="handleTo('coupon')">
-                <text>{{ myCoupon }}</text>
-                <text class="title">优惠券</text>
-              </view>
             </view>
           </view>
           <!-- 签到 -->
@@ -58,25 +54,36 @@
               </view>
             </view>
           </view>
-          <!-- 福利 -->
-          <view class="welfare">
-            <view
-              v-for="item in items"
-              :key="item.id"
-              class="item"
-              :class="{ disabled: !item.canTake }"
-              @tap="onGetCoupon(item.id, item.canTake)"
-            >
-              <view class="img">
-                <image
-                  src="/static/img/ticket.png"
-                  mode="scaleToFill"
-                />
-              </view>
-              <text>{{ item.name }}</text>
+          <!-- 积分规则、积分兑换 -->
+          <view class="ss-m-t-20">
+            <uni-section title="积分规则" type="line"  style="background-color: #fff;">
+              <uni-list>
+                <uni-list-item v-for="(k, i) in integralRules" :key="i" :showArrow="false">
+                  <template v-slot:header>
+                    <text class="ss-m-t-10">{{ k.title }}</text>
+                  </template>
+                  <template v-slot:footer>
+                    <view class="d-flex align-center" style="width: 130px; text-align: start; position: relative;">
+                      <image src="/static/svg/integral.svg" style="width: 30px; height: 30px;"></image>
+                      <view class="color-primary ss-m-l-10">{{ k.point }}</view>
+                      <uni-tag :inverted="true" :text="k.complete ? '已完成' : '未完成'" :type="k.complete ? 'success' : 'error'" style="position: absolute; right: 0;" />
+                    </view>
+                  </template>
+                </uni-list-item>
+              </uni-list>
+            </uni-section>
+            <view class="ss-m-t-20">
+              <uni-section title="积分兑换" type="line" style="background-color: #fff;">
+                <view class="goods" >
+                  <view class="goods-item" v-for="(item,index) in goodsList" :key="index" @tap.stop="handleClickGoods">
+                    <image :src="item.url" class="goods-item-img" mode="widthFix"></image>
+                    <view class="goods-item-name">{{ item.name }}</view>
+                    <view>消耗积分<text class="goods-item-price">{{ item.point }}</text></view>
+                  </view>
+                </view>
+              </uni-section>
             </view>
           </view>
-          <uni-load-more :status="more" />
         </view>
       </scroll-view>
 		</view>
@@ -92,13 +99,9 @@ import {
   createRewardSignInRecord,
   getAccountBalance,
   getUserAccount,
-  getDiyTemplateUsed,
-  getDiyTemplate,
-  getCouponTemplatePage,
-  takeCoupon,
-  getCouponPage
 } from '@/api/sign'
-import { onShow, onLoad } from '@dcloudio/uni-app'
+import { getTaskList } from '@/api/integral'
+import { onShow } from '@dcloudio/uni-app'
 import { userStore } from '@/store/user'
 import { showAuthModal } from '@/hooks/useModal'
 
@@ -106,6 +109,27 @@ const useUserStore = userStore()
 // 设置自定义tabBar选中值
 
 const SignItems = ref([])
+// 积分规则
+const integralRules = ref([])
+const getTask = async () => {
+  const { data } = await getTaskList({ mark: '推荐任务', type: 0 })
+  integralRules.value = data
+}
+getTask()
+// 商品列表
+const goodsList = [
+  { name: '房券-高端酒店房券', point: 12000, url: 'https://minio.menduner.com/dev/menduner/hotalRoomVoucher.png' },
+  { name: '门墩儿酒店英语学习年卡', point: 8000, url: 'https://minio.menduner.com/dev/menduner/englishCourses.png' },
+  { name: '红酒-经典年份葡萄酒', point: 5000, url: 'https://minio.menduner.com/dev/menduner/redWine.png' },
+  { name: '瑞幸咖啡券-瑞幸咖啡精致享受券', point: 2000, url: 'https://minio.menduner.com/dev/menduner/coffee.png' },
+  { name: '减压捏捏乐', point: 500, url: 'https://minio.menduner.com/dev/menduner/pinchMusic.png' }
+]
+const handleClickGoods = () => {
+  uni.showToast({
+    icon: 'none',
+    title: '请前往网页版门墩儿商城兑换'
+  })
+}
 
 // 连续签到天数
 const continuousDay = ref(0)
@@ -117,26 +141,8 @@ const todayNumber = ref()
 
 const balance = ref({})
 
-const pageInfo = ref({
-  pageNo: 1,
-  pageSize: 20
-})
-const total = ref(0)
-const items = ref([])
-const more = ref('more')
-
-const myCoupon = ref(0)
-
-// watch(() => useUserStore.isLogin, () => {
-//   if (useUserStore.isLogin) {
-//     init()
-//   }
-// })
-
 watch([() => useUserStore.refreshToken, () => useUserStore.isLogin], () => {
   if (useUserStore.isLogin) {
-    getMyCoupon()
-    initCoupon()
     getSummary()
     getBalance()
   }
@@ -157,11 +163,6 @@ function init () {
   getSummary()
   // 获取余额积分
   getBalance()
-  // 获取优惠券列表
-  initCoupon()
-  // 获取我的优惠券总数
-  getMyCoupon()
-
 }
 
 // 获取积分余额
@@ -222,94 +223,6 @@ async function handleSignIn () {
   }
 }
 
-
-// 获取优惠券分页
-async function getAllCouponPage () {
-  try {
-    const { data } = await getCouponTemplatePage({ ...pageInfo.value })
-    // console.log(data)
-    if (!data || !data.list || !data.list.length) {
-      if (pageInfo.value.pageNo === 1) {
-        more.value = 'more'
-        return
-      }
-      pageInfo.value.pageNo--
-      more.value = 'more'
-      return
-    }
-    items.value.push(...data.list)
-    total.value = +data.total
-    more.value = total.value === items.value.length ? 'noMore' : 'more'
-  } catch (error) {
-    if (pageInfo.value.pageNo === 1) {
-      more.value = 'more'
-      return
-    }
-    pageInfo.value.pageNo--
-    more.value = 'more'
-  }
-}
-
-async function getMyCoupon () {
-  const { data } = await getCouponPage({ pageNo:1, pageSize: 1, status: 1 })
-  if (data) {
-    myCoupon.value = +data.total
-  }
-}
-
-// 优惠券列表
-// async function handleGetTmpUsed () {
-//   try {
-//     const { data } = await getDiyTemplateUsed()
-//     if (!data?.home?.components) {
-//       uni.showToast({
-//         title: '暂无优惠券',
-//         icon: 'none',
-//         mask: true
-//       })
-//       return
-//     }
-//     const idsItem = data.home.components.find(e => e.id === 'CouponCard')
-//     if (!idsItem) {
-//       uni.showToast({
-//         title: '暂无优惠券',
-//         icon: 'none',
-//         mask: true
-//       })
-//       return
-//     }
-//     const ids = idsItem?.property?.couponIds
-//     if (!ids) {
-//       uni.showToast({
-//         title: '暂无优惠券',
-//         icon: 'none',
-//         mask: true
-//       })
-//       return
-//     }
-//     const { data: _data } = await getDiyTemplate(ids.join(','))
-//     items.value = _data
-//     more.value = 'noMore'
-//   } catch (error) {
-    
-//   }
-// }
-
-async function loadingMore () {
-  if (more.value === 'noMore') {
-    return
-  }
-  more.value = 'loading'
-  pageInfo.value.pageNo++
-  getAllCouponPage()
-}
-
-function initCoupon () {
-  pageInfo.value.pageNo = 1
-  items.value = []
-  getAllCouponPage()
-}
-
 function handleLogin () {
   if (!useUserStore.isLogin) {
 		showAuthModal()
@@ -323,38 +236,6 @@ function toInfo () {
 	})
 }
 
-async function onGetCoupon(id, canTake) {
-  if (!canTake) {
-    return
-  }
-  uni.showLoading({
-    title: '领取中'
-  })
-  try {
-    const {
-			code,
-			msg
-		} = await takeCoupon(id)
-    if (code !== 0) {
-      uni.showToast({
-        title: msg,
-        icon: 'none'
-      })
-      return
-    }
-    uni.showToast({
-      title: '领取成功',
-      icon: 'success'
-    })
-    getMyCoupon()
-    initCoupon()
-  } catch (error) {
-    
-  } finally {
-    uni.hideLoading()
-  }
-}
-
 function handleTo (page) {
   if (!useUserStore.isLogin) {
 		showAuthModal()
@@ -367,11 +248,10 @@ function handleTo (page) {
 </script>
 
 <style scoped lang="scss">
-$px: 20rpx;
 .box {
   overflow: hidden;
   height: 100vh;
-  padding: $px 0 0 0;
+  padding: 20rpx 0 0 0;
   box-sizing: border-box;
   .scrollBox{
     height: 100%;
@@ -384,14 +264,12 @@ $px: 20rpx;
     box-sizing: border-box;
   }
   .wallet {
-    // padding: 0 $px;
     box-sizing: border-box;
     height: 200rpx;
     margin-bottom: 20rpx;
     &-content {
       display: flex;
       height: 100%;
-      // border: 2rpx solid #E5E5E5;
       border-radius: 10rpx;
       background: #FFF;
       
@@ -430,7 +308,7 @@ $px: 20rpx;
         }
       }
       &-item {
-        width: 16.6%;
+        width: 25%;
         display: flex;
         flex-direction: column;
         align-items: center;
@@ -447,13 +325,13 @@ $px: 20rpx;
     }
   }
   .signIn {
-    // padding: 0 $px;
+    // padding: 0 20rpx;
     box-sizing: border-box;
     &-content {
       border-radius: 10rpx;
       background: #FFF;
       &-items {
-        padding: 20rpx $px;
+        padding: 20rpx 20rpx;
         display: flex;
         height: 220rpx;
         box-sizing: border-box;
@@ -471,6 +349,7 @@ $px: 20rpx;
             background: #f2f4f7;
             border-radius: 10rpx;
             &.active {
+              color: #fff;
               background: rgba(16,137,123, .66);
             }
             .text {
@@ -506,45 +385,51 @@ $px: 20rpx;
           background-color: #00897B;
           color: #FFF;
           &.disabled {
-            background-color: #a7a7a7 !important;
+            // background-color: #a7a7a7 !important;
+            opacity: .5;
           }
         }
       }
       
     }
   }
-  .welfare {
-    display: grid;
-    grid-template-columns: repeat(2, 1fr);
-    grid-gap: 20rpx;
-    padding: 20rpx $px;
-    .item {
-      text-align: center;
-      background: #FFF;
-      padding: $px;
-      font-size: .85em;
-      &.disabled {
-        position: relative;
-        &::after {
-          content: '已领取';
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          position: absolute;
-          top: 0;
-          left: 0;
-          width: 100%;
-          height: 100%;
-          background: rgba(255,255,255,.75);
-        }
+  .goods {
+    padding: 0 15upx;
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: space-between;
+    &-item {
+      background: #FFFFFF;
+      width: 48%;
+      margin: 10upx 0;
+      box-sizing: border-box;
+      &-img {
+        width: 100%;
+        height: 250upx;
+        display: block;
+        margin: auto;
       }
-      .img {
-        image {
-          width: 128rpx;
-          height: 128rpx;
-        }
+      &-price {
+        padding-top: 10upx;
+        color: #00897B;
+        font-size: 32upx;
+      }
+      &-name {
+        width: 100%;
+        white-space: nowrap;
+        font-size: 28upx;
+        line-height: 50upx;
+        padding-bottom: 10upx;
+        padding-top: 10upx;
+        overflow:hidden; 
+        text-overflow:ellipsis;
+        -webkit-box-orient:vertical;
+        -webkit-line-clamp:2; 
       }
     }
   }
 }
+:deep(.uni-section .uni-section-header__decoration) {
+  background-color: #00897B !important;
+}
 </style>

+ 1 - 1
pagesA/resumeOnline/dict.js

@@ -78,7 +78,7 @@ export const dealJobData = (list) => {
       if (item.isArray) {
         if (e[item.key] && e[item.key].length) {
           const result = e[item.key].map(val => {
-            return obj = dictObj[item.value].find(i => i[item.itemKey] === val)
+            return obj = dictObj[item.value].find(i => Number(i[item.itemKey]) === Number(val))
           })
           e[item.label] = result && result.length ? result.filter(Boolean) : []
         }

+ 166 - 2
pagesA/resumeOnline/educationExp.vue

@@ -1,9 +1,173 @@
-<!--  -->
+<!-- 教育经历 -->
 <template>
-  <view>教育经历</view>
+  <view class="ss-m-x-30 ss-m-y-30">
+    <uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="90px">
+      <uni-forms-item label="学校名称" name="schoolName" required>
+				<uni-combox :candidates="schoolData" placeholder="学校名称" v-model="formData.schoolName" @input="handleSearchSchool"></uni-combox>
+			</uni-forms-item>
+      <uni-forms-item label="所学专业" name="major" required>
+				<uni-combox :candidates="majorData" placeholder="所学专业" v-model="formData.major" @input="handleSearchMajor"></uni-combox>
+			</uni-forms-item>
+      <uni-forms-item label="学历" name="educationType" required>
+        <uni-data-select v-model="formData.educationType" :localdata="searchData.eduType"></uni-data-select>
+			</uni-forms-item>
+      <uni-forms-item label="学制类型" name="educationSystemType" required>
+        <uni-data-select v-model="formData.educationSystemType" :localdata="searchData.eduSystemType"></uni-data-select>
+			</uni-forms-item>
+      <uni-forms-item label="开始时间" name="startTime" required>
+				<picker mode="date" :value="formData.startTime" fields="month" :end="endDate" @change="e => formData.startTime = e.detail.value">
+					<view class="uni-input ss-m-t-20">{{ formData.startTime }}</view>
+				</picker>
+			</uni-forms-item>
+      <uni-forms-item label="结束时间" name="endTime" required>
+				<picker mode="date" :value="formData.endTime" fields="month" :end="endDate" @change="e => formData.endTime = e.detail.value">
+					<view class="uni-input ss-m-t-20">{{ formData.endTime }}</view>
+				</picker>
+			</uni-forms-item>
+      <uni-forms-item label="在校经历" name="content">
+				<uni-easyinput type="textarea" v-model="formData.content" autoHeight  placeholder="请输入内容"></uni-easyinput>
+			</uni-forms-item>
+    </uni-forms>
+    <view class="f-horizon-center">
+      <button v-if="editId" size="default" class="delete-button commonBtnStyle" @click="handleDelete">删 除</button>
+      <button size="default" :class="{'save-button': editId, 'commonBtnStyle': editId, 'send-button': !editId}"  @click="submit">保 存</button>
+    </view>
+  </view>
 </template>
 
 <script setup>
+import { ref, unref } from 'vue'
+import { dictObj } from '@/utils/position.js'
+import { convertYearMonthToTimestamp, timesTampChange } from '@/utils/date.js'
+import { schoolSearchByName, schoolMajorByName, saveResumeEduExp, getResumeEduExp, deleteResumeEduExp } from '@/api/resume.js'
+import { onLoad } from '@dcloudio/uni-app'
+import { cloneDeep } from 'lodash-es'
+
+let formData = ref({
+  startTime: '2014-01',
+  endTime: '2018-01'
+})
+const editId = ref(null)
+const majorData = ref([])
+const schoolData = ref([])
+const form = ref()
+const date = new Date()
+const endDate = date.getFullYear() + '-' + (date.getMonth() + 1) // 不可选时间
+const searchData = ref({
+  school: [],
+  major: [],
+  eduType: dictObj.edu.map(e => ({ text: e.label, value: e.value})),
+  eduSystemType: dictObj.eduSystemType.map(e => ({ text: e.label, value: e.value}))
+})
+
+const rules = {
+	schoolName:{
+		rules: [{required: true, errorMessage: '请输入学校名称' }]
+	},
+	major:{
+		rules: [{required: true, errorMessage: '请输入所学专业' }]
+	},
+	educationType:{
+		rules: [{required: true, errorMessage: '请选择学历' }]
+	},
+	educationSystemType:{
+		rules: [{required: true, errorMessage: '请选择学制类型' }]
+	},
+	startTime:{
+		rules: [{required: true, errorMessage: '请选择开始时间' }]
+	},
+	endTime:{
+		rules: [{required: true, errorMessage: '请选择结束时间' }]
+	}
+}
+const getEduExp = async (id) => {
+  const { data } = await getResumeEduExp()
+  if (!data || !data.length) {
+    return
+  }
+  const obj = data.find(e => e.id == id)
+  formData.value = cloneDeep(obj)
+  formData.value.startTime = timesTampChange(obj.startTime, 'Y-M')
+  formData.value.endTime = timesTampChange(obj.endTime, 'Y-M')
+  handleSearchSchool(obj.schoolName)
+  handleSearchMajor(obj.major)
+}
+
+onLoad((options) => {
+  if (options.id) {
+    editId.value = options.id
+    getEduExp(options.id)
+  }
+})
+
+// 学校搜索
+const handleSearchSchool = (e) => {
+  if (!e) return schoolData.value = []
+  schoolSearchByName({ name: e }).then(res => {
+    searchData.value.school = res.data
+    schoolData.value = res.data && res.data?.length ? res.data.map(e => e.value) : []
+  })
+}
+
+// 专业搜索
+const handleSearchMajor = (e) => {
+  if (!e) return majorData.value = []
+  schoolMajorByName({ name: e }).then(res => {
+    searchData.value.major = res.data
+    majorData.value = res.data && res.data?.length ? res.data.map(e => e.nameCn) : []
+  })
+}
+
+// 保存
+const submit = async () => {
+  const valid = await unref(form).validate()
+  if (!valid) return
+  formData.value.majorId = searchData.value.major.find(e => e.nameCn === formData.value.major)?.id
+  formData.value.schoolId = searchData.value.school.find(e => e.value === formData.value.schoolName)?.key
+  try {
+    formData.value.startTime = convertYearMonthToTimestamp(formData.value.startTime)
+    formData.value.endTime = convertYearMonthToTimestamp(formData.value.endTime)
+    await saveResumeEduExp(formData.value)
+    uni.showToast({
+			icon: 'success',
+			title: '保存成功'
+		})
+		setTimeout(() => {
+      editId.value = null
+      uni.navigateBack({
+        delta: 1
+      })
+    }, 1000)
+  } catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
+
+// 删除
+const handleDelete = async () => {
+	try {
+		await deleteResumeEduExp(editId.value)
+		uni.showToast({
+			icon: 'success',
+			title: '删除成功'
+		})
+		setTimeout(() => {
+			editId.value = null
+			uni.navigateBack({
+				delta: 1
+			})
+		}, 1000)
+	} catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
 </script>
+
 <style lang="scss" scoped>
 </style>

+ 36 - 41
pagesA/resumeOnline/index.vue

@@ -1,5 +1,6 @@
 <template>
   <layout-page>
+    <!-- 基本信息 -->
     <view class="baseInfo borderLine" @tap="handleTo('baseInfoEdit')">
       <view>
         <view class="baseInfo-name">
@@ -30,6 +31,7 @@
         />
       </view>
     </view>
+    <!-- 个人画像 -->
     <view class="characteristic borderLine">
       <view class="titleBox">
         <text class="title">个人画像</text>
@@ -51,6 +53,7 @@
         </view>
       </view>
     </view>
+    <!-- 个人优势 -->
     <view class="advantage borderLine">
       <view class="titleBox">
         <text class="title">个人优势</text>
@@ -64,6 +67,7 @@
       </view>
       <view class="ellipsis-2 text px-20">{{ baseInfo.advantage ? baseInfo.advantage : '请填写您的个人优势...' }}</view>
     </view>
+    <!-- 求职意向 -->
     <view class="intention borderLine">
       <view class="titleBox">
         <text class="title">求职意向</text>
@@ -72,7 +76,7 @@
           color="#666"
           custom-prefix="iconfont"
           size="18"
-          @tap="popupOpen('jobIntention')"
+          @tap="handleTo('jobIntention')"
         ></uni-icons>
       </view>
       <view class="content">
@@ -82,7 +86,9 @@
             v-for="int in intention"
             :key="int.id"
             :border="false"
+            :clickable="true"
             showArrow
+            @click="handleTo('jobIntention', int.id)"
           >
             <template v-slot:body>
               <view class="item">
@@ -91,7 +97,7 @@
                   <text class="mr-20">{{ int.position}}</text>
                   <text>{{ int.payFrom }} {{ int.payFrom  && int.payTo ? '-' : ''}} {{ int.payTo}}</text>
                 </view>
-                <view>{{ int.workArea }}</view>
+                <view>{{ int.interestedArea && int.interestedArea.length ? int.workArea + ',' + int.interestedArea.map(e => e.name).join(',') : int.workArea }}</view>
                 <view class="item-tags">
                   <view v-for="industry in int.industry" :key="industry.id" class="tag">{{ industry.nameCn }}</view>
                 </view>
@@ -101,6 +107,7 @@
         </uni-list>
       </view>
     </view>
+    <!-- 教育经历 -->
     <view class="educationExp borderLine">
       <view class="titleBox">
         <text class="title">教育经历</text>
@@ -109,6 +116,7 @@
           color="#666"
           custom-prefix="iconfont"
           size="18"
+          @tap="handleTo('educationExp')"
         ></uni-icons>
       </view>
       <view class="content">
@@ -119,13 +127,16 @@
             :key="education.id"
             showArrow
             :border="false"
+            :clickable="true"
             :title="education.schoolName"
             :note="`${education.major} ${education.educationTypeText}`"
             :rightText="education.time"
+            @click="handleTo('educationExp', education.id)"
           />
         </uni-list>
       </view>
     </view>
+    <!-- 工作经历 -->
     <view class="workExp borderLine">
       <view class="titleBox">
         <text class="title">工作经历</text>
@@ -134,6 +145,7 @@
           color="#666"
           custom-prefix="iconfont"
           size="18"
+          @tap="handleTo('workExperience')"
         ></uni-icons>
       </view>
       <view class="content">
@@ -141,6 +153,7 @@
           v-for="work in workExp"
           :key="work.id"
           class="content-item"
+          @tap="handleTo('workExperience', work.id)"
         >
           <view class="content-title">
             <view class="name">{{ work.enterpriseName }}</view>
@@ -159,6 +172,7 @@
         </view>
       </view>
     </view>
+    <!-- 培训经历 -->
     <view class="workExp trainExp borderLine">
       <view class="titleBox">
         <text class="title">培训经历</text>
@@ -167,6 +181,7 @@
           color="#666"
           custom-prefix="iconfont"
           size="18"
+          @tap.stop="handleTo('trainingExperience')"
         ></uni-icons>
       </view>
       <view class="content">
@@ -174,6 +189,7 @@
           v-for="train in trainExp"
           :key="train.id"
           class="content-item"
+          @tap.stop="handleTo('trainingExperience', train.id)"
         >
           <view class="content-title">
             <view class="name">{{ train.orgName }}</view>
@@ -192,6 +208,7 @@
         </view>
       </view>
     </view>
+    <!-- 职业技能 -->
     <view class="characteristic">
       <view class="titleBox">
         <text class="title">职业技能</text>
@@ -200,6 +217,7 @@
           color="#666"
           custom-prefix="iconfont"
           size="18"
+          @tap.stop="handleTo('vocationalSkills')"
         ></uni-icons>
       </view>
       <view class="tags">
@@ -212,19 +230,6 @@
         </view>
       </view>
     </view>
-    <!-- 底部弹出 Popup -->
-    <uni-popup ref="popupRef" type="bottom" :mask-click="true" background-color="#fff">
-      <view class="popupBox">
-        <view class="handleBtnBox borderLine">
-          <view class="save" @click="null"></view>
-          <view class="close" @click="popupRef.close()"><uni-icons type="closeempty" size="18"></uni-icons></view>
-          <!-- <view class="save" @click="null">保存</view> -->
-        </view>
-        <view class="popupContent">
-          <jobIntention></jobIntention>
-        </view>
-      </view>
-    </uni-popup>
   </layout-page>
 </template>
 
@@ -244,7 +249,6 @@ import { userStore } from '@/store/user'
 import { dealJobData } from './dict'
 import layoutPage from '@/layout'
 import { onShow } from '@dcloudio/uni-app'
-import jobIntention from './jobIntention.vue'
 import { getUserAvatar } from '@/utils/avatar'
 
 const useUserStore = userStore()
@@ -256,8 +260,8 @@ const workExp = ref([])
 const trainExp = ref([])
 const skillExp = ref([])
 
-function handleTo (str) {
-  uni.navigateTo({ url: `/pagesA/resumeOnline/${str}` })
+function handleTo (str, id) {
+  uni.navigateTo({ url: id ? `/pagesA/resumeOnline/${str}?id=${id}` : `/pagesA/resumeOnline/${str}` })
 }
 
 // 获取基础信息
@@ -298,7 +302,7 @@ async function getEduExp () {
     return {
       ...e,
       educationTypeText: item?.label ?? '',
-      time: `${timesTampChange(e.startTime ,'Y')}-${timesTampChange(e.endTime ,'Y')} `
+      time: `${timesTampChange(e.startTime ,'Y-M')}-${timesTampChange(e.endTime ,'Y-M')} `
     }
   })
   // 完成度展示
@@ -318,7 +322,7 @@ async function getWorkExp () {
   workExp.value = data.map(e => {
     return {
       ...e,
-      time: `${timesTampChange(e.startTime ,'Y')}-${e.endTime ? timesTampChange(e.endTime ,'Y') : '至今'} `
+      time: `${timesTampChange(e.startTime ,'Y-M')}-${e.endTime ? timesTampChange(e.endTime ,'Y-M') : '至今'} `
     }
   })
 }
@@ -334,7 +338,7 @@ async function getTrainExpData () {
   trainExp.value = data.map(e => {
     return {
       ...e,
-      time: `${timesTampChange(e.startTime ,'Y')}-${e.endTime ? timesTampChange(e.endTime ,'Y') : '至今'} `
+      time: `${timesTampChange(e.startTime ,'Y-M')}-${e.endTime ? timesTampChange(e.endTime ,'Y-M') : '至今'} `
     }
   })
 }
@@ -367,28 +371,19 @@ async function getSkillExpData () {
   })
 }
 
-const popupRef = ref()
-const popupOpen = (type) => {
-  popupRef.value.open()
-}
-
-// 求职状态字典
-// getJobStatus()
-// 获取基础信息
-getBaseInfo()
-// 获取求职意向
-getJobInterested()
-// 获取教育经历
-getEduExp()
-// 获取工作经验
-getWorkExp()
-// 培训经历
-getTrainExpData()
-// 职业技能
-getSkillExpData()
-
 onShow(() => {
+  // 获取基础信息
   getBaseInfo()
+  // 获取求职意向
+  getJobInterested()
+  // 获取教育经历
+  getEduExp()
+  // 获取工作经验
+  getWorkExp()
+  // 培训经历
+  getTrainExpData()
+  // 职业技能
+  getSkillExpData()
 })
 </script>
 

+ 88 - 16
pagesA/resumeOnline/jobIntention.vue

@@ -1,51 +1,122 @@
 <!--  -->
 <template>
-  <view>
-    <uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="100%" label-align="left" label-position="top">
-      <uni-forms-item label="期望岗位" name="positionId">
+  <view class="ss-m-x-30 ss-m-y-30">
+    <uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="90px">
+      <uni-forms-item label="期望岗位" name="positionId" required>
 				<uni-data-picker popup-title="请选择期望岗位" v-model="formData.positionId" :localdata="dictObj?.positionTreeData || []" :clear-icon="false" :map="{ text: 'nameCn', value: 'id'}"></uni-data-picker>
 			</uni-forms-item>
-      <uni-forms-item label="期望行业" name="industryIdList">
+      <uni-forms-item label="期望行业" name="industryIdList" required>
 				<uni-data-picker popup-title="请选择期望行业" v-model="formData.industryIdList" :localdata="dictObj?.industryTreeData || []" :clear-icon="false" :map="{ text: 'nameCn', value: 'id'}"></uni-data-picker>
 			</uni-forms-item>
-      <uni-forms-item label="期望薪资(最低要求)" name="payFrom">
-        <uni-number-box v-model="formData.payFrom" :min="1" :max="999999999" :step="100" :width="150" @change="payChange"></uni-number-box>
+      <uni-forms-item label="最低薪资" name="payFrom" required>
+        <uni-number-box v-model="formData.payFrom" :min="1" :max="999999999" :step="1000" :width="150" @change="payChange"></uni-number-box>
 			</uni-forms-item>
-      <uni-forms-item label="期望薪资(最高要求)" name="payTo">
-        <uni-number-box v-model="formData.payTo" :min="payToMin" :max="999999999" :step="100" :width="150"></uni-number-box>
+      <uni-forms-item label="最高薪资" name="payTo" required>
+        <uni-number-box v-model="formData.payTo" :min="payToMin" :max="999999999" :step="1000" :width="150"></uni-number-box>
 			</uni-forms-item>
-      <uni-forms-item label="求职类型" name="jobType">
+      <uni-forms-item label="求职类型" name="jobType" required>
 				<uni-data-picker popup-title="请选择求职类型" v-model="formData.jobType" :localdata="dictObj?.jobType || []" :clear-icon="false" :map="{ text: 'label', value: 'value'}"></uni-data-picker>
 			</uni-forms-item>
-      <uni-forms-item label="工作城市" name="workAreaProvinceId">
-				<uni-data-picker popup-title="请选择工作城市" v-model="formData.workAreaProvinceId" :localdata="dictObj?.areaTreeData || []" :clear-icon="false" :map="{ text: 'name', value: 'id'}"></uni-data-picker>
+      <uni-forms-item label="工作城市" name="workAreaId" required>
+				<uni-data-picker popup-title="请选择工作城市" v-model="formData.workAreaId" :localdata="dictObj?.areaTreeData || []" :clear-icon="false" :map="{ text: 'name', value: 'id'}"></uni-data-picker>
 			</uni-forms-item>
       <uni-forms-item label="其它感兴趣的城市" name="interestedAreaIdList">
 				<uni-data-picker popup-title="其它感兴趣的城市" v-model="formData.interestedAreaIdList" :localdata="dictObj?.areaTreeData || []" :clear-icon="false" :map="{ text: 'name', value: 'id'}"></uni-data-picker>
 			</uni-forms-item>
     </uni-forms>
     <view class="f-horizon-center">
-      <button type="primary" size="default" class="send-button"  @click="submit">确 认</button>
+      <button v-if="editId" size="default" class="delete-button commonBtnStyle" @click="handleDelete">删 除</button>
+      <button size="default" :class="{'save-button': editId, 'commonBtnStyle': editId, 'send-button': !editId}"  @click="submit">保 存</button>
     </view>
-    <!-- <view style="text-align: center; font-size: 13px; color: gray;">已加载全部</view> -->
   </view>
 </template>
 
 <script setup>
-import { ref, reactive } from 'vue'
+import { ref, unref } from 'vue'
 import { dictObj } from '@/utils/position.js'
+import { saveResumeJobInterested, getResumeJobInterested, deleteResumeJobInterested } from '@/api/resume.js'
+import { onLoad } from '@dcloudio/uni-app'
+import { cloneDeep } from 'lodash-es'
 
-const formData = reactive({ positionId: '', payFrom: 0, payTo: 0 })
+let formData = ref({ positionId: '', payFrom: 0, payTo: 0 })
 const form = ref()
+const editId = ref(null)
+
+// 获取求职意向
+async function getJobInterested (id) {
+  const { data } = await getResumeJobInterested()
+  if (!data || !data.length) {
+    return
+  }
+  const obj = data.find(k => k.id === id)
+	formData.value = cloneDeep(obj)
+	formData.value.industryIdList = obj.industryIdList.length ? obj.industryIdList[0] : ''
+	formData.value.interestedAreaIdList = obj.interestedAreaIdList.length ? Number(obj.interestedAreaIdList[0]) : ''
+}
+
+onLoad((options) => {
+	if (options.id) {
+		editId.value = options.id
+		getJobInterested(options.id)
+	}
+})
+
+// 提交
 const submit = async () => {
   const valid = await unref(form).validate()
   if (!valid) return
+	// 后续做多选
+	formData.value.industryIdList = [formData.value.industryIdList]
+	formData.value.interestedAreaIdList = [formData.value.interestedAreaIdList]
+	try {
+		await saveResumeJobInterested(formData.value)
+		uni.showToast({
+			icon: 'success',
+			title: '保存成功'
+		})
+		setTimeout(() => {
+			editId.value = null
+			uni.navigateBack({
+				delta: 1
+			})
+		}, 1000)
+	} catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
+
+// 删除
+const handleDelete = async () => {
+	try {
+		await deleteResumeJobInterested(editId.value)
+		uni.showToast({
+			icon: 'success',
+			title: '删除成功'
+		})
+		setTimeout(() => {
+			editId.value = null
+			uni.navigateBack({
+				delta: 1
+			})
+		}, 1000)
+	} catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
 }
 
 const rules = {
 	positionId:{
 		rules: [{required: true, errorMessage: '请选择期望岗位' }]
 	},
+	industryIdList:{
+		rules: [{required: true, errorMessage: '请选择期望行业' }]
+	},
 	payFrom:{
 		rules: [{required: true, errorMessage: '请输入薪资最低要求' }]
 	},
@@ -63,9 +134,10 @@ const rules = {
 const payToMin = ref(1)
 const payChange = (val) => {
   payToMin.value = val
-  if (val > formData.payTo) formData.payTo = val
+  if (val > formData.value.payTo) formData.value.payTo = val
 }
 
 </script>
+
 <style lang="scss" scoped>
 </style>

+ 1 - 1
pagesA/resumeOnline/portrait.vue

@@ -67,7 +67,7 @@ const select = ref([])
 // 获取基础信息
 function getBaseInfo () {
   const baseInfo = useUserStore.baseInfo
-  select.value = baseInfo?.tagList?.length ? tagList : []
+  select.value = baseInfo.tagList &&  baseInfo.tagList?.length ? baseInfo.tagList : []
 }
 
 // 获取基础信息

+ 123 - 2
pagesA/resumeOnline/trainingExperience.vue

@@ -1,9 +1,130 @@
-<!--  -->
+<!-- 培训经历 -->
 <template>
-  <view>培训经历</view>
+  <view class="ss-m-x-30 ss-m-y-30">
+    <uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="90px">
+      <uni-forms-item label="培训中心" name="orgName" required>
+				<uni-easyinput type="text" v-model="formData.orgName" placeholder="请输入内容"></uni-easyinput>
+			</uni-forms-item>
+      <uni-forms-item label="培训课程" name="course" required>
+				<uni-easyinput type="text" v-model="formData.course" placeholder="请输入内容"></uni-easyinput>
+			</uni-forms-item>
+      <uni-forms-item label="开始时间" name="startTime" required>
+				<picker mode="date" :value="formData.startTime" fields="month" :end="endDate" @change="e => formData.startTime = e.detail.value">
+					<view class="uni-input ss-m-t-20">{{ formData.startTime }}</view>
+				</picker>
+			</uni-forms-item>
+      <uni-forms-item label="结束时间" name="endTime" required>
+				<picker mode="date" :value="formData.endTime" fields="month" :end="endDate" @change="e => formData.endTime = e.detail.value">
+          <view class="uni-input ss-m-t-20">{{ formData.endTime }}</view>
+        </picker>
+			</uni-forms-item>
+      <uni-forms-item label="培训描述" name="content">
+				<uni-easyinput type="textarea" v-model="formData.content" autoHeight  placeholder="请输入内容"></uni-easyinput>
+			</uni-forms-item>
+    </uni-forms>
+    <view class="f-horizon-center">
+      <button v-if="editId" size="default" class="delete-button commonBtnStyle" @click="handleDelete">删 除</button>
+      <button size="default" :class="{'save-button': editId, 'commonBtnStyle': editId, 'send-button': !editId}"  @click="submit">保 存</button>
+    </view>
+  </view>
 </template>
 
 <script setup>
+import { ref, unref } from 'vue'
+import { convertYearMonthToTimestamp, timesTampChange } from '@/utils/date.js'
+import { saveResumeTrainExp, deleteResumeTrainExp, getResumeTrainExp } from '@/api/resume.js'
+import { onLoad } from '@dcloudio/uni-app'
+import { cloneDeep } from 'lodash-es'
+
+let formData = ref({
+  startTime: '2014-01',
+  endTime: '2018-01'
+})
+const editId = ref(null)
+const form = ref()
+const date = new Date()
+const endDate = date.getFullYear() + '-' + (date.getMonth() + 1) // 不可选时间
+
+const rules = {
+	orgName:{
+		rules: [{required: true, errorMessage: '请输入培训中心' }]
+	},
+	course:{
+		rules: [{required: true, errorMessage: '请输入培训课程' }]
+	},
+	startTime:{
+		rules: [{required: true, errorMessage: '请选择培训开始时间' }]
+	},
+  endTime:{
+		rules: [{required: true, errorMessage: '请选择培训结束时间' }]
+	}
+}
+const getTTrainExp = async (id) => {
+  const { data } = await getResumeTrainExp()
+  if (!data || !data.length) {
+    return
+  }
+  const obj = data.find(e => e.id == id)
+  formData.value = cloneDeep(obj)
+  formData.value.startTime = timesTampChange(obj.startTime, 'Y-M')
+  formData.value.endTime = timesTampChange(obj.endTime, 'Y-M')
+}
+
+onLoad((options) => {
+  if (options.id) {
+    editId.value = options.id
+    getTTrainExp(options.id)
+  }
+})
+
+// 保存
+const submit = async () => {
+  const valid = await unref(form).validate()
+  if (!valid) return
+  formData.value.startTime = convertYearMonthToTimestamp(formData.value.startTime)
+  formData.value.endTime = convertYearMonthToTimestamp(formData.value.endTime)
+  try {
+    await saveResumeTrainExp(formData.value)
+    uni.showToast({
+			icon: 'success',
+			title: '保存成功'
+		})
+		setTimeout(() => {
+      editId.value = null
+      uni.navigateBack({
+        delta: 1
+      })
+    }, 1000)
+  } catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
+
+// 删除
+const handleDelete = async () => {
+	try {
+		await deleteResumeTrainExp(editId.value)
+		uni.showToast({
+			icon: 'success',
+			title: '删除成功'
+		})
+		setTimeout(() => {
+			editId.value = null
+			uni.navigateBack({
+				delta: 1
+			})
+		}, 1000)
+	} catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
 </script>
+
 <style lang="scss" scoped>
 </style>

+ 151 - 2
pagesA/resumeOnline/vocationalSkills.vue

@@ -1,9 +1,158 @@
-<!--  -->
+<!-- 1职业技能 -->
 <template>
-  <view>职业技能</view>
+  <view class="ss-m-x-30 ss-m-y-30">
+    <!-- 已选中 -->
+    <view class="chose borderLine">
+      <view class="choseTitle">当前职业技能</view>
+      <view class="tags">
+        <view
+          v-for="tag in skillExp"
+          :key="tag.id"
+          class="tag"
+          style="color: #00897B; border: 2rpx solid #00897B;"
+          @tap="handleDelete(tag.id)"
+        >
+          {{ tag.title }}
+          <uni-icons type="clear" size="16" color="#00897B"></uni-icons>
+        </view>
+      </view>
+    </view>
+
+    <uni-section title="新增" type="line">
+      <uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="90px" class="ss-m-t-50">
+        <uni-forms-item label="技能名称" name="skillId" required>
+          <uni-data-picker :localdata="skill" v-model="formData.skillId" :map="{ text: 'nameCn', value: 'id' }" placeholder="技能名称" popup-title="请选择技能名称"></uni-data-picker>
+        </uni-forms-item>
+        <uni-forms-item label="熟练度" name="level" required>
+          <uni-data-picker :localdata="skillLevelArr" v-model="formData.level" :map="{ text: 'label', value: 'value' }" placeholder="熟练度" popup-title="请选择熟练度"></uni-data-picker>
+        </uni-forms-item>
+      </uni-forms>
+      <view class="f-horizon-center">
+        <button size="default" class="send-button" @click="submit">提 交</button>
+      </view>
+    </uni-section>
+  </view>
 </template>
 
 <script setup>
+import { ref, unref } from 'vue'
+import { saveResumePersonSkill, deleteResumePersonSkill, getResumePersonSkill, getSkillTree } from '@/api/resume.js'
+import { getDict } from '@/hooks/useDictionaries'
+import { getText } from '@/utils/getText'
+
+let formData = ref({})
+const form = ref()
+const rules = {
+	skillId:{
+		rules: [{required: true, errorMessage: '请选择技能名称' }]
+	},
+	level:{
+		rules: [{required: true, errorMessage: '请选择熟练度' }]
+	}
+}
+
+// 熟练度
+const skillLevelArr = ref([])
+getDict('menduner_skill_level').then(({ data }) => {
+  data = data.data?.length && data.data || []
+  skillLevelArr.value = data
+})
+const skillList = ref([])
+getDict('skillList', {}, 'skillList').then(({ data }) => {
+  data = data.data?.length && data.data || []
+  skillList.value = data
+})
+
+// 获取 职业技能选项
+const skill = ref([])
+const getSkillTreeFunc = async () => {
+  const { data } = await getSkillTree()
+  skill.value = data || []
+}
+getSkillTreeFunc()
+
+// 职业技能
+const skillExp = ref([])
+async function getSkillExpData () {
+  const { data } = await getResumePersonSkill()
+  if (!data || !data.length) {
+    return
+  }
+  skillExp.value = data.map(e => {
+    return {
+      ...e,
+      title: `${getText(e.skillId, skillList.value, 'nameCn', 'id')} / ${getText(e.level, skillLevelArr.value)}`
+    }
+  })
+}
+getSkillExpData()
+
+// 保存
+const submit = async () => {
+  const valid = await unref(form).validate()
+  if (!valid) return
+  try {
+    await saveResumePersonSkill(formData.value)
+    uni.showToast({
+			icon: 'success',
+			title: '新增成功'
+		})
+		setTimeout(() => {
+      getSkillExpData()
+    })
+  } catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
+
+// 删除
+const handleDelete = async (id) => {
+	try {
+		await deleteResumePersonSkill(id)
+		uni.showToast({
+			icon: 'success',
+			title: '删除成功'
+		})
+		setTimeout(() => {
+			getSkillExpData()
+		})
+	} catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
 </script>
+
 <style lang="scss" scoped>
+.borderLine {
+  border-bottom: 2rpx solid #f5f5f5;
+}
+.chose {
+  margin-bottom: 30rpx;
+  .choseTitle {
+    margin-bottom: 30rpx;
+  }
+}
+.tags {
+  padding: 30rpx 0;
+  display: flex;
+  flex-wrap: wrap;
+  .tag {
+    margin: 0 15rpx 12rpx 0;
+    border: 2rpx 15rpx #008978;
+    color: #008978;
+    white-space: nowrap;
+    padding: 4rpx 10rpx;
+    border-radius: 10rpx;
+    font-size: 24rpx;
+  }
+}
+:deep(.uni-section .uni-section-header__decoration) {
+  background-color: #00897B !important;
+}
 </style>

+ 168 - 2
pagesA/resumeOnline/workExperience.vue

@@ -1,9 +1,175 @@
-<!--  -->
+<!-- 工作经历 -->
 <template>
-  <view>工作经历</view>
+  <view class="ss-m-x-30 ss-m-y-30">
+    <uni-forms ref="form" :modelValue="formData" :rules="rules" validateTrigger="bind" label-width="90px">
+      <uni-forms-item label="企业名称" name="enterpriseName" required>
+				<uni-combox :candidates="enterpriseData" placeholder="企业名称" v-model="formData.enterpriseName" @input="handleSearchEnterprise"></uni-combox>
+			</uni-forms-item>
+      <uni-forms-item label="职位名称" name="positionName" required>
+				<uni-combox :candidates="positionData" placeholder="职位名称" v-model="formData.positionName"></uni-combox>
+			</uni-forms-item>
+      <uni-forms-item label="开始时间" name="startTime" required>
+				<picker mode="date" :value="formData.startTime" fields="month" :end="endDate" @change="e => formData.startTime = e.detail.value">
+					<view class="uni-input ss-m-t-20">{{ formData.startTime }}</view>
+				</picker>
+			</uni-forms-item>
+      <uni-forms-item label="结束时间" name="endTime" required>
+				<view class="d-flex">
+          <picker mode="date" :value="formData.endTime" :disabled="endDisabled" fields="month" :end="endDate" @change="e => formData.endTime = e.detail.value">
+            <view class="uni-input ss-m-t-20" :style="{'opacity': endDisabled ? '0.5' : '1'}">{{ formData.endTime }}</view>
+          </picker>
+          <uni-data-checkbox selectedColor="#00897B" class="ss-m-l-50 ss-m-t-14" multiple v-model="sofar" :localdata="[{ text: '至今', value: 1 }]" @change="handleChangeSofar"></uni-data-checkbox>
+        </view>
+			</uni-forms-item>
+      <uni-forms-item label="工作内容" name="content" required>
+				<uni-easyinput type="textarea" v-model="formData.content" autoHeight  placeholder="请输入内容"></uni-easyinput>
+			</uni-forms-item>
+    </uni-forms>
+    <view class="f-horizon-center">
+      <button v-if="editId" size="default" class="delete-button commonBtnStyle" @click="handleDelete">删 除</button>
+      <button size="default" :class="{'save-button': editId, 'commonBtnStyle': editId, 'send-button': !editId}"  @click="submit">保 存</button>
+    </view>
+  </view>
 </template>
 
 <script setup>
+import { ref, unref } from 'vue'
+import { convertYearMonthToTimestamp, timesTampChange } from '@/utils/date.js'
+import { enterpriseSearchByName, saveResumeWorkExp, deleteResumeWorkExp, getResumeWorkExp } from '@/api/resume.js'
+import { onLoad } from '@dcloudio/uni-app'
+import { cloneDeep } from 'lodash-es'
+import { getDict } from '@/hooks/useDictionaries.js'
+
+let formData = ref({
+  startTime: '2014-01',
+  endTime: '2018-01'
+})
+const sofar = ref([])
+const endDisabled = ref(false)
+const editId = ref(null)
+const enterpriseData = ref([])
+const positionData = ref([])
+const form = ref()
+const date = new Date()
+const endDate = date.getFullYear() + '-' + (date.getMonth() + 1) // 不可选时间
+const searchData = ref({
+  enterprise: [],
+  position: []
+})
+
+const rules = {
+	enterpriseName:{
+		rules: [{required: true, errorMessage: '请输入企业名称' }]
+	},
+	positionName:{
+		rules: [{required: true, errorMessage: '请输入职位名称' }]
+	},
+	startTime:{
+		rules: [{required: true, errorMessage: '请选择开始时间' }]
+	},
+  content:{
+		rules: [{required: true, errorMessage: '请输入工作内容' }]
+	}
+}
+const getExp = async (id) => {
+  const { data } = await getResumeWorkExp()
+  if (!data || !data.length) {
+    return
+  }
+  const obj = data.find(e => e.id == id)
+  formData.value = cloneDeep(obj)
+  formData.value.startTime = timesTampChange(obj.startTime, 'Y-M')
+  if (!obj.endTime) {
+    endDisabled.value = true
+    formData.value.endTime = '2018-01'
+    sofar.value = [1]
+  } else formData.value.endTime = timesTampChange(obj.endTime, 'Y-M')
+  handleSearchEnterprise(obj.enterpriseName)
+}
+
+onLoad((options) => {
+  if (options.id) {
+    editId.value = options.id
+    getExp(options.id)
+  }
+})
+
+// 企业搜索
+const handleSearchEnterprise = (e) => {
+  if (!e) return enterpriseData.value = []
+  enterpriseSearchByName({ name: e }).then(res => {
+    searchData.value.enterprise = res.data
+    enterpriseData.value = res.data && res.data?.length ? res.data.map(e => e.value) : []
+  })
+}
+
+let positionTreeChildrenData = []
+getDict('positionTreeData', null, 'positionTreeData').then(({ data }) => {
+  data = data.data?.length && data.data || []
+  data.forEach(e => {
+    if (e?.children?.length) positionTreeChildrenData = positionTreeChildrenData.concat(e.children)
+  })
+  searchData.value.position = positionTreeChildrenData
+  positionData.value = positionTreeChildrenData.map(e => e.nameCn)
+})
+
+// 至今
+const handleChangeSofar = (e) => {
+  const value = e.detail.value.length ? e.detail.value[0] : ''
+  endDisabled.value = value ? true : false
+}
+
+// 保存
+const submit = async () => {
+  const valid = await unref(form).validate()
+  if (!valid) return
+  formData.value.enterpriseId = searchData.value.enterprise.find(e => e.value === formData.value.enterpriseName)?.key
+  formData.value.positionId = searchData.value.position.find(e => e.nameCn === formData.value.positionName)?.id
+  formData.value.startTime = convertYearMonthToTimestamp(formData.value.startTime)
+  formData.value.endTime = sofar.value.length ? null : convertYearMonthToTimestamp(formData.value.endTime)
+  if (!formData.value.endTime && !sofar.value.length) return uni.showToast({ icon: 'none', title: '请选择结束时间' })
+  try {
+    await saveResumeWorkExp(formData.value)
+    uni.showToast({
+			icon: 'success',
+			title: '保存成功'
+		})
+		setTimeout(() => {
+      editId.value = null
+      uni.navigateBack({
+        delta: 1
+      })
+    }, 1000)
+  } catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
+
+// 删除
+const handleDelete = async () => {
+	try {
+		await deleteResumeWorkExp(editId.value)
+		uni.showToast({
+			icon: 'success',
+			title: '删除成功'
+		})
+		setTimeout(() => {
+			editId.value = null
+			uni.navigateBack({
+				delta: 1
+			})
+		}, 1000)
+	} catch (err) {
+		uni.showToast({
+			icon: 'none',
+			title: err.msg
+		})
+	}
+}
 </script>
+
 <style lang="scss" scoped>
 </style>

+ 44 - 68
static/style/index.css

@@ -40,6 +40,16 @@
   text-align: center;
 }
 
+.vertical80-center {
+  text-align: center;
+  line-height: 80vh;
+}
+
+.vertical-center {
+  text-align: center;
+  line-height: 80vh;
+}
+
 .d-flex {
   display: flex;
 }
@@ -184,80 +194,27 @@
   margin: 5rpx;
 }
 
-/* 列表触底暂无更多 */
-.noMore {
-  text-align: center;
-  color: grey;
-}
-
-.salary-text {
-  float: right;
-  color: #fe574a;
-}
-
-.list-shape {
-  padding: 10px 30rpx 10px;
-  margin-top: 10px;
-  background-color: #fff;
-}
-
-.tag-gap {
-  margin: 10rpx 10rpx 10rpx 0;
-}
-
-.tag-gap1 {
-  margin: 10rpx;
-}
-
-.viewider {
-  margin: 0 10rpx;
-}
-
-.mt {
-  margin-top: 10rpx;
-}
-
-.mb {
-  margin-bottom: 10rpx;
-}
-
-.ml {
-  margin-left: 20rpx;
-}
-
-.mr {
-  margin-right: 20rpx;
-}
-
-.cer-end {
-  position: absolute;
-  top: 85%;
-  right: 16%;
-}
-
-.cer-text {
-  text-decoration: underline;
-  margin: 0 5rpx;
-}
-
-.dis {
-  display: flex;
-  align-items: center;
+.salary {
+  color: var(--v-error-base);
+  line-height: 41px;
+  font-weight: 600;
+  height: auto;
+  display: inline-block;
+  vertical-align: sub;
 }
 
-.show-more {
-  width: 26vw;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
+.bold {
+  font-weight: bold;
 }
 
-.mr-10 {
-  margin-right: 10rpx;
+.w-600 {
+  font-weight: 600;
 }
 
-.divider {
-  color: #e4d4d2;
+.horizontalDividingLine {
+  height: 1px;
+  color: #EDEDED;
+  width: 100%;
 }
 
 .default-active {
@@ -9099,6 +9056,25 @@
   color: #fff;
 }
 
+.commonBtnStyle {
+  width: 45vw;
+  height: 44px;
+  line-height: 44px;
+  color: #fff;
+}
+
+.save-button {
+  margin: 20px 0 20px 20px;
+  background-color: #00897B !important;
+}
+
+.delete-button {
+  margin: 20px auto;
+  color: #FE574A !important;
+  background-color: #fff !important;
+  border: 1px solid #FE574A;
+}
+
 .disabled-button {
   width: 85%;
   height: 44px;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
static/style/index.min.css


+ 17 - 0
static/style/index.scss

@@ -431,6 +431,23 @@
 	// border-radius: 25px;
 	color: #fff;
 }
+
+.commonBtnStyle {
+  width: 45vw;
+  height: 44px;
+  line-height: 44px;
+  color: #fff;
+}
+.save-button {
+  margin: 20px 0 20px 20px;
+  background-color: #00897B !important;
+}
+.delete-button {
+  margin: 20px auto;
+	color: #FE574A !important;
+  background-color: #fff !important;
+	border: 1px solid #FE574A;
+}
 //禁用按钮
 .disabled-button {
 	width: 85%;

+ 3 - 0
static/svg/integral.svg

@@ -0,0 +1,3 @@
+<svg t="1719285689429" class="icon mx-1" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="38595" width="24" height="24">
+  <path d="M98.0992 511.7952c0 228.5568 185.1392 413.696 413.696 413.696s413.696-185.1392 413.696-413.696-185.1392-413.696-413.696-413.696c-109.7728 0-214.8352 43.6224-292.4544 121.2416-77.6192 77.4144-121.2416 182.6816-121.2416 292.4544z m0 0" fill="#FBE945" p-id="38596"></path><path d="M804.2496 219.3408L219.3408 804.4544c162.2016 158.1056 421.2736 156.4672 581.2224-3.6864 160.1536-160.1536 161.792-419.2256 3.6864-581.4272z m0 0" fill="#F2D636" p-id="38597"></path><path d="M210.944 511.7952c0 121.6512 73.3184 231.2192 185.5488 277.9136 112.4352 46.4896 241.664 20.8896 327.68-65.1264s111.8208-215.4496 65.1264-327.68c-46.4896-112.4352-156.2624-185.5488-277.9136-185.5488C345.7024 210.944 210.944 345.7024 210.944 511.7952z m0 0" fill="#FBB11B" p-id="38598"></path><path d="M717.824 293.2736c-118.1696-112.0256-303.9232-109.568-419.0208 5.5296-115.0976 115.0976-117.5552 301.056-5.5296 419.0208l424.5504-424.5504z m0 0" fill="#FDC72F" p-id="38599"></path><path d="M648.3968 566.4768c23.7568 125.1328-22.9376 157.696-138.4448 97.8944-118.1696 64.3072-163.0208 32.5632-136.6016-93.3888-96.0512-85.4016-77.6192-137.4208 54.6816-156.0576 58.1632-116.3264 114.688-117.1456 170.1888-2.6624 131.2768 14.1312 148.0704 65.3312 50.176 154.2144z m0 0" fill="#F4EA2A" p-id="38600"></path><path d="M598.2208 412.2624c131.2768 14.1312 148.0704 65.1264 50.176 154.2144 23.7568 125.1328-22.9376 157.696-138.4448 97.8944-90.112 49.152-137.6256 42.1888-143.36-19.8656l231.6288-232.2432z m50.176 154.2144" fill="#F2D636" p-id="38601"></path>
+</svg>

+ 1 - 1
uni_modules/uni-combox/components/uni-combox/uni-combox.vue

@@ -205,7 +205,7 @@
 		border: 1px solid #EBEEF5;
 		border-radius: 6px;
 		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-		z-index: 2;
+		z-index: 9;
 		padding: 4px 0;
 	}
 

+ 12 - 0
utils/date.js

@@ -24,4 +24,16 @@ export const getAgeByBirthdayTimestamp = (timestamp) => {
   const birthday = new Date(timestamp)
   const age = now.getFullYear() - birthday.getFullYear()
   return age
+}
+
+// 将YYYY-MM转换为时间戳
+export const convertYearMonthToTimestamp = (yearMonth) => {  
+  const regex = /^\d{4}-\d{2}$/
+  if (!regex.test(yearMonth)) {  
+    throw new Error("Invalid input format. Expected 'YYYY-MM'.")
+  }
+  const [year, month] = yearMonth.split('-').map(Number)
+  const date = new Date(Date.UTC(year, month - 1, 1))
+  const timestamp = date.getTime()
+  return timestamp  
 }

+ 3 - 13
utils/position.js

@@ -14,7 +14,8 @@ export const dictObj = reactive({
   financing: [], // 融资阶段
   sex: [],
   jobType: [],
-  areaTreeData: []
+  areaTreeData: [],
+  eduSystemType: []
 })
 const dictList = ref([
   { type: 'menduner_pay_unit', value: 'payUnit', key: 'payUnit', label: 'payName' },
@@ -26,6 +27,7 @@ const dictList = ref([
   { type: 'menduner_marital_status', value: 'marital', key: 'maritalStatus', label: 'maritalStatusName' },
   { type: 'menduner_industry_type', value: 'industry', key: 'industryId', label: 'industryName', params: {}, apiType: 'industryList', nameKey: 'nameCn', valueKey: 'id' },
   { type: 'menduner_education_type', value: 'edu', key: 'eduType', label: 'eduName' },
+  { type: 'menduner_education_system_type', value: 'eduSystemType', key: 'eduSystemType', label: 'eduSystemName' },
   { type: 'menduner_exp_type', value: 'exp', key: 'expType', label: 'expName' },
   { type: 'menduner_area_type', value: 'area', key: 'areaId', label: 'areaName', params: {}, apiType: 'areaList', nameKey: 'name', valueKey: 'id' },
   { type: 'positionData', value: 'position', key: 'positionId', label: 'positionName', params: {}, apiType: 'positionData', nameKey: 'nameCn', valueKey: 'id' },
@@ -78,18 +80,6 @@ export const dealDictObjData = (res, obj) => {
   return res
 }
 
-// 获取单个字典对应的数值
-export const getDictValueWithLabel = (dict, value, valueKey = 'value', labelKey = 'label') => {
-  let result = ''
-  getDict(dict).then(({ data }) => {
-    if (!data || !data.length) return
-    const obj = data.find(e => e[valueKey] === value)
-    if (!obj) return
-    result = obj[labelKey]
-  })
-  return result
-}
-
 // 计算众聘佣金
 let data
 const list = ['headhuntRate', 'recommendRate', 'cvRate'] // 平台、推荐人、投递人

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác