Browse Source

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

Xiao_123 7 months ago
parent
commit
c8977e07f8

+ 259 - 0
api/resume.js

@@ -0,0 +1,259 @@
+import request from "@/utils/request"
+
+// 保存基本信息
+export const saveResumeBasicInfo = async (data) => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/info/save',
+    method: 'POST',
+    data,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 保存个人优势
+// export const saveResumeAdvantage = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/advantage/save',
+//     data
+//   })
+// }
+
+// // 保存培训经历
+// export const saveResumeTrainExp = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/train/exp/save',
+//     data
+//   })
+// }
+
+// // 删除培训经历
+// export const deleteResumeTrainExp = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/train/exp/remove?id=' + id
+//   })
+// }
+
+// 获取培训经历
+export const getResumeTrainExp = async () => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/get/train/exp',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 获取-教育经历
+export const getResumeEduExp = async () => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/get/edu/exp',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 删除-教育经历
+// export const deleteResumeEduExp = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/edu/exp/remove?id=' + id
+//   })
+// }
+
+// // 保存-教育经历
+// export const saveResumeEduExp = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/edu/exp/save',
+//     data
+//   })
+// }
+
+// 获取-工作经历
+export const getResumeWorkExp = async () => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/get/work/exp',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 删除-工作经历
+// export const deleteResumeWorkExp = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/work/exp/remove?id=' + id
+//   })
+// }
+
+// // 保存-工作经历
+// export const saveResumeWorkExp = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/work/exp/save',
+//     data
+//   })
+// }
+
+// // 保存项目经历
+// export const saveResumeProjectExp = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/project/exp/save',
+//     data
+//   })
+// }
+
+// // 删除项目经历
+// export const deleteResumeProjectExp = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/project/exp/remove?id=' + id
+//   })
+// }
+
+// 获取项目经历
+export const getResumeProjectExp = async () => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/get/project/exp',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 获取-技能树形
+// export const getSkillTree = async () => {
+//   return await request.get({
+//     url: '/app-api/menduner/system/skill/get/tree'
+//   })
+// }
+
+// 获取-职业技能
+export const getResumePersonSkill = async () => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/get/person/skill',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 删除-职业技能
+// export const deleteResumePersonSkill = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/person/skill/remove?id=' + id
+//   })
+// }
+
+// // 保存-职业技能
+// export const saveResumePersonSkill = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/person/skill/save',
+//     data
+//   })
+// }
+
+// // 保存求职意向
+// export const saveResumeJobInterested = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/job/interested/save',
+//     data
+//   })
+// }
+
+// // 删除求职意向
+// export const deleteResumeJobInterested = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/job/interested/remove?id=' + id
+//   })
+// }
+
+// // 获取求职意向
+export const getResumeJobInterested = async () => {
+  return request({
+    url: '/app-api/menduner/system/person/resume/get/job/interested',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// // 根据专业名称模糊搜索
+// export const schoolMajorByName = async (params) => {
+//   return await request.get({
+//     url: '/app-api/menduner/system/major/search/by/name',
+//     params
+//   })
+// }
+
+// // 根据学校名称模糊搜索
+// export const schoolSearchByName = async (params) => {
+//   return await request.get({
+//     url: '/app-api/menduner/system/school/search/by/name',
+//     params
+//   })
+// }
+
+// // 根据企业名称模糊搜索
+// export const enterpriseSearchByName = async (params) => {
+//   return await request.get({
+//     url: '/app-api/menduner/system/enterprise/search/by/name',
+//     params
+//   })
+// }
+
+// // 保存附件
+// export const savePersonResumeCv = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/person/cv/save',
+//     data
+//   })
+// }
+
+// // 删除附件
+// export const deletePersonResumeCv = async (id) => {
+//   return await request.delete({
+//     url: '/app-api/menduner/system/person/resume/person/cv/remove?id=' + id
+//   })
+// }
+
+// // 获取附件列表
+// export const getPersonResumeCv = async () => {
+//   return await request.get({
+//     url: '/app-api/menduner/system/person/resume/get/person/cv'
+//   })
+// }
+
+// // 修改求职类型
+// export const updateJobStatus = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/job/status/update?status=' + data,
+//   })
+// }
+
+// // 修改人才头像
+// export const updatePersonAvatar = async (url) => {
+//   return await request.post({
+//     url: `/app-api/menduner/system/person/resume/avatar/update?avatar=${url}`
+//   })
+// }
+
+// // 修改个人画像
+// export const savePersonPortrait = async (data) => {
+//   return await request.post({
+//     url: '/app-api/menduner/system/person/resume/tag/update',
+//     data
+//   })
+// }

+ 174 - 0
api/sign.js

@@ -0,0 +1,174 @@
+import request from "@/utils/request"
+
+// 签到
+export const createRewardSignInRecord = (data) => {
+  return request({
+    url: '/app-api/menduner/reward/sign-in/record/create',
+    method: 'POST',
+    data,
+    custom: {
+      auth: true,
+      showLoading: false
+    }
+  })
+}
+
+
+// 获得个人签到统计
+export const getRewardSignInRecordSummary = () => {
+  return request({
+    url: '/app-api/menduner/reward/sign-in/record/get-summary',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// 获得签到记录分页
+export const getRewardSignInRecordPage = (pageNo, pageSize) => {
+  return request({
+    url: `/app-api/menduner/reward/sign-in/record/page?pageSize=${pageSize}&pageNo=${pageNo}`,
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// 获取签到规则列表
+export const getRewardSignInConfigList = () => {
+  return request({
+    url: '/app-api/menduner/reward/sign-in/config/list',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: false
+    }
+  })
+}
+
+// 获取账户余额
+export const getAccountBalance = () => {
+  return request({
+    url: '/app-api/pay/wallet/get',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// 获取积分余额
+export const getUserAccount = () => {
+  return request({
+    url: '/app-api/menduner/system/mde-user/get/account',
+    method: 'GET',
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// 福利 领领取优惠券
+export const takeCoupon = (templateId) => {
+  return request({
+    url: '/app-api/promotion/coupon/take',
+    method: 'POST',
+    data: { templateId },
+    custom: {
+      auth: true,
+      showLoading: true,
+      loadingMsg: '领取中',
+      showSuccess: true,
+      successMsg: '领取成功'
+    }
+  })
+}
+// 福利 优惠券ID
+export const getDiyTemplate = (ids) => {
+  return request({
+    url: '/app-api/promotion/coupon-template/list-by-ids',
+    method: 'GET',
+    params: {
+      ids
+    },
+    custom: {
+      auth: true,
+      showError: false,
+      showLoading: false,
+    }
+  })
+}
+// 福利 获取商城模板
+export const getDiyTemplateUsed = () => {
+  return request({
+    url: '/app-api/promotion/diy-template/used',
+    method: 'GET',
+    custom: {
+      auth: true,
+      showError: false,
+      showLoading: false,
+    }
+  })
+}
+
+
+
+// 获取优惠券模板分页
+export const getCouponTemplatePage = (params) => {
+  return request({
+    url: '/app-api/promotion/coupon-template/page',
+    method: 'GET',
+    params,
+    custom: {
+      auth: false,
+      showError: false,
+      showLoading: false,
+    }
+  })
+}
+
+// 我的优惠劵列表
+export const getCouponPage = (params) => {
+  return request({
+    url: '/app-api/promotion/coupon/page',
+    method: 'GET',
+    params,
+    custom: {
+      auth: true,
+      showError: false,
+      showLoading: false,
+    }
+  })
+}
+
+// 获得钱包充值记录分页
+export const getUserWalletRechargePage = async (params) => {
+  return request({
+    url: '/app-api/pay/wallet-recharge/page',
+    method: 'GET',
+    params,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}
+
+// 账户变动记录
+export const getEnterpriseAccountRecordPage = async (params) => {
+  return request({
+    url: '/app-api/menduner/system/recruit/enterprise/account/record/page',
+    method: 'GET',
+    params,
+    custom: {
+      showLoading: false,
+      auth: true
+    }
+  })
+}

+ 0 - 1
custom-tab-bar/index.js

@@ -51,7 +51,6 @@ Component({
       this.setData({  
         selected: data.index  
       })
-      console.log('select', this.data)
     }
   }
 })

+ 1 - 1
custom-tab-bar/index.wxss

@@ -70,5 +70,5 @@
 }
 
 .tab-bar-item view {
-  font-size: 10px;
+  font-size: 12px;
 }

+ 1 - 1
hooks/useDictionaries.js

@@ -24,7 +24,7 @@ export const getDict = (type, params, apiType = 'dict') => {
     return new Promise((resolve) => {
       const item = uni.getStorageSync(type)
       const catchData = item ? JSON.parse(item) : null
-      if (catchData && catchData.expire && (Date.now() <= catchData.expire) && catchData.data) {
+      if (catchData && catchData.expire && (Date.now() <= catchData.expire) && catchData.data && catchData.data?.data?.length) {
         return resolve({ data: catchData.data })
       }
       // 传参按照规范参数传

+ 0 - 1
hooks/useIM.js

@@ -212,7 +212,6 @@ export const useIM = () => {
 
   async function resetConfig () {
     const { uid, wssUrl, token } = await getKey()
-    console.log(uid, wssUrl, token)
     IM.setUid(uid)
     // 单机模式可以直接设置地址
     WKSDK.shared().config.addr = 'wss://' + wssUrl// 默认端口为5200 + wsUrl 

+ 30 - 0
pages.json

@@ -42,6 +42,18 @@
 		{
 			"root": "pagesA",
 			"pages": [
+				{
+					"path": "resumeOnline/index",
+					"style": {
+						"navigationBarTitleText": "在线简历"
+					}
+				},
+				{
+					"path": "resumeOnline/baseInfoEdit",
+					"style": {
+						"navigationBarTitleText": "个人信息"
+					}
+				},
 				{
 					"path": "resume/index",
 					"style": {
@@ -83,6 +95,24 @@
 					"style": {
 						"navigationBarTitleText": "我的聊天"
 					}
+				},
+				{
+					"path": "coupon/index",
+					"style": {
+						"navigationBarTitleText": "我的优惠券"
+					}
+				},
+				{
+					"path": "balance/index",
+					"style": {
+						"navigationBarTitleText": "我的余额"
+					}
+				},
+				{
+					"path": "integral/index",
+					"style": {
+						"navigationBarTitleText": "积分明细"
+					}
 				}
 			]
 		},

+ 8 - 2
pages/index/communicate.vue

@@ -1,6 +1,6 @@
 <template>
-  <layout-page class="ss-m-x-15">
-		<view class="height">
+  <layout-page>
+		<view class="height defaultBgc">
 			<scroll-view class="scrollBox" scroll-y="true" >
 				<view class="box" v-for="item in items" :key="item.id" @tap="handleTo(item)">
 					<view class="box-header">
@@ -38,6 +38,7 @@
 					mode="widthFix"
 					style="width: 100%;">
 				</image>
+				<uni-load-more status="noMore" />
 			</scroll-view>
 		</view>
   </layout-page>
@@ -140,7 +141,12 @@ async function init () {
 </script>
 
 <style scoped lang="scss">
+.scrollBox {
+	padding-bottom: 24rpx;
+  box-sizing: border-box;
+}
 .box {
+	background: #FFF;
 	height: 130rpx;
 	padding: 20rpx;
 	box-sizing: border-box;

+ 4 - 2
pages/index/crowdsourcing.vue

@@ -51,7 +51,7 @@ import { getJobAdvertisedHire } from '@/api/position.js'
 import { getDict } from '@/hooks/useDictionaries.js'
 import { dealDictArrayData } from '@/utils/position.js'
 import PositionList from '@/components/PositionList'
-import { onShow } from '@dcloudio/uni-app'
+import { onShow, onLoad } from '@dcloudio/uni-app'
 // 设置自定义tabbar选中值
 onShow(() => {
     const currentPage = getCurrentPages()[0];  // 获取当前页面实例
@@ -59,7 +59,9 @@ onShow(() => {
 
     // 设置当前tab页的下标index
     currentTabBar?.setData({ selected: 3 });
-		getList()
+})
+onLoad(() => {
+	getList()
 })
 const swiperAdList = ref(swiperAdListTest)
 const items = reactive([])

+ 2 - 1
pages/index/my.vue

@@ -74,7 +74,8 @@ const itemList = [
 ]
 
 const list = [
-	{	title: '我的简历',	path: '/pagesA/resume/index'	},					
+	{	title: '在线简历',	path: '/pagesA/resumeOnline/index'	},					
+	{	title: '附件简历',	path: '/pagesA/resume/index'	},					
 	{ title: '面试管理', path: '/pagesA/interview/index' },
 	{ title: '门墩儿商城', appId: 'wx6decdf12f9e7a061' },
 	{ title: '我要招聘', key: 'recruit' }

+ 2 - 0
pages/index/position.vue

@@ -149,6 +149,8 @@ const loadingMore = () => { // 加载更多
   // height: 100%;
   flex: 1;
   height: 0 !important;
+  padding-bottom: 24rpx;
+  box-sizing: border-box;
   // padding-bottom: 160rpx;
 }
 </style>

+ 535 - 15
pages/index/welfare.vue

@@ -1,30 +1,550 @@
 <template>
   <layout-page>
-		<view class="box">
-			<SwiperAd :list="swiperAdList"></SwiperAd>
-			<view class=""></view>
+		<view class="box defaultBgc">
+      <scroll-view class="scrollBox" scroll-y="true" @scrolltolower="loadingMore">
+        <view class="content">
+          <!-- 钱包 -->
+          <view class="wallet">
+            <view class="wallet-content">
+              <view class="wallet-content-member">
+                <view class="iconBox">
+                  <view class="iconBox-line">
+                    <uni-icons type="vip-filled" size="20" color="#ffbc00"></uni-icons>
+                  </view>
+                </view>
+                <view class="name">
+                  <text v-if="useUserStore.isLogin" @tap="toInfo" class="active">
+                    {{ useUserStore?.baseInfo?.name || useUserStore?.userInfo?.phone }}
+                  </text>
+                  <text v-else @tap="handleLogin">点击登录</text>
+                </view>
+                </view>
+              <view class="wallet-content-integral wallet-content-item" @tap="handleTo('integral')">
+                <text>{{ balance.point || 0 }}</text>
+                <text class="title">积分</text>
+              </view>
+              <view class="wallet-content-cash wallet-content-item" @tap="handleTo('balance')">
+                <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>
+          <!-- 签到 -->
+          <view class="signIn">
+            <view class="signIn-content">
+              <view class="signIn-content-items">
+                <view class="item" v-for="(sign, i) in SignItems" :key="sign.day">
+                  <view class="box" :class="{ active: i < continuousDay }">
+                    <uni-icons type="vip" size="30" color="#ffbc00" style="text-align: center;"></uni-icons>
+                    <text class="text">+{{ sign.point }}</text>
+                  </view>
+                  <view class="day">
+                    <text>{{ i === todayNumber ? '今' : '第' + sign.day }}天</text>
+                  </view>
+                </view>
+              </view>
+              <view class="tips">
+                <button
+                  :disabled="todaySignIn"
+                  :class="{ disabled: todaySignIn }"
+                  @tap="handleSignIn"
+                >
+                  {{ todaySignIn ? '已签到' : '签到'}}
+                </button>
+              </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>
+          </view>
+          <uni-load-more :status="more" />
+        </view>
+      </scroll-view>
 		</view>
 	</layout-page>
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { ref, watch } from 'vue'
 import layoutPage from '@/layout'
-import SwiperAd from '@/components/SwiperAd'
+import {
+	getRewardSignInConfigList,
+	getRewardSignInRecordSummary,
+  createRewardSignInRecord,
+  getAccountBalance,
+  getUserAccount,
+  getDiyTemplateUsed,
+  getDiyTemplate,
+  getCouponTemplatePage,
+  takeCoupon,
+  getCouponPage
+} from '@/api/sign'
+import { onShow, onLoad } from '@dcloudio/uni-app'
+import { userStore } from '@/store/user'
+import { showAuthModal } from '@/hooks/useModal'
 
-import { swiperAdListTest } from '@/utils/testData'
-import { onShow } from '@dcloudio/uni-app'
-// 设置自定义tabbar选中值
-onShow(() => {
-    const currentPage = getCurrentPages()[0];  // 获取当前页面实例
-    const currentTabBar = currentPage?.getTabBar?.();
+const useUserStore = userStore()
+// 设置自定义tabBar选中值
+
+const SignItems = ref([])
+
+// 连续签到天数
+const continuousDay = ref(0)
+// 今天有无签到
+const todaySignIn = ref(false)
+
+// 今天
+const todayNumber = ref()
+
+const balance = ref({})
+
+const pageInfo = ref({
+  pageNo: 1,
+  pageSize: 20
+})
+const total = ref(0)
+const items = ref([])
+const more = ref('more')
 
-    // 设置当前tab页的下标index
-    currentTabBar?.setData({ selected: 2 });
+const myCoupon = ref(0)
+
+// watch(() => useUserStore.isLogin, () => {
+//   if (useUserStore.isLogin) {
+//     init()
+//   }
+// })
+
+watch([() => useUserStore.refreshToken, () => useUserStore.isLogin], () => {
+  if (useUserStore.isLogin) {
+    getMyCoupon()
+    initCoupon()
+    getSummary()
+    getBalance()
+  }
 })
-const swiperAdList = ref(swiperAdListTest)
+
+onShow(() => {
+  const currentPage = getCurrentPages()[0];  // 获取当前页面实例
+  const currentTabBar = currentPage?.getTabBar?.();
+  // 设置当前tab页的下标index
+  currentTabBar?.setData({ selected: 2 });
+  init()
+})
+
+function init () {
+  // 获取签到列表
+  getSignIn()
+  // 获取签到信息
+  getSummary()
+  // 获取余额积分
+  getBalance()
+  // 获取优惠券列表
+  initCoupon()
+  // 获取我的优惠券总数
+  getMyCoupon()
+
+}
+
+// 获取积分余额
+async function getBalance() {
+  const { data } = await getAccountBalance()
+  const { data: _data } = await getUserAccount()
+  balance.value = {
+    ...data,
+    point: _data.point
+  }
+}
+
+
+// 获取个人签到统计
+async function getSummary() {
+  const { data } = await getRewardSignInRecordSummary()
+  if (!data) return
+  continuousDay.value = data.continuousDay // 连续签到第n天
+  todaySignIn.value = data.todaySignIn // 今天有无签到
+  todayNumber.value = todaySignIn.value ? continuousDay.value - 1 : continuousDay.value
+}
+// 获取签到列表
+async function getSignIn () {
+  try {
+    const { data } = await getRewardSignInConfigList()
+    SignItems.value = data
+  } catch (error) {
+    
+  }
+}
+// 签到
+async function handleSignIn () {
+  uni.showLoading({
+    title: '正在签到'
+  })
+  try {
+    const { code } = await createRewardSignInRecord()
+    if (code !== 0) {
+      return
+    }
+    setTimeout(async () => {
+      const { code: _code } = await getSummary()
+      if (_code !== 0) {
+        return
+      }
+      uni.showToast({
+        title: '签到成功',
+        icon: 'success',
+        mask: true
+      })
+      // 更新积分
+      getBalance()
+    }, 1000)
+  } catch (error) {
+    
+  } finally {
+    uni.hideLoading()
+  }
+}
+
+
+// 获取优惠券分页
+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()
+		return
+	}
+}
+
+function toInfo () {
+  uni.navigateTo({
+		url: '/pagesA/info/index'
+	})
+}
+
+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()
+		return
+  }
+  uni.navigateTo({
+    url: `/pagesA/${page}/index`
+  })
+}
 </script>
 
 <style scoped lang="scss">
-
+$px: 20rpx;
+.box {
+  overflow: hidden;
+  height: 100vh;
+  padding: $px 0 0 0;
+  box-sizing: border-box;
+  .scrollBox{
+    height: 100%;
+    
+    padding-bottom: 120rpx;
+    box-sizing: border-box;
+  }
+  .content {
+    padding-bottom: 24rpx;
+    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;
+      
+      &-member {
+        width: 50%;
+        display: flex;
+        align-items: center;
+        position: relative;
+        &:after {
+          content: '';
+          position: absolute;
+          width: 4rpx;
+          height: 30%;
+          right: 0;
+          top: 35%;
+          background: #00897B;
+        }
+        .iconBox {
+          width: 100rpx;
+          height: 100%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          &-line {
+            border: 4rpx solid #ffbc00;
+            border-radius: 180rpx;
+            padding: 10rpx;
+          }
+        }
+        .name {
+          flex: 1;
+          .actvie {
+            color: #ffbc00;
+          }
+          
+        }
+      }
+      &-item {
+        width: 16.6%;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        .title {
+          font-size: .85em;
+        }
+      }
+      &-integral {
+      }
+      &-cash {
+        
+      }
+    }
+  }
+  .signIn {
+    // padding: 0 $px;
+    box-sizing: border-box;
+    &-content {
+      border-radius: 10rpx;
+      background: #FFF;
+      &-items {
+        padding: 20rpx $px;
+        display: flex;
+        height: 220rpx;
+        box-sizing: border-box;
+        .item {
+          height: 140rpx;
+          width: 100%;
+          align-items: center;
+          justify-content: center;
+          padding: 0 10rpx;
+          .box {
+            height: 100%;
+            width: 100%;
+            display: flex;
+            flex-direction: column;
+            background: #f2f4f7;
+            border-radius: 10rpx;
+            &.active {
+              background: rgba(16,137,123, .66);
+            }
+            .text {
+              font-size: .75em;
+              text-align: center;
+            }
+          }
+          .day {
+            margin-top: 10rpx;
+            height: 60rpx;
+            text-align: center;
+            font-size: .5em;
+          }
+        }
+      }
+      .tips {
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        height: 80rpx;
+        font-size: .75em;
+        color: #999;
+        &-light {
+          color: #00897B;
+          padding: 0 10rpx;
+        }
+        button {
+          width: 180rpx;
+          height: 60rpx;
+          font-size: 24rpx;
+          margin: 0 10rpx;
+          border: unset;
+          background-color: #00897B;
+          color: #FFF;
+          &.disabled {
+            background-color: #a7a7a7 !important;
+          }
+        }
+      }
+      
+    }
+  }
+  .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);
+        }
+      }
+      .img {
+        image {
+          width: 128rpx;
+          height: 128rpx;
+        }
+      }
+    }
+  }
+}
 </style>

+ 142 - 0
pagesA/balance/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <layout-page>
+    <view class="box defaultBgc">
+      <scroll-view class="scrollBox" scroll-y="true" @scrolltolower="loadingMore">
+        <view>
+          <view class="panel">
+            <view>
+              <uni-icons color="#f30" type="icon-renminbi1688" size="16" custom-prefix="iconfont"></uni-icons>
+              <text class="text">{{ balance.balance > 0 ? (balance?.balance / 100.0).toFixed(2) : 0 }}</text>
+            </view>
+            <view>
+              <button class="btn">充值</button>
+            </view>
+          </view>
+          <view class="list">
+            <uni-list border-full>
+              <uni-list-item
+                v-for="item in items"
+                :key="item.id"
+                :title="item._payPrice"
+                :note="item._payTime"
+                :rightText="item.payChannelName"
+              />
+            </uni-list>
+            <uni-load-more :status="more" />
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+  </layout-page>
+</template>
+<!-- balance 余额 -->
+<script setup>
+import { ref } from 'vue'
+import {
+  getAccountBalance,
+  getUserWalletRechargePage
+} from '@/api/sign'
+import { timesTampChange } from '@/utils/date'
+
+const balance = ref({})
+
+const items = ref([])
+const pageInfo = ref({
+  pageNo: 1,
+  pageSize: 20
+})
+const total = ref(0)
+const more = ref('more')
+
+getBalance()
+getList()
+// 获取积分余额
+async function getBalance() {
+  const { data } = await getAccountBalance()
+  if (!data) {
+    return
+  }
+  balance.value = data
+}
+
+async function getList () {
+  try {
+    const { data } = await getUserWalletRechargePage(pageInfo.value)
+    if (!data || !data.list || !data.list.length) {
+      if (pageInfo.value.pageNo === 1) {
+        return
+      }
+      pageInfo.value.pageNo--
+      more.value = 'more'
+      return
+    }
+    const _data = data.list.map(e => {
+      return {
+        ...e,
+        _payPrice: (e.payPrice / 100.0).toFixed(2),
+        _payTime: timesTampChange(e.payTime)
+      }
+    })
+    items.value.push(..._data)
+    total.value = +data.total
+    more.value = total.value <= items.value.length ? 'noMore' : 'more'
+  } catch (error) {
+    if (pageInfo.value.pageNo === 1) {
+      return
+    }
+    pageInfo.value.pageNo--
+    more.value = 'more'
+  }
+}
+function loadingMore () {
+  if (more.value === 'noMore') {
+    return
+  }
+  more.value = 'loading'
+  pageInfo.value.pageNo++
+  getList()
+}
+</script>
+
+<style lang="scss" scoped>
+.box {
+  height: 100vh;
+}
+.scrollBox {
+  width: 100vw;
+  // padding: 20rpx;
+  box-sizing: border-box;
+  .panel {
+    position: sticky;
+    z-index: 2;
+    top: 0;
+    width: 100%;
+    padding: 20rpx;
+    margin-bottom: 20rpx;
+    box-sizing: border-box;
+    background: #FFF;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-end;
+    box-shadow: 0px 0px 10px 0px rgb(0, 0, 0, 0.25);
+    .text {
+      color: #F30;
+      font-size: 54rpx;
+
+    }
+    .btn {
+      width: 180rpx;
+      height: 60rpx;
+      line-height: 60rpx;
+      font-size: 28rpx;
+      text-align: center;
+      background: #00897B;
+      color: #FFF;
+      border-radius: 30rpx;
+    }
+  }
+  .list {
+    // padding: 20rpx;
+  }
+}
+</style>

+ 198 - 0
pagesA/coupon/index.vue

@@ -0,0 +1,198 @@
+<template>
+  <layout-page>
+    <scroll-view class="scrollBox" scroll-y="true" @scrolltolower="loadingMore">
+      <view class="defaultBgc content">
+        <view
+          v-for="item in items"
+          :key="item.id"
+          class="content-item"
+          :class="{ used: item.status === 2, disabled: item.status === 3 }"
+        >
+          <view class="msg">
+            <view class="item">
+              <view class="name">{{ item.name }}</view>
+              <view class="price">
+                <uni-icons color="#f30" type="icon-renminbi1688" size="16" custom-prefix="iconfont"></uni-icons>
+                {{ item.price }}
+              </view>
+            </view>
+            <view class="item">
+              <view class="desc">有效期:{{ item.legalTime }}</view>
+              <view class="desc">满 {{ item.used }} 可用</view>
+            </view>
+          </view>
+          <view class="use">
+            <button
+            class="btn"
+            :class="{ disabled: item.status !== 1 }"
+            @tap="handleTo(item.status)"
+            >{{ item.status === 1 ? '立即使用' : item.status === 2 ? '已使用' : '已过期'}}</button>
+          </view>
+        </view>
+        <uni-load-more :status="more" />
+      </view>
+    </scroll-view>
+  </layout-page>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import {
+  getCouponPage
+} from '@/api/sign'
+import { timesTampChange } from '@/utils/date'
+
+
+const pageInfo = ref({
+  pageNo:1,
+  pageSize: 20
+})
+const total = ref(0)
+const items = ref([])
+const more = ref('more')
+
+getMyCoupon()
+
+async function getMyCoupon () {
+  try {
+    const { data } = await getCouponPage({ ...pageInfo.value })
+    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.map(e => {
+      return {
+        ...e,
+        price: (e.discountPrice / 100).toFixed(2),
+        legalTime: timesTampChange(e.validStartTime, 'Y-M-D') + ' 至 ' + timesTampChange(e.validEndTime, 'Y-M-D'),
+        used: (e.usePrice / 100).toFixed(2)
+      }
+    }))
+    total.value = +data.total
+    more.value = items.value.length >= total.value ? 'noMore' : 'more'
+  } catch (error) {
+    if (pageInfo.value.pageNo === 1) {
+      more.value = 'more'
+      return
+    }
+    pageInfo.value.pageNo--
+    more.value = 'more'
+  }
+}
+
+function handleTo (status) {
+  if (status !== 1) {
+    return
+  }
+  wx.navigateToMiniProgram({  
+    appId: 'wx6decdf12f9e7a061', // 目标小程序的 appId
+    // envVersion: 'develop',
+    success(res) {  
+        // 打开成功  
+        console.log('成功跳转至小程序:', res);  
+    },  
+    fail(err) {  
+        // 打开失败
+        uni.showToast({
+          title: '打开商城失败',
+          icon: 'none'
+        })
+    }  
+  })
+}
+
+function loadingMore () {
+  if (more.value === 'noMore') {
+    return
+  }
+  more.value = 'loading'
+  pageInfo.value.pageNo++
+  getMyCoupon()
+}
+</script>
+
+<style lang="scss" scoped>
+.content {
+  // height: 100vh;
+  width: 100vw;
+  padding: 20rpx;
+  box-sizing: border-box;
+  &-item {
+    margin-bottom: 20rpx;
+    .msg {
+      background: #FFF;
+      padding: 40rpx;
+      box-sizing: border-box;
+      -webkit-mask: radial-gradient(circle at 0.375rem 100%, #00000000 0.375rem, red 0) -0.375rem;
+      position: relative;
+      &::after {
+        content: '';
+        position: absolute;
+        bottom: 0;
+        right: 0.375rem;
+        width: calc( 100% - 0.75rem);
+        height: 0;
+        border-top: 2rpx dashed #eee;
+      }
+    }
+    .use {
+      background: #FFF;
+      padding: 20rpx;
+      box-sizing: border-box;
+      display: flex;
+      justify-content: flex-end;
+      font-size: .85em ;
+      -webkit-mask: radial-gradient(circle at 0.375rem 0%, #0000 0.375rem, red 0) -0.375rem;
+      .btn {
+        margin: 0;
+        position: relative;
+        border: 0;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        box-sizing: border-box;
+        text-align: center;
+        text-decoration: none;
+        white-space: nowrap;
+        vertical-align: baseline;
+        transform: translate(0, 0);
+        padding: 0 0.5rem;
+        height: 1.5625rem;
+        width: 200rpx;
+        border-radius: 1.25rem;
+        background: linear-gradient(90deg, #ff3000, rgba(255, 48, 0, 0.6));
+        color: #ffffff;
+        font-size: 0.75rem;
+        font-weight: 400;
+        &.disabled {
+          background: rgba(130, 130, 130, 0.5);
+        }
+      }
+    }
+    .item {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 20rpx;
+      .name {
+        font-weight: bolder;
+        font-size: 36rpx;
+      }
+      .price {
+        color: #f30;
+        font-size: 54rpx;
+      }
+      .desc {
+        color: #999;
+        font-size: 24rpx;
+      }
+      
+    }
+  }
+}
+</style>

+ 159 - 0
pagesA/integral/index.vue

@@ -0,0 +1,159 @@
+<template>
+  <layout-page>
+    <view class="box defaultBgc">
+      <scroll-view class="scrollBox" scroll-y="true" @scrolltolower="loadingMore">
+        <view>
+          <view class="panel">
+            <view>
+              <uni-icons color="#f30" type="icon-renminbi1688" size="16" custom-prefix="iconfont"></uni-icons>
+              <text class="text">{{ balance.point }}</text>
+            </view>
+            <view>
+              <button class="btn" @tap="handleUse">使用积分</button>
+            </view>
+          </view>
+          <view class="list">
+            <uni-list>
+              <uni-list-item
+                v-for="item in items"
+                :key="item.id"
+                :title="item.description"
+                :rightText="item._createTime"
+              />
+            </uni-list>
+            <uni-load-more :status="more" />
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+  </layout-page>
+</template>
+<!-- balance 余额 -->
+<script setup>
+import { ref } from 'vue'
+import {
+  getUserAccount,
+  getEnterpriseAccountRecordPage
+} from '@/api/sign'
+import { timesTampChange } from '@/utils/date'
+
+const balance = ref({})
+
+const items = ref([])
+const pageInfo = ref({
+  pageNo: 1,
+  pageSize: 20
+})
+const total = ref(0)
+const more = ref('more')
+
+getBalance()
+getList()
+// 获取积分余额
+async function getBalance() {
+  const { data } = await getUserAccount()
+  if (!data) {
+    return
+  }
+  balance.value = data
+}
+
+async function getList () {
+  try {
+    const { data } = await getEnterpriseAccountRecordPage({ ...pageInfo.value, type: 0 })
+    if (!data || !data.list) {
+      if (pageInfo.value.pageNo === 1) {
+        return
+      }
+      pageInfo.value.pageNo--
+      more.value = 'more'
+      return
+    }
+    const _data = data.list.map(e => {
+      return {
+        ...e,
+        _createTime: timesTampChange(e.createTime)
+      }
+    })
+    items.value.push(..._data)
+    total.value = +data.total
+    more.value = total.value <= items.value.length ? 'noMore' : 'more'
+  } catch (error) {
+    if (pageInfo.value.pageNo === 1) {
+      return
+    }
+    pageInfo.value.pageNo--
+    more.value = 'more'
+  }
+}
+function loadingMore () {
+  if (more.value === 'noMore') {
+    return
+  }
+  more.value = 'loading'
+  pageInfo.value.pageNo++
+  getList()
+}
+
+function handleUse () {
+  wx.navigateToMiniProgram({  
+    appId: 'wx6decdf12f9e7a061', // 目标小程序的 appId
+    // envVersion: 'develop',
+    success(res) {  
+        // 打开成功  
+        console.log('成功跳转至小程序:', res);  
+    },  
+    fail(err) {  
+        // 打开失败
+        uni.showToast({
+          title: '打开商城失败',
+          icon: 'none'
+        })
+    }  
+  })
+}
+
+</script>
+
+<style lang="scss" scoped>
+.box {
+  height: 100vh;
+}
+.scrollBox {
+  width: 100vw;
+  // padding: 20rpx;
+  box-sizing: border-box;
+  .panel {
+    position: sticky;
+    z-index: 2;
+    top: 0;
+    width: 100%;
+    padding: 20rpx;
+    margin-bottom: 20rpx;
+    box-sizing: border-box;
+    background: #FFF;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-end;
+    box-shadow: 0px 0px 10px 0px rgb(0, 0, 0, 0.25);
+    .text {
+      color: #F30;
+      font-size: 54rpx;
+
+    }
+    .btn {
+      width: 180rpx;
+      height: 60rpx;
+      line-height: 60rpx;
+      font-size: 28rpx;
+      text-align: center;
+      background: #00897B;
+      color: #FFF;
+      border-radius: 30rpx;
+    }
+  }
+  .list {
+    // padding: 20rpx;
+  }
+}
+</style>

+ 12 - 0
pagesA/resumeOnline/baseInfoEdit.vue

@@ -0,0 +1,12 @@
+<template>
+  <Info></Info>
+</template>
+
+<script setup>
+import Info from '@/pagesA/info/index'
+
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 95 - 0
pagesA/resumeOnline/dict.js

@@ -0,0 +1,95 @@
+import { reactive } from 'vue'
+import { getDict } from '@/hooks/useDictionaries'
+
+const dictObj = reactive({})
+const dictList = [
+  { 
+    type: 'positionData', 
+    apiType: 'positionData', 
+    key: 'positionId', 
+    label: 'position', 
+    value: 'positionTypeData', 
+    itemKey: 'id', 
+    itemText: 'nameCn'
+  },
+  { 
+    type: 'industryList', 
+    apiType: 'industryList', 
+    key: 'industryIdList', 
+    label: 'industry', 
+    isArray: true, 
+    value: 'industryTypeData', 
+    itemKey: 'id', 
+    itemText: 'nameCn' 
+  },
+  { 
+    type: 'menduner_area_type',
+    apiType: 'areaList',
+    key: 'workAreaId',
+    params: { type: undefined },
+    label: 'workArea',
+    value: 'areaTypeData',
+    itemKey: 'id',
+    itemText: 'name'
+  },
+  { 
+    type: 'menduner_job_type',
+    key: 'jobType',
+    label: 'jobTypeName',
+    value: 'jobTypeData',
+    itemKey: 'value',
+    itemText: 'label'
+  },
+  { 
+    type: 'menduner_area_type', 
+    apiType: 'areaList', 
+    key: 'interestedAreaIdList', 
+    label: 'interestedArea', 
+    params: { type: undefined },
+    isArray: true, 
+    value: 'areaTypeData', 
+    itemKey: 'id', 
+    itemText: 'name' 
+  }
+]
+
+// 字典
+const getDictList = async () => {
+  dictList.forEach(async (val) => {
+    const { data } = await getDict(val.type, val.params, val.apiType)
+    console.log(val.type, val.params, val.apiType,data)
+    if (!data?.data) {
+      dictObj[val.value] = []
+      return
+    }
+    dictObj[val.value] = data.data
+  })
+}
+
+const getData = async () => {
+  await getDictList()
+}
+getData()
+
+export const dealJobData = (list) => {
+  let res = {}
+  dictList.forEach(item => {
+    res = list.map(e => {
+      let obj = {}
+      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)
+          })
+          e[item.label] = result && result.length ? result.filter(Boolean) : []
+        }
+      } else {
+        obj = dictObj[item.value].find(k => Number(k[item.itemKey]) === Number(e[item.key]))
+        if (!obj) return
+        e[item.label] = obj[item.itemText]
+      }
+      return e
+    })
+  })
+  return res
+}

+ 609 - 0
pagesA/resumeOnline/index.vue

@@ -0,0 +1,609 @@
+<template>
+  <layout-page>
+    <view class="baseInfo borderLine" @tap="handleTo('baseInfoEdit')">
+      <view>
+        <view class="baseInfo-name">
+          <text class="name title">{{ baseInfo.name }}</text>
+          <uni-icons
+            type="icon-Edit"
+            color="#333"
+            custom-prefix="iconfont"
+            size="20"
+          ></uni-icons>
+        </view>
+        <view class="baseInfo-desc">{{ baseInfo.jobStatusText }}</view>
+        <view class="baseInfo-desc">{{ baseInfo.expTypeText }} - {{ baseInfo.age }}岁 - {{ baseInfo.eduTypeText }}</view>
+        <view class="baseInfo-phone">
+          <uni-icons
+            type="icon-Phone"
+            color="#999"
+            custom-prefix="iconfont"
+            size="14"
+          ></uni-icons>
+          <text class="number">{{ baseInfo.phone }}</text>
+        </view>
+      </view>
+      <view class="head">
+        <image
+          :src="baseInfo.avatar"
+          mode="scaleToFill"
+        />
+      </view>
+    </view>
+    <view class="characteristic borderLine">
+      <view class="titleBox">
+        <text class="title">个人画像</text>
+        <uni-icons
+          type="icon-Edit"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="tags">
+        <view
+          v-for="tag in baseInfo.tagList"
+          :key="tag"
+          class="tag"
+        >
+          {{ tag }}
+        </view>
+      </view>
+    </view>
+    <view class="advantage borderLine">
+      <view class="titleBox">
+        <text class="title">个人优势</text>
+        <uni-icons
+          type="icon-Edit"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </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>
+        <uni-icons
+          type="icon-add"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="content">
+        <view class="text" v-if="!intention.length">请填写您的求职意向...</view>
+        <uni-list :border="false">
+          <uni-list-item
+            v-for="int in intention"
+            :key="int.id"
+            :border="false"
+            showArrow
+          >
+            <template v-slot:body>
+              <view class="item">
+                <view class="item-title">{{ int.jobTypeName}}</view>
+                <view>
+                  <text class="mr-20">{{ int.position}}</text>
+                  <text>{{ int.payFrom }} {{ int.payFrom  && int.payTo ? '-' : ''}} {{ int.payTo}}</text>
+                </view>
+                <view>{{ int.workArea }}</view>
+                <view class="item-tags">
+                  <view v-for="industry in int.industry" :key="industry.id" class="tag">{{ industry.nameCn }}</view>
+                </view>
+              </view>
+            </template>
+          </uni-list-item>
+        </uni-list>
+      </view>
+    </view>
+    <view class="educationExp borderLine">
+      <view class="titleBox">
+        <text class="title">教育经历</text>
+        <uni-icons
+          type="icon-add"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="content">
+        <view class="text" v-if="!educationExp.length">请填写您的教育经历...</view>
+        <uni-list :border="false">
+          <uni-list-item
+            v-for="education in educationExp"
+            :key="education.id"
+            showArrow
+            :border="false"
+            :title="education.schoolName"
+            :note="`${education.major} ${education.educationTypeText}`"
+            :rightText="education.time"
+          />
+        </uni-list>
+      </view>
+    </view>
+    <view class="workExp borderLine">
+      <view class="titleBox">
+        <text class="title">工作经历</text>
+        <uni-icons
+          type="icon-add"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="content">
+        <view
+          v-for="work in workExp"
+          :key="work.id"
+          class="content-item"
+        >
+          <view class="content-title">
+            <view class="name">{{ work.enterpriseName }}</view>
+            <view class="time">
+              {{ work.time }}
+              <uni-icons
+                class="icon"
+                type="right"
+                color="#aaa"
+                size="16"
+              />
+            </view>
+          </view>
+          <view class="content-subTitle">{{ work.positionName }}</view>
+          <view class="content-main ellipsis-2">内容:{{ work.content }}</view>
+        </view>
+      </view>
+    </view>
+    <view class="projectExp workExp borderLine">
+      <view class="titleBox">
+        <text class="title">项目经历</text>
+        <uni-icons
+          type="icon-add"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="content">
+        <view
+          v-for="project in projectExp"
+          :key="project.id"
+          class="content-item"
+        >
+          <view class="content-title">
+            <view class="name">{{ project.name }}</view>
+            <view class="time">
+              {{ project.time }}
+              <uni-icons
+                class="icon"
+                type="right"
+                color="#aaa"
+                size="16"
+              />
+            </view>
+          </view>
+          <view class="content-main ellipsis-2">描述:{{ project.content }}</view>
+        </view>
+      </view>
+    </view>
+    <view class="workExp trainExp borderLine">
+      <view class="titleBox">
+        <text class="title">培训经历</text>
+        <uni-icons
+          type="icon-add"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="content">
+        <view
+          v-for="train in trainExp"
+          :key="train.id"
+          class="content-item"
+        >
+          <view class="content-title">
+            <view class="name">{{ train.orgName }}</view>
+            <view class="time">
+              {{ train.time }}
+              <uni-icons
+                class="icon"
+                type="right"
+                color="#aaa"
+                size="16"
+              />
+            </view>
+          </view>
+          <view class="content-subTitle">课程:{{ train.course }}</view>
+          <view class="content-main ellipsis-2">描述:{{ train.content }}</view>
+        </view>
+      </view>
+    </view>
+    <view class="characteristic">
+      <view class="titleBox">
+        <text class="title">职业技能</text>
+        <uni-icons
+          type="icon-Edit"
+          color="#666"
+          custom-prefix="iconfont"
+          size="18"
+        ></uni-icons>
+      </view>
+      <view class="tags">
+        <view
+          v-for="skill in skillExp"
+          :key="skill.title"
+          class="tag"
+        >
+          {{ skill.title }}
+        </view>
+      </view>
+    </view>
+  </layout-page>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { getAgeByBirthdayTimestamp, timesTampChange } from '@/utils/date'
+import {
+  getResumeJobInterested,
+  getResumeEduExp,
+  getResumeWorkExp,
+  getResumeProjectExp,
+  getResumeTrainExp,
+  getResumePersonSkill
+} from '@/api/resume'
+import { getText } from '@/utils/getText'
+import { getDict } from '@/hooks/useDictionaries'
+import { userStore } from '@/store/user'
+import { dealJobData } from './dict'
+
+const useUserStore = userStore()
+
+const baseInfo = ref({})
+const intention = ref([])
+const educationExp = ref([])
+const workExp = ref([])
+const projectExp = ref([])
+const trainExp = ref([])
+const skillExp = ref([])
+
+function handleTo (str) {
+  uni.navigateTo({ url: `/pagesA/resumeOnline/${str}` })
+}
+
+
+
+
+// 获取基础信息
+function getBaseInfo () {
+  const { name, phone, ...obj } = useUserStore.baseInfo
+  baseInfo.value = {
+    ...obj,
+    name: name ? name : useUserStore.userInfo.phone,
+    phone: phone ? phone : useUserStore.userInfo.phone,
+    age: obj.birthday ? getAgeByBirthdayTimestamp(obj.birthday) : 0
+  }
+}
+
+// 获取求职意向
+async function getJobInterested () {
+  const { data } = await getResumeJobInterested()
+  if (!data || !data.length) {
+    return
+  }
+  // 完成度展示
+  // emit('complete', { status: Boolean(data?.length), id: 'jobIntention' })
+  // if (!data.length) return
+  intention.value = dealJobData(data)
+}
+
+// 获取教育经历
+async function getEduExp () {
+  const { data: dict } = await getDict('menduner_education_type')
+  if (dict.code !== 0) {
+    return
+  }
+  const { data } = await getResumeEduExp()
+  if (!data || !data.length) {
+    return
+  }
+  educationExp.value = data.map(e => {
+    const item = dict.data.find(_e => _e.value === e.educationType)
+    return {
+      ...e,
+      educationTypeText: item?.label ?? '',
+      time: `${timesTampChange(e.startTime ,'Y')}-${timesTampChange(e.endTime ,'Y')} `
+    }
+  })
+  // 完成度展示
+  // emit('complete', { status: Boolean(data?.length), id: 'educationExp' })
+  // dataList.value = data
+}
+
+// 获取工作经验
+async function getWorkExp () {
+  const { data } = await getResumeWorkExp()
+  if (!data || !data.length) {
+    return
+  }
+  // console.log(data)
+  // 完成度展示
+  // emit('complete', { status: Boolean(data?.length), id: 'workExperience' })
+  workExp.value = data.map(e => {
+    return {
+      ...e,
+      time: `${timesTampChange(e.startTime ,'Y')}-${e.endTime ? timesTampChange(e.endTime ,'Y') : '至今'} `
+    }
+  })
+}
+
+// 项目经历
+async function getProjectExpData () {
+  const { data } = await getResumeProjectExp()
+  if (!data || !data.length) {
+    return
+  }
+  // 完成度展示
+  // emit('complete', { status: Boolean(data?.length), id: 'projectExperience' })
+  projectExp.value = data.map(e => {
+    return {
+      ...e,
+      time: `${timesTampChange(e.startTime ,'Y')}-${e.endTime ? timesTampChange(e.endTime ,'Y') : '至今'} `
+    }
+  })
+}
+
+// 培训经历
+async function getTrainExpData () {
+  const { data } = await getResumeTrainExp()
+  if (!data || !data.length) {
+    return
+  }
+  // 完成度展示
+  // emit('complete', { status: Boolean(data?.length), id: 'trainingExperience' })
+  trainExp.value = data.map(e => {
+    return {
+      ...e,
+      time: `${timesTampChange(e.startTime ,'Y')}-${e.endTime ? timesTampChange(e.endTime ,'Y') : '至今'} `
+    }
+  })
+}
+
+// 职业技能
+async function getSkillExpData () {
+  const { data: _skillList} = await getDict('skillList', {}, 'skillList')
+  const skillList = _skillList?.data
+  if (!skillList || !skillList.length) {
+    return
+  }
+
+  const { data: _skillLevelArr } = await getDict('menduner_skill_level')
+  const skillLevelArr = _skillLevelArr?.data
+  if (!skillLevelArr || !skillLevelArr.length) {
+    return
+  }
+
+  const { data } = await getResumePersonSkill()
+  if (!data || !data.length) {
+    return
+  }
+  // 完成度展示
+  // emit('complete', { status: Boolean(data?.length), id: 'vocationalSkills' })
+  skillExp.value = data.map(e => {
+    return {
+      ...e,
+      title: `${getText(e.skillId, skillList, 'nameCn', 'id')} / ${getText(e.level, skillLevelArr)}`
+    }
+  })
+}
+
+// 求职状态字典
+// getJobStatus()
+// 获取基础信息
+getBaseInfo()
+// 获取求职意向
+getJobInterested()
+// 获取教育经历
+getEduExp()
+// 获取工作经验
+getWorkExp()
+// 项目经历
+getProjectExpData()
+// 培训经历
+getTrainExpData()
+// 职业技能
+getSkillExpData()
+</script>
+
+<style lang="scss" scoped>
+$px: 30rpx;
+.borderLine {
+  border-bottom: 2rpx solid #f5f5f5;
+}
+.title {
+  font-size: 40rpx;
+  font-weight: 600;
+}
+.flex-1 {
+  flex: 1;
+}
+.soloHeight {
+  height: 80rpx;
+  line-height: 80rpx;
+}
+.px-20 {
+  padding-left: 20rpx;
+  padding-right: 20rpx;
+  box-sizing: border-box;
+}
+.mr-20 {
+  margin-right: 20rpx;
+}
+.ellipsis-2 {
+  overflow: hidden;
+  display: -webkit-box;
+  text-overflow: ellipsis; //属性规定当文本溢出包含元素时发生的事情  text-overflow: clip|ellipsis|string; (修剪/省略号/指定字符串)
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical; //属性规定框的子元素应该被水平或垂直排列
+}
+.titleBox {
+  margin-bottom: 10rpx;
+  display: flex;
+  justify-content: space-between;
+}
+.text {
+  font-size: 28rpx;
+  color: #666;
+}
+.baseInfo {
+  padding: 20rpx $px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  &-name {
+    margin-bottom: 10rpx;
+    .name {
+      margin-right: 10rpx;
+    }
+  }
+  &-desc {
+    font-size: 28rpx;
+    color: #666;
+    margin-bottom: 10rpx;
+  }
+  &-phone {
+    font-size: 28rpx;
+    color: #666;
+    .number {
+      margin-left: 10rpx;
+    }
+  }
+  .head {
+    image {
+      width: 150rpx;
+      height: 150rpx;
+      border: 2rpx solid #ccc;
+      border-radius: 50%;
+    }
+  }
+}
+.advantage {
+  padding: $px;
+}
+
+.characteristic {
+  padding: $px;
+  .tags {
+    padding-top: $px;
+    display: flex;
+    flex-wrap: wrap;
+    .tag {
+      margin: 0 10rpx 10rpx 0;
+      border: 2rpx solid #008978;
+      color: #008978;
+      white-space: nowrap;
+      padding: 4rpx 10rpx;
+      border-radius: 10rpx;
+      font-size: 24rpx;
+    }
+  }
+}
+.intention,.educationExp,.workExp,.projectExp {
+  padding: $px;
+}
+.workExp {
+  .content {
+    &-item {
+      padding: $px 20rpx;
+    }
+    &-title {
+      display: flex;
+      justify-content: space-between;
+      .name {
+        // font-weight: 600;
+        font-size: 30rpx;
+        color: #333;
+      }
+      .time {
+        color: #999;
+        font-size: 24rpx;
+        display: flex;
+        align-items: center;
+        .icon {
+          margin-left: 20rpx;
+        }
+      }
+    }
+    &-subTitle {
+      font-size: 24rpx;
+      margin-top: 6rpx;
+      color: #999;
+    }
+    &-main {
+      margin-top: 20rpx;
+      font-size: 24rpx;
+      color: #999;
+    }
+  }
+}
+.intention {
+  .content {
+    .item {
+      font-size: 28rpx;
+      color: #666;
+      &-title {
+        color: #000;
+        font-weight: 600;
+      }
+      &-tags {
+        display: flex;
+        .tag {
+          border: 2rpx solid #008978;
+          color: #008978;
+          padding: 4rpx 16rpx;
+          font-size: 24rpx;
+          margin: 10rpx 10rpx 0 0;
+          border-radius: 10rpx;
+        }
+      }
+    }
+  }
+}
+
+
+.popup {
+  padding: $px;
+  padding-bottom: 100rpx;
+  &-title {
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: $px;
+    font-size: 24rpx;
+    .title {
+      font-size: 36rpx;
+    }
+  }
+  &-content {
+    .box {
+      display: flex;
+      justify-content: space-between;
+      border-bottom: 2rpx solid #eee;
+      padding: $px 0;
+      font-size: 30rpx;
+      font-weight: 500;
+      color: #000;
+      &:last-of-type {
+        border-bottom: none;
+      }
+      &.active {
+        color: #008978;
+        font-weight: 600;
+      }
+    }
+  }
+}
+</style>

+ 1 - 1
pagesB/positionDetail/index.vue

@@ -231,7 +231,7 @@ const poster = ref()
 
 let jobId = ''
 onLoad((options) => {
-  console.log(options)  
+  // console.log(options)  
   // 是否是众聘
   if (options.sharedById) {
     isEmployment.value = options.sharedById

BIN
static/iconfont.ttf


+ 12 - 0
static/iconfont.wxss

@@ -11,6 +11,18 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-add:before {
+  content: "\e633";
+}
+
+.icon-Edit:before {
+  content: "\e616";
+}
+
+.icon-Phone:before {
+  content: "\e89a";
+}
+
 .icon-renminbi1688:before {
   content: "\e6cb";
 }

BIN
static/img/gold.png


BIN
static/img/ticket.png


+ 48 - 10
store/user.js

@@ -3,6 +3,8 @@ import { clone, cloneDeep } from 'lodash-es';
 import { getBaseInfo, getUserInfo } from '@/api/user';
 import { smsLogin, passwordLogin, logout, userRegister } from '@/api/common'
 import { closeAuthModal } from '@/hooks/useModal'
+import { timesTampChange } from '@/utils/date'
+import { getBaseInfoDictOfName } from '@/utils/getText'
 
 // 默认用户信息
 const defaultBaseInfo = {
@@ -27,17 +29,20 @@ const tabUrl = [
   'pages/index/communicate',
   'pages/index/my'
 ]
-
 export const userStore = defineStore({
   id: 'user',
-  state: () => ({
-    baseInfo: {}, // 用户信息
-    userInfo: {},
-    isLogin: !!uni.getStorageSync('token'), // 登录状态
-    refreshToken: uni.getStorageSync('refresh-token'), // 用户切换
-    lastUpdateTime: 0, // 上次更新时间
-    accountInfo: cloneDeep(defaultAccountInfo), // 账号信息
-  }),
+  state: () => {
+    const userInfo = JSON.parse(uni.getStorageSync('user') ?? '{}')
+    console.log('userInfo====',userInfo)
+    return {
+      baseInfo: userInfo ? userInfo.baseInfo : {}, // 用户信息
+      userInfo: userInfo ? userInfo.userInfo : {},
+      isLogin: !!uni.getStorageSync('token'), // 登录状态
+      refreshToken: uni.getStorageSync('refresh-token'), // 用户切换
+      lastUpdateTime: 0, // 上次更新时间
+      accountInfo: cloneDeep(defaultAccountInfo), // 账号信息
+    }
+  },
 
   actions: {
     setLogin (val) {
@@ -90,7 +95,8 @@ export const userStore = defineStore({
       if (code !== 0) {
         return;
       }
-      this.baseInfo = data;
+      const _data = await this.getFieldText(data)
+      this.baseInfo = _data
       return Promise.resolve(data);
     },
     // 获取用户信息
@@ -157,6 +163,38 @@ export const userStore = defineStore({
       this.resetUserData();
       return !this.isLogin;
     },
+    // 字典对应中文
+    async getFieldText (data) {
+      if (data.birthday && data.birthday !== 0) {
+        data.birthdayText = timesTampChange(data.birthday, 'Y-M-D') // 出生日期
+      }
+      if (data.firstWorkTime && data.firstWorkTime !== 0) {
+        data.firstWorkTimeText = timesTampChange(data.firstWorkTime, 'Y-M-D') // 首次工作时间
+      }
+      if (data.areaId && data.areaId !== 0) {
+        await getBaseInfoDictOfName(0, data, data.areaId, 'areaName') // 现居住地text
+        await getBaseInfoDictOfName(0, data, data.regId, 'regName') // 户籍地text
+      }
+      if (data.eduType && data.eduType !== 0) {
+        await getBaseInfoDictOfName(1, data, data.eduType, 'eduTypeText') // 学历
+      }
+      if (data.expType && data.expType !== 0) {
+        await getBaseInfoDictOfName(2, data, data.expType, 'expTypeText') // 工作经验
+      }
+      if (data.sex && data.sex !== 0) {
+        await getBaseInfoDictOfName(3, data, data.sex, 'sexTypeText') // 性别
+      }
+      if (data.jobType && data.jobType !== 0) {
+        await getBaseInfoDictOfName(4, data, data.jobType, 'jobTypeText') // 求职类型
+      }
+      if (data.jobStatus && data.jobStatus !== 0) {
+        await getBaseInfoDictOfName(5, data, data.jobStatus, 'jobStatusText') // 	求职状态
+      }
+      if (data.maritalStatus && data.maritalStatus !== 0) {
+        await getBaseInfoDictOfName(6, data, data.maritalStatus, 'maritalText') // 	婚姻状况
+      }
+      return data
+    }
   },
   persist: {
     // enabled: true,

+ 8 - 0
utils/date.js

@@ -16,4 +16,12 @@ export const timesTampChange = (timestamp, format = 'Y-M-D h:m:s') => {
   if (!formattedDate) formattedDate = Y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s
 
   return formattedDate
+}
+
+// 根据生日时间戳计算年龄
+export const getAgeByBirthdayTimestamp = (timestamp) => {
+  const now = new Date()
+  const birthday = new Date(timestamp)
+  const age = now.getFullYear() - birthday.getFullYear()
+  return age
 }

+ 57 - 0
utils/getText.js

@@ -0,0 +1,57 @@
+import { getDict } from '@/hooks/useDictionaries'
+
+export const getText = (value, arr, itemText = 'label', itemValue = 'value') => { // 一维数组
+  // console.log('getText', value, arr)
+  if (!arr?.length || !(value && value !== 0)) return
+  const item = arr.find(formItem => formItem[itemValue] === value)
+  if (!item) return
+  return item[itemText]
+}
+
+export const getBaseInfoDictOfName = async (index = 0, baseInfo, value, addKeyName) => { // 一维数组
+  const test = [
+    { dictType: 'menduner_area_type', itemText: 'name', itemValue: 'id', saveType: 'areaList' },
+    { dictType: 'menduner_education_type', itemText: 'label', itemValue: 'value' },
+    { dictType: 'menduner_exp_type', itemText: 'label', itemValue: 'value' },
+    { dictType: 'menduner_sex', itemText: 'label', itemValue: 'value' },
+    { dictType: 'menduner_job_type', itemText: 'label', itemValue: 'value' },
+    { dictType: 'menduner_job_status', itemText: 'label', itemValue: 'value' },
+    { dictType: 'menduner_marital_status', itemText: 'label', itemValue: 'value' },
+  ]
+  const e = test[index]
+
+  if (!value && value !== 0 && !e) baseInfo[addKeyName] = '暂无'
+  const params = e.saveType === 'areaList' ? {} : null
+  const { data } = await getDict(e.dictType, params, (e.saveType || 'dict'))
+  if (data.code !== 0) {
+    return
+  }
+  const item = data.data.find(formItem => Number(formItem[e.itemValue]) === Number(value))
+  baseInfo[addKeyName] = item ? item[e.itemText] : '暂无'
+}
+
+// export const getBaseInfoDictOfName1 = async (baseInfo, value, addKey, itemText = 'name', itemValue = 'id') => { // 一维数组
+//   if (!value && value !== 0) baseInfo[addKey] = '暂无'
+//   const { data } = await getDict('menduner_area_type', {}, 'areaList')
+//   const item = data.find(formItem => Number(formItem[itemValue]) === Number(value))
+//   baseInfo[addKey] = item ? item[itemText] : '暂无'
+// }
+
+export const dealCanBeInputtedValueAndLabel = (formItem, data) => {
+  if (!formItem.key || !formItem.itemTextName) return
+  //
+  formItem.value = data[formItem.key] || data[formItem.itemTextName]
+  formItem[formItem.itemTextName] = data[formItem.itemTextName]
+  if (data[formItem.key] && data[formItem.itemTextName]) {
+    formItem.search(data[formItem.itemTextName]) // 存在id的情况下->回显下拉框列表
+  }
+  // if (data[formItem.key] && data[formItem.itemTextName]) {
+  //   formItem.items = [{ [formItem.itemText]: data[formItem.itemTextName], [formItem.itemValue]: data[formItem.key] }] // 存在id的情况下->回显下拉框
+  // }
+}
+export const dealCanBeInputtedSave = (formItem, params) => {
+  if (formItem.value === formItem[formItem.itemTextName]) {
+    params[formItem.key] = null; params[formItem.itemTextName] = formItem[formItem.itemTextName]
+  }
+  else { params[formItem.key] = formItem.value; params[formItem.itemTextName] = formItem[formItem.itemTextName] }
+}