index.vue 16 KB

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