item.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <template>
  2. <div>
  3. <div v-if="props.items.length" class="d-flex align-center mb-1">
  4. <v-checkbox v-if="tab !== 3" v-model="selectAll" :label="!selectAll ? $t('common.selectAll') : `已选中${selectList.length}条`" hide-details color="primary" @update:model-value="handleChangeSelectAll"></v-checkbox>
  5. <div v-if="tab === 1" class="ml-8">
  6. <v-btn :disabled="!selectAll" color="primary" variant="tonal" size="small" @click="handleAction(2, 'batch', {})">一键刷新</v-btn>
  7. <v-btn class="mx-3" :disabled="!selectAll" color="primary" variant="tonal" size="small" @click="handleAction(3, 'top', {})">{{ $t('common.topping') }}</v-btn>
  8. <v-btn class="mr-3" :disabled="!selectAll" color="primary" variant="tonal" size="small" @click="handleAction(4, 'top', {})">取消置顶</v-btn>
  9. <v-btn :disabled="!selectAll" color="primary" variant="tonal" size="small" @click="handleAction(0, 'close', {})">{{ $t('common.close') }}</v-btn>
  10. </div>
  11. <v-btn v-if="tab === 2" class="ml-8" :disabled="!selectAll" color="primary" variant="tonal" size="small" @click="handleAction(1, 'activation', {})">一键激活</v-btn>
  12. </div>
  13. <div v-for="val in items" :key="val.id" class="itemBox mb-3" style="height: 134px;">
  14. <div v-if="val.top && tab === 1" style="position: absolute;">
  15. <svg-icon name="top" size="50"></svg-icon>
  16. </div>
  17. <div class="d-flex justify-space-between" style="padding: 10px 20px;">
  18. <div class="position">
  19. <div class="item-select ml-5" v-if="tab !== 3">
  20. <v-checkbox v-model="val.select" hide-details color="primary" @update:model-value="handleChangeSelect"></v-checkbox>
  21. </div>
  22. <div class="d-flex align-center" :class="{'cursor-pointer': tab === 1, 'ml-15': tab !== 3}" @click="handleEdit(val)">
  23. <span v-if="val.name.indexOf('style')" v-html="val.name" class="position-name"></span>
  24. <span v-else class="position-name">{{ val.name }}</span>
  25. </div>
  26. <div :class="['mt-3', 'other-info', 'ellipsis', 'ml-10']">
  27. <span>{{ val.areaName }}</span>
  28. <span class="lines" v-if="val.areaName && val.eduName"></span>
  29. <span>{{ val.eduName }}</span>
  30. <span class="lines"></span>
  31. <span>{{ val.expName }}</span>
  32. <span class="lines"></span>
  33. <span v-if="!val.payFrom && !val.payTo">面议</span>
  34. <span v-else>{{ val.payFrom ? val.payFrom + '-' : '' }}{{ val.payTo }}{{ val.payName ? '/' + val.payName : '' }}</span>
  35. <span class="lines" v-if="val.positionName"></span>
  36. <span>{{ val.positionName }}</span>
  37. </div>
  38. </div>
  39. <!-- <div class="d-flex align-center">
  40. <v-btn v-if="tab === 1" class="ml-3" color="primary" @click="handleAction(2, '', val)">
  41. <span>{{ $t('common.refresh') + $t('common.position') }}</span>
  42. <v-icon class="ml-2">mdi-help-circle-outline</v-icon>
  43. <v-tooltip activator="parent" location="top">刷新职位后,发布时间为最新的</v-tooltip>
  44. </v-btn>
  45. <v-btn v-if="tab === 2" color="primary" @click="handleAction(1, '', val)">{{ $t('common.activatePosition') }}</v-btn>
  46. </div> -->
  47. </div>
  48. <div class="bottom pa-5 d-flex justify-space-between align-center">
  49. <div>
  50. {{ $t('position.refreshTime') }} :{{ timesTampChange(val.updateTime, 'Y-M-D') }}
  51. <span>
  52. <span class="septal-line"></span>
  53. 到期时间:{{ val.expireTime ? timesTampChange(val.expireTime, 'Y-M-D') : '长期有效' }}
  54. </span>
  55. </div>
  56. <div class="d-flex">
  57. <div class="ml-10 d-flex">
  58. <div v-if="tab === 1">
  59. <span class="cursor-pointer actions" @click="handleAction(val.top ? 4 : 3, '', val)">{{ val.top ? '取消置顶' : $t('common.topping') }}</span>
  60. <span class="lines"></span>
  61. <span class="cursor-pointer actions" @click="handleAction(0, '', val)">{{ $t('common.close') }}</span>
  62. <span class="lines"></span>
  63. </div>
  64. <div v-if="tab === 1" class="cursor-pointer actions" @click="handleEdit(val)">{{ $t('common.edit') }}</div>
  65. <div v-if="tab === 3" class="cursor-pointer actions" @click="handleUpdateExpireTime(val)">修改到期时间</div>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. <Loading :visible="loading"></Loading>
  72. <CtDialog :visible="showExpire" :widthType="2" titleClass="text-h6" title="修改职位到期时间" @close="showExpire = false; expireTimeId = null" @submit="handleSubmit">
  73. <CtForm v-if="showExpire" ref="CtFormRef" :items="formItem" style="height: 100px;"></CtForm>
  74. </CtDialog>
  75. </template>
  76. <script setup>
  77. defineOptions({ name: 'enterprise-position-item'})
  78. import { ref, watch } from 'vue'
  79. import { useRouter } from 'vue-router'
  80. import { timesTampChange } from '@/utils/date'
  81. import { useI18n } from '@/hooks/web/useI18n'
  82. import { getEnterprisePubJobTypePermission } from '@/api/recruit/enterprise/position'
  83. import { closeJobAdvertised, enableJobAdvertised, refreshJobAdvertised, topJobAdvertised, updatePositionExpireTime, topJobAdvertisedCancel } from '@/api/position'
  84. import Snackbar from '@/plugins/snackbar'
  85. import { useUserStore } from '@/store/user'
  86. const store = useUserStore()
  87. const { t } = useI18n()
  88. const emit = defineEmits(['refresh'])
  89. const props = defineProps({
  90. tab: {
  91. type: Number,
  92. default: 1
  93. },
  94. items: Array
  95. })
  96. const showExpire = ref(false)
  97. const CtFormRef = ref()
  98. const loading = ref(false)
  99. const selectAll = ref(false) // 全选
  100. const selectList = ref([]) // 选中列表
  101. const formItem = ref({
  102. options: [
  103. {
  104. type: 'datePicker',
  105. key: 'time',
  106. value: null,
  107. format: 'YYYY-MM-DD',
  108. label: '到期时间 *',
  109. labelWidth: 110,
  110. disabledDates: true,
  111. }
  112. ]
  113. })
  114. const dealSelect = () => {
  115. selectList.value = props.items.filter(e => e.select).map(k => k.id)
  116. }
  117. // 全选
  118. const handleChangeSelectAll = () => {
  119. props.items.map(k => {
  120. k.select = selectAll.value
  121. return k
  122. })
  123. dealSelect()
  124. }
  125. // 单选
  126. const handleChangeSelect = () => {
  127. const length = props.items.filter(k => k.select).length
  128. selectAll.value = length > 0 ? true : false
  129. dealSelect()
  130. }
  131. // tab改变时清空选中的项
  132. watch(
  133. () => props.tab,
  134. () => {
  135. props.items.map(e => e.select = false)
  136. selectList.value = []
  137. selectAll.value = false
  138. },
  139. { immediate: true }
  140. )
  141. // 分页选中回显
  142. watch(
  143. () => props.items,
  144. (newVal) => {
  145. selectList.value.forEach(e => {
  146. const obj = newVal.find(k => k.id === e)
  147. if (obj) obj.select = true
  148. })
  149. },
  150. { immediate: true },
  151. { deep: true }
  152. )
  153. let baseInfo = ref(JSON.parse(localStorage.getItem('entBaseInfo')) || {})
  154. store.$subscribe((mutation, state) => {
  155. if (Object.keys(state.entBaseInfo).length) baseInfo.value = state.entBaseInfo
  156. })
  157. const apiList = [closeJobAdvertised, enableJobAdvertised, refreshJobAdvertised, topJobAdvertised, topJobAdvertisedCancel]
  158. // 职位关闭、激活、刷新、置顶
  159. const handleAction = async (index, type, { id }) => {
  160. // 激活职位时查询是否有可发布职位数
  161. if (index === 1) {
  162. await store.getEnterpriseInfo()
  163. if (baseInfo.value?.entitlement.publishJobCount <= 0) return Snackbar.warning('可发布职位数不足,请联系平台管理员')
  164. }
  165. const ids = type ? props.items.filter(e => e.select).map(k => k.id) : [id]
  166. if (!ids.length && !index) return
  167. loading.value = true
  168. try {
  169. await apiList[index](ids)
  170. Snackbar.success(t('common.operationSuccessful'))
  171. // 清空选项
  172. selectList.value = []
  173. selectAll.value = false
  174. emit('refresh')
  175. } finally {
  176. loading.value = false
  177. }
  178. }
  179. // 职位过期时间修改
  180. const expireTimeId = ref('')
  181. const handleUpdateExpireTime = (item) => {
  182. expireTimeId.value = item.id
  183. showExpire.value = true
  184. }
  185. const handleSubmit = async () => {
  186. const time = formItem.value.options.find(e => e.key === 'time').value
  187. if (!time) return Snackbar.warning('请选择职位到期时间')
  188. await updatePositionExpireTime({ id: expireTimeId.value, time })
  189. expireTimeId.value = ''
  190. showExpire.value = false
  191. emit('refresh')
  192. }
  193. const router = useRouter()
  194. // 职位编辑
  195. const handleEdit = async (val) => {
  196. if (props.tab !== 1) return
  197. const data = await getEnterprisePubJobTypePermission()
  198. if (!data || !data.length) return Snackbar.warning('没有该操作权限,请联系平台管理员升级后再试')
  199. router.push(`/recruit/enterprise/position/edit?id=${val.id}`)
  200. }
  201. </script>
  202. <style scoped lang="scss">
  203. .itemBox {
  204. position: relative;
  205. border: 1px solid #e5e6eb;
  206. }
  207. .position-name {
  208. color: var(--color-333);
  209. font-size: 19px;
  210. }
  211. .position {
  212. max-width: 46%;
  213. position: relative;
  214. .item-select {
  215. position: absolute;
  216. left: -8px;
  217. top: -13px;
  218. }
  219. }
  220. .lines {
  221. display: inline-block;
  222. width: 1px;
  223. height: 17px;
  224. vertical-align: middle;
  225. background-color: #e0e0e0;
  226. margin: 0 10px;
  227. }
  228. .other-info {
  229. font-size: 15px;
  230. color: var(--color-666);
  231. }
  232. .bottom {
  233. position: absolute;
  234. bottom: 0;
  235. left: 0;
  236. width: 100%;
  237. height: 40px;
  238. background-color: #f7f8fa;
  239. font-size: 14px;
  240. color: var(--color-888);
  241. }
  242. .actions:hover {
  243. color: var(--v-primary-base);
  244. }
  245. </style>