index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. <template>
  2. <div :class="mobile ? 'mobileMain' : ''" :style="{
  3. marginTop: mainMarginTop,
  4. marginBottom: mobile ? '0px' : '30px !important'
  5. }">
  6. <div class="developer-container" v-if="!mobile">
  7. <div class="developer-left">
  8. <!-- 接单流程:start -->
  9. <section class="developer-process block" v-if="!isSign">
  10. <h3 class="title">接单流程</h3>
  11. <div class="developer-process-list">
  12. <article class="developer-process-item cur">
  13. <div class="developer-process-step line">
  14. <div class="developer-process-step-icon icon-1"></div>
  15. <div class="developer-process-step-content">注册</div>
  16. </div>
  17. <div class="developer-process-tips">成为客栈注册用户</div>
  18. </article>
  19. <article class="developer-process-item" :class="isRealName ? 'cur' : ''">
  20. <div class="developer-process-step normal line">
  21. <div class="developer-process-step-icon icon-2" :class="isRealName ? 'icon-1' : 'icon-2'"></div>
  22. <div class="developer-process-step-content">实名认证</div>
  23. </div>
  24. <div class="developer-process-tips">
  25. <p>
  26. 按国家相关规定,用户需实名,目前{{
  27. isRealName ? "已实名" : "尚未实名"
  28. }}
  29. </p>
  30. <p v-if="!isRealName">
  31. <a href="/frontend/name_cert">立即实名</a>
  32. </p>
  33. </div>
  34. </article>
  35. <article class="developer-process-item" :class="isSign ? 'cur' : ''">
  36. <div class="developer-process-step normal line">
  37. <div class="developer-process-step-icon icon-3"></div>
  38. <div class="developer-process-step-content">签约开发者</div>
  39. </div>
  40. <div class="developer-process-tips">
  41. <p v-if="!isSign">尚未签约 <a href="/sign/new">立即签约</a></p>
  42. <p v-else>已签约</p>
  43. </div>
  44. </article>
  45. <article class="developer-process-item" :class="isSign ? '' : ''">
  46. <div class="developer-process-step normal">
  47. <div class="developer-process-step-icon icon-4"></div>
  48. <div class="developer-process-step-content">开始接单</div>
  49. </div>
  50. <!-- <div class="developer-process-tips">内容已通过</div>-->
  51. </article>
  52. </div>
  53. </section>
  54. <!-- 接单流程:end -->
  55. <!-- 新人如何接单:start -->
  56. <section class="developer-order block">
  57. <h3 class="title">新人如何接单</h3>
  58. <p class="tips">
  59. 客栈接单采用智能对接池匹配原则,权重越高优先匹配。当前在“前端”对接池的<span style="color: #308eff;font-weight: bold;">排名{{ userInfo.rand_score || "100+" }}</span>,影响对接池的因素有以下几点:
  60. </p>
  61. <div class="developer-order-list">
  62. <article class="developer-order-item">
  63. <div class="developer-order-title-area">
  64. <div class="developer-order-title-area-wrap">
  65. <div class="developer-order-icon icon-1"></div>
  66. <h5 class="developer-order-title">完善个人资料</h5>
  67. </div>
  68. <div class="developer-order-link">
  69. <a :href="'/wo/'+userinfo.uid">立即完善</a>
  70. </div>
  71. </div>
  72. <p class="developer-order-tips">
  73. 账号信息完善度(个人信息+简历+作品)越高,客户信任感更高,也更容易为您精准匹配。
  74. </p>
  75. </article>
  76. <article class="developer-order-item">
  77. <div class="developer-order-title-area">
  78. <div class="developer-order-title-area-wrap">
  79. <div class="developer-order-icon icon-2"></div>
  80. <h5 class="developer-order-title">技术等级认证</h5>
  81. </div>
  82. <div class="developer-order-link">
  83. <a href="/frontend/skill_cert/profile">立即认证</a>
  84. </div>
  85. </div>
  86. <p class="developer-order-tips">
  87. 我们会优先匹配进行过技术认证的开发者,如果您是自由职业者还可以进行自由工作者认证。
  88. </p>
  89. </article>
  90. <article class="developer-order-item">
  91. <div class="developer-order-title-area">
  92. <div class="developer-order-title-area-wrap">
  93. <div class="developer-order-icon icon-3"></div>
  94. <h5 class="developer-order-title">Ping一下</h5>
  95. </div>
  96. <div class="developer-order-link">
  97. <a href="" @click.prevent="ping">Ping一下</a>
  98. </div>
  99. </div>
  100. <p class="developer-order-tips">
  101. 每日Ping一下,表达你的接单意愿,将提升你的对接池权重。
  102. </p>
  103. </article>
  104. <article class="developer-order-item">
  105. <div class="developer-order-title-area">
  106. <div class="developer-order-title-area-wrap">
  107. <div class="developer-order-icon icon-4"></div>
  108. <h5 class="developer-order-title">客户好评</h5>
  109. </div>
  110. <!-- <div class="developer-order-link"><a href="">立即完善</a></div> -->
  111. </div>
  112. <p class="developer-order-tips">
  113. 成功接单后,服务质量优秀,之后会多多派单哦!
  114. </p>
  115. </article>
  116. <article class="developer-order-item">
  117. <div class="developer-order-title-area">
  118. <div class="developer-order-title-area-wrap">
  119. <div class="developer-order-icon icon-5"></div>
  120. <h5 class="developer-order-title">开通开发者会员</h5>
  121. </div>
  122. <div class="developer-order-link">
  123. <a href="/type/vip/developer">会员介绍</a>
  124. </div>
  125. </div>
  126. <p class="developer-order-tips">
  127. 开发者会员出来提高权重,还有更多权益!
  128. </p>
  129. </article>
  130. </div>
  131. </section>
  132. <!-- 新人如何接单:end -->
  133. <!-- 热门课程:start -->
  134. <section class="developer-hot block">
  135. <article class="developer-hot-class">
  136. <h3 class="title">热门课程</h3>
  137. <ul class="developer-hot-list">
  138. <li v-for="(learnItem, index) in hotInfo['learn']" :key="learnItem.link" class="developer-hot-item text-line-1">
  139. <span class="index">{{ index + 1 }}</span>
  140. <a :href="learnItem.link">{{ learnItem.title }}</a>
  141. </li>
  142. </ul>
  143. </article>
  144. <article class="developer-hot-resource">
  145. <h3 class="title">热门资源</h3>
  146. <ul class="developer-hot-list">
  147. <li v-for="(workItem, index2) in hotInfo['works']" :key="workItem.link" class="developer-hot-item text-line-1">
  148. <span class="index">{{ index2 + 1 }}</span>
  149. <a :href="workItem.link">{{ workItem.title }}</a>
  150. </li>
  151. </ul>
  152. </article>
  153. </section>
  154. <!-- 热门课程:end -->
  155. <!-- 推荐tab:start -->
  156. <section class="developer-tab block">
  157. <div class="developer-tab-title-list">
  158. <!-- cur -->
  159. <div v-for="typeItem in typeList" :key="typeItem.typeId" @click="reset(typeItem.typeId)" :data-typeid="typeItem.typeId" :class="tid == typeItem.typeId ? 'cur' : ''" class="developer-tab-title-item">
  160. {{ typeItem.name }}
  161. </div>
  162. </div>
  163. <div class="developer-tab-main">
  164. <p class="developer-tab-tips">
  165. PC端圈子发布功能尚未上线,可下载APP体验哦~
  166. </p>
  167. <ul class="developer-dynamic-list" v-if="list.length > 0">
  168. <li v-for="dynamic in list" :key="dynamic.dynamicId" class="developer-dynamic-item">
  169. <div class="dynamic-user">
  170. <div class="dynamic-user-avatar">
  171. <img :src="dynamic.user_info.icon_url" />
  172. </div>
  173. <div class="dynamic-user-info">
  174. <p class="dynamic-user-nickname text-line-1">
  175. <span>{{ dynamic.user_info.nickname }}</span><span v-if="dynamic.user_info.freework_level > 2" class="dynamic-level">F{{ dynamic.user_info.freework_level }}</span>
  176. </p>
  177. <p class="dynamic-job">
  178. {{ dynamic.user_info.tag[0].name }} ·
  179. {{ dynamic.user_info.tag[1].name }}
  180. </p>
  181. </div>
  182. </div>
  183. <div class="dynamic-title dynamic-margin">
  184. {{ dynamic.title }}
  185. </div>
  186. <div class="dynamic-type-list dynamic-margin">
  187. <span class="dynamic-type-item">{{ dynamic.type_text }}</span>
  188. </div>
  189. <div class="dynamic-img-area dynamic-margin" v-if="dynamic.img && dynamic.img.length > 0">
  190. <div class="dynamic-img-item" v-for="d_img in dynamic.img" :key="d_img.img">
  191. <!-- <img :src="d_img.img" /> -->
  192. <el-image style="width:90px;height:90px" fit="cover" :src="d_img.img" :preview-src-list="dynamic.imgList">
  193. </el-image>
  194. </div>
  195. </div>
  196. <div class="dynamic-link-area dynamic-margin" @click.capture.stop="clickResource(dynamic.resources)" v-if="dynamic.resources.resources_exist == 1">
  197. <div class="dynamic-link-img-area">
  198. <img :src="dynamic.resources.resources_img" />
  199. </div>
  200. <div class="dynamic-link-content text-line-1">
  201. <span :href="dynamic.resources.resources_url">{{dynamic.resources.resources_title}}</span>
  202. </div>
  203. </div>
  204. <div class="dynamic-control">
  205. <div class="dynamic-control-item" @click="gotoAppTips"><span class="dynamic-icon icon-share"></span>分享</div>
  206. <div class="dynamic-control-item" @click="gotoAppTips"><span class="dynamic-icon icon-comment"></span>评论</div>
  207. <div class="dynamic-control-item" @click="gotoAppTips"><span class="dynamic-icon icon-like"></span>赞</div>
  208. </div>
  209. </li>
  210. </ul>
  211. <div class="dynamic-empty" v-else>
  212. <Empty></Empty>
  213. <p>暂无动态</p>
  214. </div>
  215. </div>
  216. </section>
  217. <!-- 推荐tab:start -->
  218. </div>
  219. <div class="developer-right">
  220. <!-- 工作台:start -->
  221. <section class="developer-workbench block">
  222. <div class="developer-workbench-user">
  223. <div class="developer-user-avatar">
  224. <img :src="userInfo.icon_url || personalIcon" />
  225. </div>
  226. <div class="developer-user-info">
  227. <div v-if="isLogin" class="developer-user-name text-line-1">
  228. {{ userInfo.nickname }}
  229. </div>
  230. <div @click="login" v-else class="developer-user-name nologin text-line-1">
  231. 登录/注册
  232. </div>
  233. <div class="developer-user-level">
  234. <span>当前等级Lv.{{ userInfo.dynamic_rand || 0 }} </span><span class="arrow_icon"></span>
  235. </div>
  236. </div>
  237. </div>
  238. <h5 class="user-title">工作台</h5>
  239. <div class="developer-work-list">
  240. <div class="developer-work-item" @click="goto('/wo/work_todo')">
  241. <div class="developer-work-count">
  242. {{ workPlatInfo.pendingNumber || 0 }}
  243. </div>
  244. <div class="developer-work-tips">待办</div>
  245. </div>
  246. <div class="developer-work-item" @click="gotoAppTips">
  247. <div class="developer-work-count">
  248. {{ workPlatInfo.recruitDeveloperCount || 0 }}
  249. </div>
  250. <div class="developer-work-tips">沟通</div>
  251. </div>
  252. <div class="developer-work-item" @click="goto('/wo/work_hire')">
  253. <div class="developer-work-count">
  254. {{ workPlatInfo.developerWorkNumber || 0 }}
  255. </div>
  256. <div class="developer-work-tips">工作</div>
  257. </div>
  258. <div class="developer-work-item" @click="goto('/wo/work_platform')">
  259. <div class="developer-work-count">
  260. {{ workPlatInfo.developerProjectNumber || 0 }}
  261. </div>
  262. <div class="developer-work-tips">整包</div>
  263. </div>
  264. </div>
  265. <div class="developer-setting-area">
  266. <div class="developer-setting-item" @click="goto('/setting/work')">
  267. <div class="developer-setting-icon setting-icon"></div>
  268. <div class="developer-setting-tips ">接单设置</div>
  269. </div>
  270. <div class="developer-setting-item">
  271. <div class="developer-setting-icon ping-icon"></div>
  272. <div class="developer-setting-tips" @click="ping">Ping</div>
  273. </div>
  274. <div class="developer-setting-line"></div>
  275. </div>
  276. </section>
  277. <!-- 工作台:end -->
  278. <!-- 收入:start -->
  279. <section @click.stop="goto('/wo/account')" class="developer-reward block" v-if="init">
  280. <div class="developer-reward-title">
  281. <p>总收入 (元) <span class="arrow_icon"></span></p>
  282. <div @click.stop="toggleBanlace" class="developer-reward-show-setting" :class="isShowBablance ? 'show' : 'hide'"></div>
  283. </div>
  284. <div v-if="isLogin" class="developer-reward-count">
  285. {{ isShowBablance ? balanceInfo.historyTotalBalance : "****" }}
  286. </div>
  287. <div v-else class="developer-reward-count">
  288. {{ isShowBablance ? 0 : "****" }}
  289. </div>
  290. <div class="developer-reward-detail">
  291. <div class="developer-reward-item">
  292. <span>账户余额:</span>
  293. <span v-if="isLogin" class="num">{{isShowBablance ? balanceInfo.totalBalance : "****"}}</span>
  294. <span v-else class="num">{{isShowBablance ? 0 : "****"}}</span>
  295. </div>
  296. <div class="developer-reward-item">
  297. <span>薪资余额:</span>
  298. <span v-if="isLogin" class="num">{{isShowBablance ? balanceInfo.gongMallBalance : "****"}}</span>
  299. <span v-else class="num">{{isShowBablance ? 0 : "****"}}</span>
  300. </div>
  301. <div class="developer-reward-item">
  302. <span>冻结余额:</span>
  303. <span v-if="isLogin" class="num">{{isShowBablance ? balanceInfo.frozenBalance : "****"}}</span>
  304. <span v-else class="num">{{isShowBablance ? 0 : "****"}}</span>
  305. </div>
  306. </div>
  307. </section>
  308. <!-- 收入:end -->
  309. <div class="developer-skill block">
  310. <div class="developer-skill-item" @click="goto('/workbench/skill/index')">
  311. <span class="developer-skill-icon icon1"></span>发布技能
  312. </div>
  313. <div class="developer-skill-item" @click="goto('/workbench/consult/index')">
  314. <span class="developer-skill-icon icon2"></span>发布咨询
  315. </div>
  316. <div class="developer-skill-item" @click="goto('/workbench/learn/index')">
  317. <span class="developer-skill-icon icon3"></span>上传课程
  318. </div>
  319. <div class="developer-skill-item" @click="goto('/otherpage/works/create')">
  320. <span class="developer-skill-icon icon4"></span>上传资源
  321. </div>
  322. </div>
  323. </div>
  324. </div>
  325. </div>
  326. </template>
  327. <script>
  328. import {
  329. mapState
  330. } from "vuex";
  331. import qs from "qs";
  332. import DeveloperSeoData from "./developData";
  333. import Empty from "./empty";
  334. import personalIcon from "@/assets/img/account/personal.png"
  335. export default {
  336. name: "SeoLearnList",
  337. components: {
  338. Empty
  339. },
  340. data() {
  341. return {
  342. baseUrl: "",
  343. mobile: false,
  344. // firstLoad: true,
  345. isWeixinApp: true,
  346. isShowBablance: 1,
  347. init: false,
  348. tid: "",
  349. page: 1,
  350. pageSize: 10,
  351. list: [],
  352. isMore: true,
  353. pageLoading: false,
  354. personalIcon
  355. };
  356. },
  357. head() {
  358. const {
  359. title = "程序员客栈-领先的程序员自由远程工作平台",
  360. keyword = "软件开发,网站系统,APP小程序,UI设计,web前端,原型产品经理,程序员兼职,程序员招聘",
  361. description = "程序员客栈是领先的程序员自由远程工作平台,未来互联网企业用人方式。提供优秀程序员为您进行网站建设制作、测试运维服务、人工智能AI、大数据区块链、软件开发等优质服务。",
  362. h1 = "",
  363. canonical = "",
  364. metaLocation
  365. } = this.head || {};
  366. let obj = {
  367. title: title,
  368. meta: [{
  369. name: "keywords",
  370. content: keyword
  371. },
  372. {
  373. name: "description",
  374. content: description
  375. },
  376. {
  377. name: "h1",
  378. content: h1
  379. }
  380. ],
  381. link: [{
  382. rel: "canonical",
  383. href: canonical
  384. }]
  385. };
  386. if (metaLocation) {
  387. obj.meta.push({
  388. name: "location",
  389. content: metaLocation
  390. });
  391. }
  392. return obj;
  393. },
  394. computed: {
  395. ...mapState(["deviceType"]),
  396. showWxHeader() {
  397. return (
  398. !this.deviceType.app &&
  399. !this.isWeixinApp &&
  400. (this.deviceType.android || this.deviceType.ios)
  401. );
  402. },
  403. mainMarginTop() {
  404. if (this.mobile && this.showWxHeader) {
  405. return "64px !important";
  406. } else if (this.mobile) {
  407. return "0px !important";
  408. } else {
  409. return "20px !important";
  410. }
  411. },
  412. // 是否实名
  413. isRealName() {
  414. return this.userInfo["realname_verify_status"] == 2 ? true : false;
  415. // return false
  416. },
  417. // 是否签约
  418. isSign() {
  419. return this.userInfo["realname_re"] == 2 ? true : false;
  420. // return false
  421. },
  422. dynamicTranlate() {
  423. return ;
  424. let typeList = this.typeList;
  425. let total = 680;
  426. let block = parseInt(total / typeList.length);
  427. let half = parseInt(block / 2);
  428. let line = 24 / 2;
  429. let curIndex = this.typeList.findIndex(item => {
  430. return item.typeId == this.tid;
  431. });
  432. curIndex = curIndex ? curIndex : 0;
  433. let result = curIndex * block + half - line;
  434. return result;
  435. },
  436. isLogin() {
  437. return this.$store.getters.isLogin
  438. }
  439. },
  440. async asyncData({
  441. ...params
  442. }) {
  443. let dealDataObj = new DeveloperSeoData(params);
  444. let ans = await dealDataObj.dealData();
  445. return {
  446. ...ans
  447. };
  448. },
  449. created() {},
  450. mounted() {
  451. let isShowBablance = window.localStorage.getItem("banlanceShow");
  452. if (isShowBablance === null || isShowBablance === undefined) {
  453. isShowBablance = 1;
  454. }
  455. this.isShowBablance = Number(isShowBablance);
  456. this.init = true;
  457. this.baseUrl = this.$store.state.domainConfig.siteUrl;
  458. this.isWeixinApp = navigator.userAgent.indexOf("miniProgram") > -1;
  459. this.tid = this.firstType.typeId;
  460. this.list = [...this.dynamicList];
  461. this.$nextTick(() => {
  462. this.listenToEnd();
  463. });
  464. },
  465. destroy: function () {
  466. window.onscroll = null;
  467. },
  468. methods: {
  469. gotoApp() {
  470. this.checkLogin(true);
  471. this.$message("请前往APP完成实名");
  472. },
  473. gotoAppTips() {
  474. this.checkLogin(true);
  475. this.$message("请前往APP查看");
  476. },
  477. goto(url) {
  478. location.href = url;
  479. },
  480. async ping() {
  481. let res = await this.$axios.$post("/api/remote/ping");
  482. if (res.status == 1) {
  483. this.$message.success("操作成功");
  484. }
  485. },
  486. toggleBanlace() {
  487. if (this.isShowBablance) {
  488. this.hideBanlance();
  489. } else {
  490. this.showBanlance();
  491. }
  492. },
  493. hideBanlance() {
  494. this.isShowBablance = 0;
  495. window.localStorage.setItem("banlanceShow", 0);
  496. },
  497. showBanlance() {
  498. this.isShowBablance = 1;
  499. window.localStorage.setItem("banlanceShow", 1);
  500. },
  501. listenToEnd() {
  502. let that = this;
  503. window.onscroll = function () {
  504. var scrollTop =
  505. document.documentElement.scrollTop || document.body.scrollTop;
  506. var windowHeight =
  507. document.documentElement.clientHeight || document.body.clientHeight;
  508. var scrollHeight =
  509. document.documentElement.scrollHeight || document.body.scrollHeight;
  510. if (scrollHeight - scrollTop - windowHeight < 400) {
  511. that.fetchDynamicData();
  512. }
  513. };
  514. },
  515. reset(type_id) {
  516. if (this.pageLoading) return;
  517. this.page = 0;
  518. this.isMore = true;
  519. this.tid = type_id;
  520. this.list = [];
  521. this.pageLoading = false;
  522. this.fetchDynamicData();
  523. },
  524. async fetchDynamicData() {
  525. if (this.pageLoading || !this.isMore) return;
  526. this.pageLoading = true;
  527. let page = this.page + 1;
  528. let type_id = this.tid
  529. let res = await this.$axios.$post("/uapi/dynamic/get_dynamic_detail", {
  530. type_id: type_id,
  531. page: page,
  532. pagesize: this.pageSize
  533. });
  534. setTimeout(() => {
  535. this.pageLoading = false;
  536. }, 100);
  537. if (Number(res.status) === 1) {
  538. // if (type_id != this.tid) {
  539. // return
  540. // }
  541. let info = res.data.list;
  542. info = info.map((item) => {
  543. let imgList = item.img
  544. imgList = imgList.map(item => {
  545. return item.img
  546. })
  547. return {
  548. ...item,
  549. imgList
  550. }
  551. })
  552. this.page = page;
  553. this.list = [...this.list, ...info];
  554. this.isMore = info.length < this.pageSize ? false : true;
  555. } else if (Number(res.status) === 40001) {
  556. this.isExist = false;
  557. }
  558. },
  559. clickResource(resources){
  560. if(resources.resources_status != 1){
  561. this.$message.info(resources.resources_text)
  562. }else{
  563. location.href = resources.resources_url
  564. }
  565. },
  566. login(){
  567. this.goLogin()
  568. }
  569. }
  570. };
  571. </script>
  572. <style lang="scss">
  573. @import "@/assets/css/developer/index.scss";
  574. </style>