item.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <template>
  2. <view>
  3. <view v-for="(val, index) in items" :key="index" class="mList default-border">
  4. <!-- 基本信息 -->
  5. <view class="d-flex align-center">
  6. <view class="user-avatar">
  7. <image class="user-avatar-img" :src="getUserAvatar(val.person?.avatar, val.person?.sex)" mode="scaleToFill"></image>
  8. <image class="user-avatar-sex" :src="val?.person?.sex ? val?.person?.sex === '1' ? '/static/img/man.png' : '/static/img/female.png' : ''" alt="" mode="scaleToFill" />
  9. </view>
  10. <view style="flex: 1; margin-left: 10px;">
  11. <view class="d-flex justify-space-between align-center">
  12. <view class="font-size-18 default-text-color">{{ val.person?.name }}</view>
  13. <view :style="{'color': colorData[val.status]}">
  14. {{ val.status ? statusList.find(i => i.value === val.status)?.label : '' }}
  15. </view>
  16. </view>
  17. </view>
  18. </view>
  19. <view class="ss-m-t-15 color-999">
  20. <view>
  21. 投递职位:
  22. <image v-if="val.jobFairId" src="/static/svg/jobFair.svg" style="width: 15px; height: 15px;"></image>
  23. {{ formatName(val.job?.name) }}
  24. </view>
  25. <view>联系电话:{{ val.person?.phone ?? '未填写' }}</view>
  26. <view>面试时间:{{ timesTampChange(val.time, 'Y-M-D h:m') }}</view>
  27. <view v-if="val.status === '4'">反馈内容:{{ val.evaluate }}</view>
  28. <view v-if="val.status === '5' || val.status === '99'">{{ val.status === '5' ? '爽约' : '取消' }}原因:{{ val.reason }}</view>
  29. </view>
  30. <view class="sub-li-bottom ss-m-t-20">
  31. <template v-if="val.job?.status !== '1'" >
  32. <view v-if="editStatus.indexOf(val.status) !== -1" class="sub-li-bottom-item color-primary" @tap.stop="handleActionClick('edit', val)">修改面试</view>
  33. <view v-if="againStatus.indexOf(val.status) !== -1" class="sub-li-bottom-item color-primary" @tap.stop="handleActionClick('edit', val)">重新邀约</view>
  34. </template>
  35. <view v-if="val.status === '1'" class="sub-li-bottom-item color-primary" @click="handleActionClick('completed', val)">完成面试</view>
  36. <view v-if="val.status === '3'" class="sub-li-bottom-item color-primary" @click="handleActionClick('feedback', val)">填写反馈</view>
  37. <view
  38. class="sub-li-bottom-item d-flex align-center justify-center"
  39. @tap.stop="handleLoadMore(val)"
  40. :style="{'color': val?.job?.status === '1' || !actionItems(val)?.length ? '#ccc' : '#00B760'}"
  41. >
  42. <view>更多操作</view>
  43. <uni-icons type="list" class="ss-m-l-10" size="20" :color="val?.job?.status === '1' || !actionItems(val)?.length ? '#ccc' : '#00B760'"></uni-icons>
  44. </view>
  45. </view>
  46. </view>
  47. <!-- 更多操作 -->
  48. <uni-popup ref="popup" type="bottom" :mask-click="true">
  49. <view class="actions" v-if="itemData && Object.keys(itemData).length">
  50. <view
  51. class="action-item"
  52. v-for="(val, index) in actionItems(itemData)"
  53. :key="index"
  54. @tap.stop="handleActionClick(val.value, itemData)"
  55. >{{ val.title }}</view>
  56. </view>
  57. <button class="big-cancel-button" @tap.stop="handleClosePopup">取消</button>
  58. </uni-popup>
  59. <!-- 完成面试 -->
  60. <uni-popup ref="finishPopup" type="dialog">
  61. <uni-popup-dialog
  62. type="warn"
  63. cancelText="取消"
  64. confirmText="确定"
  65. title="系统提示"
  66. content="是否确认已完成面试?"
  67. @confirm="handleFinishConfirm"
  68. @close="handleFinishClose"
  69. ></uni-popup-dialog>
  70. </uni-popup>
  71. </view>
  72. </template>
  73. <script setup>
  74. import { ref } from 'vue'
  75. import { timesTampChange } from '@/utils/date'
  76. import { getUserAvatar } from '@/utils/avatar'
  77. import { formatName } from '@/utils/getText'
  78. import { completedInterviewInvite } from '@/api/interview'
  79. const emit = defineEmits(['refresh'])
  80. const props = defineProps({ items: Array, current: [Number, String], statusList: Array })
  81. const editStatus = ['0'] // 修改面试状态
  82. const againStatus = ['98', '99'] // 重新邀约状态
  83. const colorData = {
  84. '0': 'orange',
  85. '1': 'green',
  86. '2': 'green',
  87. '3': '#00B760',
  88. '4': '#999',
  89. '5': '#FE574A',
  90. '98': '#FE574A',
  91. '99': '#999'
  92. }
  93. const popup = ref()
  94. const finishPopup = ref()
  95. const itemData = ref({})
  96. // 更多操作
  97. const handleLoadMore = (val) => {
  98. if (val?.job?.status === '1') {
  99. itemData.value = {}
  100. uni.showToast({ title: '职位已关闭,暂无更多操作', icon: 'none' })
  101. return
  102. }
  103. if (!actionItems(val).length) {
  104. itemData.value = {}
  105. uni.showToast({ title: '暂无更多操作', icon: 'none' })
  106. return
  107. }
  108. itemData.value = val
  109. popup.value.open()
  110. }
  111. // 关闭操作弹窗
  112. const handleClosePopup = () => {
  113. popup.value.close()
  114. itemData.value = {}
  115. }
  116. // 完成面试
  117. const handleFinishClose = () => {
  118. if (actionItems(itemData.value).length && actionItems(itemData.value).find(e => e.value === 'completed')) handleClosePopup()
  119. else itemData.value = {}
  120. finishPopup.value.close()
  121. }
  122. const handleFinishConfirm = async () => {
  123. if (!itemData.value || !itemData.value.id) return
  124. try {
  125. await completedInterviewInvite(itemData.value.id)
  126. uni.showToast({ title: '操作成功', icon: 'none' })
  127. emit('refresh')
  128. handleFinishClose()
  129. } catch {
  130. handleFinishClose()
  131. }
  132. }
  133. const handleActionClick = (type, val) => {
  134. if (val.job?.status === '1' && (type !== 'completed')) {
  135. uni.showToast({ title: '职位已关闭', icon: 'none' })
  136. return
  137. }
  138. itemData.value = val
  139. // 完成面试
  140. if (type === 'completed') {
  141. finishPopup.value.open()
  142. }
  143. // 修改面试、重新邀约
  144. if (type === 'edit') {
  145. uni.navigateTo({
  146. url: '/pagesB/InviteInterview/index?editData=' + encodeURIComponent(JSON.stringify(val))
  147. })
  148. }
  149. // 取消面试、爽约、面试反馈
  150. if (['cancel', 'attended', 'feedback'].includes(type)) {
  151. uni.navigateTo({
  152. url: `/pagesA/interview/${type}?id=${val.id}`
  153. })
  154. }
  155. popup.value.close()
  156. }
  157. const obj = {
  158. '0': [1],
  159. '1': [4, 1, 3],
  160. '2': [3]
  161. }
  162. const actions = ref([
  163. { title: '完成面试', value: 'completed' },
  164. { title: '取消面试', value: 'cancel' },
  165. { title: '填写反馈', value: 'feedback' },
  166. { title: '爽约', value: 'attended' },
  167. { title: '修改面试', value: 'edit' }
  168. ])
  169. const actionItems = (item) => {
  170. const status = item?.status
  171. const jobClosed = item.job?.status === '1'
  172. const type = jobClosed && obj[status] ? [0] : obj[status] // 职位已关闭只能操作完成面试
  173. if (!type || !type.length) return []
  174. let data = type.map(e => actions.value[e])
  175. return data
  176. }
  177. </script>
  178. <style scoped lang="scss">
  179. .mList {
  180. border-radius: 12px;
  181. box-shadow: 1px 2px 12px rgba(0, 0, 0, 0.17);
  182. margin: 0 30rpx 20rpx 30rpx;
  183. padding: 30rpx;
  184. background-color: #fbfbfb;
  185. font-size: 28rpx;
  186. &:first-child {
  187. margin-top: 20rpx;
  188. }
  189. }
  190. .user-avatar {
  191. position: relative;
  192. &-img {
  193. width: 45px;
  194. height: 45px;
  195. border-radius: 50%;
  196. }
  197. &-sex {
  198. position: absolute;
  199. right: 0;
  200. bottom: 2px;
  201. width: 20px;
  202. height: 20px;
  203. background-color: #fff;
  204. border-radius: 50%;
  205. }
  206. }
  207. .action {
  208. font-size: 28rpx;
  209. &-item {
  210. text-align: center;
  211. width: 90vw;
  212. border-bottom: 1px solid #eee;
  213. height:44px;
  214. line-height: 44px;
  215. margin: 0 auto;
  216. color: #00B760;
  217. background-color: #fff !important;
  218. &:first-child {
  219. border-radius: 5px 5px 0 0;
  220. }
  221. &:last-child {
  222. border-radius: 0 0 5px 5px;
  223. border-bottom: none;
  224. }
  225. }
  226. }
  227. .big-cancel-button {
  228. width: 90vw;
  229. height:44px;
  230. line-height: 44px;
  231. margin: 10px auto;
  232. color: #fe574a;
  233. background-color: #fff !important;
  234. font-size: 28rpx;
  235. }
  236. .sub-li-bottom {
  237. display: flex;
  238. justify-content: space-between;
  239. // align-items: flex-end;
  240. margin-top: 10px;
  241. font-size: 13px;
  242. &-item {
  243. width: 50%;
  244. height: 35px;
  245. line-height: 35px;
  246. text-align: center;
  247. margin-right: 15px;
  248. background-color: #f7f8fa;
  249. border-radius: 4px;
  250. &:nth-child(2) {
  251. margin-right: 0;
  252. }
  253. }
  254. }
  255. </style>