index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <div :class="{isMobile: mobile}">
  3. <div v-if="!mobile">
  4. <div class="jobList">
  5. <div class="topArea" v-if="!isSeoList">
  6. <!--{{JSON.stringify(typeList)}}-->
  7. </div>
  8. <div class="contentArea">
  9. <div class="selectArea" v-if="!isSeoList">
  10. <div class="selectContent" v-for="(key, i) in Object.keys(typeList)" :key="i + 'selectContent'">
  11. <div class="content">
  12. <div class="left"><p>{{typeList[key].title}}</p></div>
  13. <div class="right">
  14. <div class="cell"
  15. v-for="(item, ii) in typeList[key].list"
  16. :class="{selected: item.id === selected[key], noneClick: !canSelectCity && key === 'city'}"
  17. @click="changeIndexSeo(key, item)"
  18. v-if="ii < 8 || expansion[key]"
  19. :key="ii+key+item.id"
  20. >
  21. <p>{{item.name}}</p>
  22. </div>
  23. </div>
  24. <div class="more" @click="changeExpansion(key)" v-if="typeList[key].list.length > 8">
  25. {{expansion[key] ? "收起" : "更多"}}
  26. </div>
  27. </div>
  28. <div class="smallContent"
  29. v-if="key === 'direction' && typeList[key].smallList.length > 0"
  30. >
  31. <div class="cell"
  32. v-for="(item) in typeList[key].smallList"
  33. :class="{selected: item.id === selected.directionSmall}"
  34. @click="changeIndexSeo('directionSmall', item)"
  35. >
  36. <p>{{item.name}}</p>
  37. </div>
  38. </div>
  39. </div>
  40. </div>
  41. <div class="breadcrumb">
  42. <a
  43. v-for="(item, index) in breadcrumbList"
  44. :key="'breadcrumb'+index"
  45. :href="item.url"
  46. :title="item.name"
  47. >
  48. <p v-if="index!==breadcrumbList.length-1">{{item.name}} <span>&nbsp;>&nbsp;</span></p>
  49. <h1 v-else>{{item.name}}</h1>
  50. </a>
  51. </div>
  52. <div class="listArea">
  53. <!--<h1 class="sTitle">{{head.h1 || '解决方案'}}</h1>-->
  54. <div class="list" v-loading="loading">
  55. <nuxt-link class="cell"
  56. v-for="item in dataList"
  57. :key="item.id"
  58. :to="`/job/detail/${item.id}.html`"
  59. target="_blank"
  60. :title="item.name"
  61. >
  62. <div class="topArea">
  63. <div class="left">{{item.title}}</div>
  64. <div class="right">{{item.salaryName}}</div>
  65. </div>
  66. <div class="workDesc">{{item.description}}</div>
  67. <div class="labelList">
  68. <div class="label" v-for="skill in (item.skills || [])"><p>{{skill.name}}</p></div>
  69. <div class="label"><p>{{item.experienceName}}</p></div>
  70. </div>
  71. <div class="bottomArea">
  72. <div class="companyInfo">
  73. <div class="logo">
  74. <img :src="item.companyInfo.logo" alt=""/>
  75. </div>
  76. <div class="companyName">{{item.companyInfo.name || item.companyInfo.shortName}}</div>
  77. </div>
  78. <div class="publishTime">{{item.createdAtFormat}}</div>
  79. </div>
  80. </nuxt-link>
  81. <div v-if="dataList.length === 0" class="noneData">
  82. <p>没有数据</p>
  83. </div>
  84. </div>
  85. </div>
  86. <div class="pagination">
  87. <el-pagination v-if="!isSeoList" background layout="prev, pager, next" :total="page.total"
  88. :page-size="page.pageSize" @current-change="pageChange" :current-page="Number(page.current
  89. )"></el-pagination>
  90. <div v-else>
  91. <div class="list">
  92. <nuxt-link v-for="(item,index) in new Array(Math.ceil(page.total / page.size))"
  93. :to="`/job/?page=${index+1}`"
  94. :key="(page)+index"
  95. >
  96. {{index+1}}
  97. </nuxt-link>
  98. </div>
  99. </div>
  100. </div>
  101. <BottomBanner></BottomBanner>
  102. </div>
  103. </div>
  104. <SeoFooter style="" :data="footer"/>
  105. </div>
  106. <div v-else class="jobListMobile">
  107. <div class="topSelect">
  108. <van-dropdown-menu>
  109. <!--方式-->
  110. <van-dropdown-item v-model="selected['workType']" :options="typeList['workType'].list" key="workType" @change="changeIndex('workType')"/>
  111. <!--地区-->
  112. <van-dropdown-item v-model="selected['city']" :options="typeList['city'].list" key="city" @change="changeIndex('city')" :disabled="selected.workType===1"/>
  113. <!--职业-->
  114. <van-dropdown-item :title="calcName.text" key="direction" ref="directionSelect">
  115. <van-tree-select
  116. :items="typeList['direction'].list"
  117. active-id="1123321100"
  118. :main-active-index.sync="selected['directionIndex']"
  119. @click-item="(data)=>{changeIndex('directionSmall', data)}"
  120. />
  121. </van-dropdown-item>
  122. </van-dropdown-menu>
  123. </div>
  124. <h1>{{calcH1()}}</h1>
  125. <van-pull-refresh v-model="refreshing" @refresh="onRefresh" class="listArea">
  126. <div style="text-align: center" v-if="firstLoading">
  127. <van-loading size="24px">加载中...</van-loading>
  128. </div>
  129. <van-list
  130. v-else
  131. v-model="loading"
  132. :finished="finished"
  133. finished-text="没有更多了"
  134. @load="onLoad"
  135. :immediate-check="false"
  136. class="list"
  137. >
  138. <nuxt-link class="cell"
  139. v-for="item in dataList"
  140. :key="item.id"
  141. :to="`/job/detail/${item.id}.html`"
  142. target="_blank"
  143. :title="item.name"
  144. >
  145. <div class="topArea">
  146. <div class="left">{{item.title}}</div>
  147. <div class="right">{{item.salaryName}}</div>
  148. </div>
  149. <div class="workDesc">{{item.description}}</div>
  150. <div class="labelList">
  151. <div class="label" v-for="skill in (item.skills || [])"><p>{{skill.name}}</p></div>
  152. </div>
  153. <div class="companyInfo" @click.stop="jumpToCompanyInfo(item)">
  154. <div class="logo">
  155. <img :src="item.companyInfo.logo" alt=""/>
  156. </div>
  157. <div class="companyName">{{item.companyInfo.name || item.companyInfo.shortName}}</div>
  158. </div>
  159. </nuxt-link>
  160. </van-list>
  161. </van-pull-refresh>
  162. </div>
  163. </div>
  164. </template>
  165. <script>
  166. import ConnectUs from "@/components/common/connectUs"
  167. import BindMobile from "@/components/common/bindMobile"
  168. import DealSeoData from "@/components/job/dealSeoIndex"
  169. import DealSeoFooter from "@/components/job/dealSeoFooter"
  170. import BottomBanner from "@/components/job/bottomBanner"
  171. import SeoFooter from "@/components/SeoFooter"
  172. export default {
  173. name: "JobListSeoIndex",
  174. // layout: "opacity_header",
  175. showCommonFooter: false,
  176. components: { ConnectUs, BindMobile, SeoFooter, BottomBanner },
  177. head() {
  178. const { title = "", keyword = "", descrption = "", h1 = "", canonical = "", metaLocation } = this.head || {}
  179. let obj = {
  180. title: title,
  181. meta: [
  182. {
  183. 'name': 'keywords',
  184. 'content': keyword
  185. }, {
  186. 'name': 'descrption',
  187. 'content': descrption
  188. }, {
  189. 'name': 'h1',
  190. 'content': h1
  191. }
  192. ],
  193. link: [
  194. { rel: 'canonical', href: canonical },
  195. ]
  196. }
  197. if (metaLocation) {
  198. obj.meta.push({ 'name': 'location', 'content': metaLocation })
  199. }
  200. return obj
  201. },
  202. async asyncData({ ...params }) {
  203. try {
  204. params.store.commit("updateNoneCommonFooter", true)
  205. } catch ( e ) {
  206. console.log("updateNoneCommonFooter", e)
  207. }
  208. let dealDataObj = new DealSeoData(params)
  209. let ans = await dealDataObj.dealData()
  210. let dealSeoFooterObj = new DealSeoFooter(params)
  211. let footer = await dealSeoFooterObj.dealData()
  212. return {
  213. ...ans,
  214. ...footer
  215. }
  216. },
  217. data() {
  218. return {
  219. expansion: {
  220. direction: 0,
  221. city: 0,
  222. },
  223. isShowToast: false,
  224. name: '',
  225. phone: '',
  226. loading: false,
  227. refreshing: false,
  228. firstLoading: false, //移动端加载loading
  229. isLoading: false
  230. }
  231. },
  232. watch: {
  233. },
  234. computed: {
  235. canSelectCity() {
  236. //远程无法选中地区
  237. return this.selected.workType !== 1
  238. },
  239. calcName() {
  240. const {direction, directionSmall, directionName = "", directionSmallName = "", } = this.selected
  241. let job = directionSmall || direction
  242. let jobName = directionSmallName === "全部" ? directionName : (directionSmallName || directionName)
  243. return {
  244. text: jobName || '全部职业',
  245. value: job
  246. }
  247. }
  248. },
  249. created() {
  250. // this.firstLoading = true
  251. },
  252. mounted() {
  253. // this.getList()
  254. if (this.mobile) {
  255. document.body.style = "overflow:hidden;"
  256. }
  257. },
  258. methods: {
  259. //移动端选择器
  260. changeIndex(key, item) {
  261. //级联选择 特殊处理一下
  262. console.log(this.selected, this.typeList)
  263. if (key === 'directionSmall') {
  264. //当右侧选择的不是"全部"选项的时候,将大选项初始化
  265. if (item.id) {
  266. this.selected[ 'direction'] = 0
  267. this.selected[ 'directionName'] = ''
  268. this.selected[ 'directionSlug'] = ''
  269. this.selected[ key] = item.id
  270. this.selected[ key + 'Name' ] = item.name
  271. this.selected[ key + 'Slug' ] = item.slug
  272. } else {
  273. //当右侧选择的是"全部"选项的时候, 将右侧数据初始化,只保留左侧数据
  274. //左侧更改时 直接更改的是索引index,故这里要转换一下
  275. let myItem = this.typeList.direction.list[this.selected.directionIndex]
  276. this.selected[ 'direction'] = myItem.id
  277. this.selected[ 'directionName'] = myItem.name
  278. this.selected[ 'directionSlug'] = myItem.slug
  279. this.selected[ key] = 0
  280. this.selected[ key + 'Name' ] = ''
  281. this.selected[ key + 'Slug' ] = ''
  282. }
  283. }
  284. //如果选中的工作方式是远程,则初始化 城市选择
  285. if (key === 'workType' && this.selected.workType === 1) {
  286. this.selected.city = 0
  287. this.selected.cityName = ''
  288. }
  289. this.page.page = 1
  290. this.page.total = 0
  291. this.firstLoading = true
  292. this.getList()
  293. this.$refs.directionSelect.toggle(false);
  294. },
  295. //web的选择器
  296. changeIndexSeo(key, item) {
  297. console.log("key:", key, "item:", item, "selected:", this.selected)
  298. //远程无法选中地区
  299. if (!this.canSelectCity && key === 'city') {
  300. return
  301. }
  302. // 如果选中了远程工作,重置城市选择
  303. if (key === "workType" && item.id === 1) {
  304. this.selected.city = 0
  305. this.selected.cityName = ""
  306. this.selected.citySlug= ""
  307. }
  308. this.selected[ key ] = item.id
  309. this.selected[ key + 'Slug' ] = item.slug
  310. //大工作分类时,先显示子分类
  311. if (key === 'direction') {
  312. if (item.id === 0) {
  313. this.selected[ 'directionSmall' ] = item.id
  314. this.selected[ 'directionSmallSlug' ] = item.slug
  315. } else {
  316. let list = this.typeList.direction.list.filter(item => item.id === this.selected.direction)[0]
  317. if (list.children && list.children.length > 1) {
  318. this.selected[ 'directionSmall' ] = -1
  319. this.typeList[key].smallList = [...(list && list.children || [])]
  320. return
  321. }
  322. }
  323. }
  324. let { citySlug, directionSlug, directionSmallSlug, workTypeSlug} = this.selected
  325. let url = "/job/"
  326. if (citySlug) {
  327. url += citySlug + '/'
  328. }
  329. if (directionSmallSlug || directionSlug) {
  330. url += (directionSmallSlug || directionSlug) + '/'
  331. }
  332. //驻场方式 不放到url里面
  333. if (key === "workType" ) {
  334. this.page.page = 1
  335. this.page.total = 0
  336. this.getList()
  337. return
  338. }
  339. location.href = url
  340. },
  341. changeExpansion(key) {
  342. this.expansion[ key ] = !this.expansion[ key ]
  343. },
  344. getList() {
  345. const { page, selected: {city, direction, directionSmall, workType} } = this
  346. let p = {
  347. cityId: city,
  348. ...page
  349. }
  350. direction && (p.occupationId = direction) //一级
  351. workType && (p.workType = workType)
  352. directionSmall > 0 && (p.directionId = directionSmall) //耳二级
  353. if (this.isLoading) {
  354. return
  355. }
  356. this.loading = true
  357. this.isLoading = true
  358. this.$axios.post('/api/recruit/search', p).then(res => {
  359. if (Number(res.data.status) === 1) {
  360. let data = res.data.data
  361. this.page.total = data.total
  362. if (this.page.page === 1 || !this.mobile) {
  363. this.dataList = [...data.list]
  364. } else {
  365. this.dataList = [ ...this.dataList, ...data.list]
  366. }
  367. this.page.page += 1
  368. this.page.current = Number(data.page)
  369. if (this.page.total <= this.dataList.length) {
  370. this.finished = true
  371. }
  372. }
  373. }).finally(() => {
  374. this.firstLoading = false
  375. this.refreshing = false
  376. this.isLoading = false
  377. this.$nextTick(()=>{
  378. this.loading = false
  379. })
  380. console.log("this.finished", this.finished)
  381. })
  382. },
  383. pageChange(i) {
  384. this.page.page = i
  385. this.getList()
  386. },
  387. jumpToCompanyInfo(item) {
  388. const {companyInfo:{uid}} = item
  389. window.open(`/wo/${uid}`, `targetCompany${uid}`)
  390. },
  391. /** 移动端下拉刷新 **/
  392. onRefresh() {
  393. // 清空列表数据
  394. this.finished = false;
  395. console.log('onRefresh')
  396. this.onLoad();
  397. },
  398. onLoad() {
  399. console.log('onLoad')
  400. this.getList()
  401. },
  402. calcH1() {
  403. const { city, cityName = "", direction, directionName = "", directionSmall, directionSmallName = "" } = this.selected
  404. let job = directionSmall || direction
  405. let jobName = directionSmallName === "全部" ? directionName : (directionSmallName || directionName)
  406. let title = "兼职招聘"
  407. if (city && job) {
  408. title = `${cityName}${jobName}兼职招聘`
  409. } else if (city && !job) {
  410. //兼职城市
  411. title = `${cityName}兼职招聘`
  412. } else if (!city && job) {
  413. //岗位页
  414. title = `${jobName}兼职招聘`
  415. }
  416. return title
  417. },
  418. }
  419. }
  420. </script>
  421. <style scope lang="scss">
  422. @import "../../assets/css/job/index.scss";
  423. </style>
  424. <style lang="scss">
  425. .van-dropdown-menu__title {
  426. color: #666;
  427. }
  428. </style>