index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <template>
  2. <div :class="mobile ? 'mobileMain' : ''" :style="{marginTop: mainMarginTop}">
  3. <div class="works-wrapper" v-if="!mobile" v-loading="firstLoad">
  4. <div class="works-category">
  5. <div class="works-category-one">
  6. <div
  7. class="works-category-one-item"
  8. :class="currentCategoryIndex === 0 ? 'active' : ''"
  9. @click="handleClickCategoryOne(0)">
  10. 全部
  11. </div>
  12. <div
  13. class="works-category-one-item"
  14. :class="currentCategoryIndex === index + 1 ? 'active' : ''"
  15. v-for="(category, index) in categoryList"
  16. :key="`category-one-${category.category_id}`"
  17. @click="handleClickCategoryOne(index + 1)">
  18. {{ category.name }}
  19. </div>
  20. </div>
  21. <div class="works-category-two">
  22. <!-- 展开按钮 -->
  23. <img
  24. src="@/assets/img/works/expand-arrow@2x.png"
  25. alt="expand"
  26. class="works-expand-arrow"
  27. :class="categoryExpanded ? 'active' : ''"
  28. @click="handleClickExpandCategory">
  29. <!-- 全部二级分类 -->
  30. <div
  31. class="works-category-two-wrapper"
  32. :class="categoryExpanded ? 'expand' : ''"
  33. v-show="currentCategoryIndex === 0">
  34. <div
  35. class="works-category-two-item"
  36. :class="pagination.cate_id_two.indexOf(category.category_id) > -1 ? 'active' : ''"
  37. v-for="category in categoryAll"
  38. :key="`category-all-${category.category_id}`"
  39. @click="handleClickCategoryTwo(category.category_id)">
  40. {{ category.name }}
  41. </div>
  42. </div>
  43. <!-- 接口返回的二级分类 -->
  44. <div
  45. class="works-category-two-wrapper"
  46. :class="categoryExpanded ? 'expand' : ''"
  47. v-for="(category, index) in categoryList"
  48. :key="`category-two-wrapper-${category.category_id}`"
  49. v-show="currentCategoryIndex === index + 1">
  50. <div
  51. class="works-category-two-item"
  52. :class="pagination.cate_id_two.indexOf(categoryChild.category_id) > -1 ? 'active' : ''"
  53. v-for="categoryChild in category.child"
  54. :key="`category-two-${categoryChild.category_id}`"
  55. @click="handleClickCategoryTwo(categoryChild.category_id)">
  56. {{ categoryChild.name }}
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. <div class="works-list" v-if="worksList.length" v-loading="loadingWorksList">
  62. <div
  63. class="works-item"
  64. v-for="works in worksList"
  65. :key="`works-item-${works.wid}`">
  66. <div class="works-detail-wrapper">
  67. <a :href="`${baseUrl}/w/${works.wid}`">
  68. <img v-if="works.image" class="works-image" :src="works.image" alt="works-image">
  69. </a>
  70. <div class="works-detail" :style="{'width': works.image ? '630px' : '770px'}">
  71. <a class="works-name" :href="`${baseUrl}/w/${works.wid}`">{{ works.name }}</a>
  72. <div class="works-description">{{ works.description }}</div>
  73. <div class="more-info-wrapper">
  74. <div class="price-info">
  75. <span class="works-price">¥{{ works.price }}</span>
  76. <span class="download-count">{{ works.down_num }}人已下载</span>
  77. </div>
  78. <div class="more-info">
  79. <img class="plus-img" src="@/assets/img/works/plus-icon@2x.png" alt="">
  80. <span class="plus-count">{{ works.plus_co }}</span>
  81. <span class="time">{{ works.update_time }}</span>
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. <a class="works-user-wrapper" :href="`${baseUrl}/wo/${works.uid}/works`">
  87. <img class="user-avatar" :src="works.icon_url" alt="avatar">
  88. <div class="username">{{ works.nickname }}</div>
  89. <div class="company">{{ works.company }} {{ works.kill_title || '' }}</div>
  90. </a>
  91. </div>
  92. </div>
  93. <div class="result-empty-wrapper" v-else>
  94. <img src="@/assets/img/common/empty@2x.png" alt="empty">
  95. <span>暂无搜索内容</span>
  96. </div>
  97. <div class="pagination-wrapper" v-if="pagination.total > pagination.pagesize">
  98. <el-pagination
  99. background
  100. layout="prev, pager, next"
  101. :current-page="pagination.page"
  102. :total="pagination.total"
  103. :page-size="pagination.pagesize"
  104. @current-change="handlePageChange">
  105. </el-pagination>
  106. </div>
  107. </div>
  108. <div class="works-wrapper-mobile" v-else>
  109. <div class="works-category">
  110. <div class="works-category-one">
  111. <div class="category-scroller">
  112. <div
  113. class="works-category-one-item"
  114. :class="currentCategoryIndex === 0 ? 'active' : ''"
  115. @click="handleClickCategoryOne(0)">
  116. 全部
  117. </div>
  118. <div
  119. class="works-category-one-item"
  120. :class="currentCategoryIndex === index + 1 ? 'active' : ''"
  121. v-for="(category, index) in categoryList"
  122. :key="`category-one-${category.category_id}`"
  123. @click="handleClickCategoryOne(index + 1)">
  124. {{ category.name }}
  125. </div>
  126. </div>
  127. <!-- filter -->
  128. <div class="filter-bg"></div>
  129. <div class="filter-wrapper" @click="handleShowCategoryDrawer">
  130. <img src="@/assets/img/works/filter-icon@2x.png" alt="filter">
  131. </div>
  132. </div>
  133. <div class="works-category-two">
  134. <!-- 全部二级分类 -->
  135. <div
  136. class="works-category-two-wrapper"
  137. :class="categoryExpanded ? 'expand' : ''"
  138. v-show="currentCategoryIndex === 0">
  139. <div
  140. class="works-category-two-item"
  141. :class="pagination.cate_id_two.indexOf(category.category_id) > -1 ? 'active' : ''"
  142. v-for="category in categoryAll"
  143. :key="`category-all-${category.category_id}`"
  144. @click="handleClickCategoryTwo(category.category_id)">
  145. {{ category.name }}
  146. </div>
  147. </div>
  148. <!-- 接口返回的二级分类 -->
  149. <div
  150. class="works-category-two-wrapper"
  151. :class="categoryExpanded ? 'expand' : ''"
  152. v-for="(category, index) in categoryList"
  153. :key="`category-two-wrapper-${category.category_id}`"
  154. v-show="currentCategoryIndex === index + 1">
  155. <div
  156. class="works-category-two-item"
  157. :class="pagination.cate_id_two.indexOf(categoryChild.category_id) > -1 ? 'active' : ''"
  158. v-for="categoryChild in category.child"
  159. :key="`category-two-${categoryChild.category_id}`"
  160. @click="handleClickCategoryTwo(categoryChild.category_id)">
  161. {{ categoryChild.name }}
  162. </div>
  163. </div>
  164. </div>
  165. </div>
  166. <div class="works-list" :class="showWxHeader ? 'works-list__showWxHeader' : ''">
  167. <ul
  168. class="works-list-wrapper"
  169. v-infinite-scroll="handleLoadMoreWorks"
  170. :infinite-scroll-disabled="pagination.noMore"
  171. :infinite-scroll-immediate="false">
  172. <div
  173. class="works-item"
  174. v-for="works in worksList"
  175. :key="`works-item-${works.wid}`"
  176. @click="handleClickWorkItem(works.wid)">
  177. <img v-if="works.image" class="works-image" :src="works.image" alt="works-image">
  178. <div class="works-detail" :class="works.image ? '' : 'without-img'">
  179. <div class="works-name">{{ works.name }}</div>
  180. <div class="works-description">{{ works.description }}</div>
  181. <div class="price-info">
  182. <span class="works-price">¥{{ works.price }}</span>
  183. <span class="download-count">{{ works.down_num }}人已下载</span>
  184. </div>
  185. </div>
  186. </div>
  187. <!-- 空数据 -->
  188. <div class="result-empty-wrapper" v-if="!worksList.length && !pagination.loading">
  189. <img src="@/assets/img/common/empty@2x.png" alt="empty">
  190. <span>暂无搜索内容</span>
  191. </div>
  192. <p v-if="pagination.loading" class="works-list-tips">加载中...</p>
  193. <p v-if="worksList.length && pagination.noMore && !firstLoad" class="works-list-tips">没有更多了</p>
  194. </ul>
  195. </div>
  196. <!-- 弹出的分类选择 -->
  197. <el-drawer
  198. ref="categoryDrawer"
  199. class="category-drawer"
  200. :visible.sync="showCategoryDrawer"
  201. direction="ttb"
  202. :withHeader="false">
  203. <div class="drawer-category-one">
  204. <div
  205. class="drawer-category-one-item"
  206. :class="currentDrawerCategoryIndex === 0 ? 'active' : ''"
  207. @click="handleClickDrawerCategoryOne(0)">
  208. 全部
  209. </div>
  210. <div
  211. class="drawer-category-one-item"
  212. :class="currentDrawerCategoryIndex === index + 1 ? 'active' : ''"
  213. v-for="(category, index) in categoryList"
  214. :key="`drawer-category-one-${category.category_id}`"
  215. @click="handleClickDrawerCategoryOne(index + 1)">
  216. {{ category.name }}
  217. </div>
  218. </div>
  219. <div class="drawer-category-two">
  220. <!-- 全部二级分类 -->
  221. <div
  222. class="drawer-category-two-wrapper"
  223. v-show="currentDrawerCategoryIndex === 0">
  224. <div
  225. class="drawer-category-two-item"
  226. :class="pagination.cate_id_two.indexOf(category.category_id) > -1 ? 'active' : ''"
  227. v-for="category in categoryAll"
  228. :key="`drawer-category-all-${category.category_id}`"
  229. @click="handleClickDrawerCategoryTwo(category.category_id)">
  230. {{ category.name }}
  231. </div>
  232. </div>
  233. <!-- 接口返回的二级分类 -->
  234. <div
  235. class="drawer-category-two-wrapper"
  236. v-for="(category, index) in categoryList"
  237. :key="`drawer-category-two-wrapper-${category.category_id}`"
  238. v-show="currentDrawerCategoryIndex === index + 1">
  239. <div
  240. class="drawer-category-two-item"
  241. :class="pagination.cate_id_two.indexOf(categoryChild.category_id) > -1 ? 'active' : ''"
  242. v-for="categoryChild in category.child"
  243. :key="`drawer-category-two-${categoryChild.category_id}`"
  244. @click="handleClickDrawerCategoryTwo(categoryChild.category_id)">
  245. {{ categoryChild.name }}
  246. </div>
  247. </div>
  248. </div>
  249. </el-drawer>
  250. </div>
  251. </div>
  252. </template>
  253. <script>
  254. import {mapState} from "vuex";
  255. export default {
  256. data () {
  257. return {
  258. baseUrl: '',
  259. categoryAll: [],
  260. categoryList: [],
  261. worksList: [],
  262. currentCategoryIndex: 0,
  263. currentDrawerCategoryIndex: 0,
  264. categoryExpanded: false,
  265. firstLoad: true,
  266. loadingWorksList: false,
  267. showCategoryDrawer: false,
  268. pagination: {
  269. page: 1,
  270. keywords: '',
  271. cate_id_two: [],
  272. // 非接口参数
  273. pagesize: 20,
  274. total: 0,
  275. loading: true,
  276. noMore: true
  277. },
  278. isWeixinApp: true
  279. }
  280. },
  281. computed: {
  282. ...mapState(["deviceType"]),
  283. showWxHeader () {
  284. return !this.deviceType.app && !this.isWeixinApp &&
  285. (this.deviceType.android || this.deviceType.ios)
  286. },
  287. mainMarginTop () {
  288. if (this.mobile && this.showWxHeader) {
  289. return '64px'
  290. } else if (this.mobile) {
  291. return '0px'
  292. } else {
  293. return '20px'
  294. }
  295. }
  296. },
  297. async asyncData ({...params}) {
  298. return {
  299. mobile: params.app.$deviceType.isMobile()
  300. }
  301. },
  302. created() {
  303. this.baseUrl = this.$store.state.domainConfig.siteUrl;
  304. },
  305. mounted () {
  306. this.isWeixinApp = navigator.userAgent.indexOf("miniProgram") > -1
  307. const self = this
  308. const getWorksCategoryPromise = this._getWorksCategory()
  309. const getWorksListPromise = this._getWorksList()
  310. Promise.all([getWorksCategoryPromise, getWorksListPromise]).then(([a, b]) => {
  311. console.log(a, b)
  312. self.firstLoad = false
  313. })
  314. },
  315. methods: {
  316. /**
  317. * 获取作品资源分类
  318. */
  319. _getWorksCategory () {
  320. const self = this
  321. const promise = new Promise((resolve, reject) => {
  322. self.$axios.$post('/api/user_works/cate').then(res => {
  323. if (res.status === 1) {
  324. let categoryAll = []
  325. self.categoryList = res.data || []
  326. self.categoryList.forEach(category => {
  327. if (category.child && category.child.length) {
  328. category.child.forEach(categoryChild => {
  329. categoryAll.push(categoryChild)
  330. })
  331. }
  332. })
  333. self.categoryAll = categoryAll
  334. }
  335. resolve()
  336. }).catch(err => {
  337. reject(err)
  338. })
  339. })
  340. return promise
  341. },
  342. /**
  343. * 获取作品列表
  344. */
  345. _getWorksList () {
  346. const self = this
  347. if (!this.firstLoad) {
  348. this.loadingWorksList = true
  349. this.pagination.loading = true
  350. this.pagination.noMore = false
  351. }
  352. const data = {
  353. page: this.pagination.page,
  354. keywords: this.pagination.keywords,
  355. cate_id_two: this.pagination.cate_id_two.join(',')
  356. }
  357. const promise = new Promise((resolve, reject) => {
  358. self.$axios.$post('/api/user_works/workFileList', data).then(res => {
  359. if (res.status === 1) {
  360. const worksList = res.data.list || []
  361. self.pagination.pagesize = res.data.pagesize || 20
  362. self.pagination.total = res.data.total || 0
  363. if (self.mobile) {
  364. self.worksList = self.worksList.concat(worksList)
  365. } else {
  366. self.worksList = worksList
  367. }
  368. if (self.pagination.page * self.pagination.pagesize >= self.pagination.total) {
  369. self.pagination.noMore = true
  370. } else {
  371. self.pagination.noMore = false
  372. }
  373. }
  374. resolve()
  375. }).catch(err => {
  376. reject(err)
  377. }).then(() => {
  378. self.loadingWorksList = false
  379. self.pagination.loading = false
  380. })
  381. })
  382. return promise
  383. },
  384. /**
  385. * 点击一级分类
  386. */
  387. handleClickCategoryOne (id) {
  388. if (id !== this.currentCategoryIndex) {
  389. this.currentCategoryIndex = id
  390. }
  391. },
  392. /**
  393. * 点击二级分类
  394. */
  395. handleClickCategoryTwo (id) {
  396. if (this.mobile) {
  397. // 移动端单选
  398. const index = this.pagination.cate_id_two.indexOf(id)
  399. if (index > -1) {
  400. this.pagination.cate_id_two = []
  401. } else {
  402. this.pagination.cate_id_two = [id]
  403. }
  404. this.pagination.page = 1
  405. this.worksList = []
  406. window.scroll({ top: 0 })
  407. this._getWorksList()
  408. } else {
  409. // web 端多选
  410. const index = this.pagination.cate_id_two.indexOf(id)
  411. if (index > -1) {
  412. // 已选择,移除
  413. this.pagination.cate_id_two.splice(index, 1)
  414. } else {
  415. // 未选择,添加
  416. this.pagination.cate_id_two.push(id)
  417. }
  418. this.pagination.page = 1
  419. this._getWorksList()
  420. }
  421. },
  422. /**
  423. * 展开二级分类
  424. */
  425. handleClickExpandCategory () {
  426. this.categoryExpanded = !this.categoryExpanded
  427. },
  428. /**
  429. * 分页页码改变时
  430. */
  431. handlePageChange (val) {
  432. this.pagination.page = val
  433. this._getWorksList()
  434. },
  435. /**
  436. * mobile 加载更多
  437. */
  438. handleLoadMoreWorks () {
  439. if (this.pagination.loading) {
  440. return
  441. }
  442. this.pagination.page++
  443. this._getWorksList()
  444. },
  445. /**
  446. * 弹出分类选择 drawer
  447. */
  448. handleShowCategoryDrawer () {
  449. this.showCategoryDrawer = true
  450. },
  451. /**
  452. * 点击 mobile 分类 drawer 一级分类
  453. */
  454. handleClickDrawerCategoryOne (id) {
  455. if (id !== this.currentDrawerCategoryIndex) {
  456. this.currentDrawerCategoryIndex = id
  457. }
  458. },
  459. /**
  460. * 点击 mobile 分类 drawer 二级分类
  461. */
  462. handleClickDrawerCategoryTwo (id) {
  463. const index = this.pagination.cate_id_two.indexOf(id)
  464. if (index > -1) {
  465. this.pagination.cate_id_two = []
  466. } else {
  467. this.pagination.cate_id_two = [id]
  468. }
  469. this.showCategoryDrawer = false
  470. this.pagination.page = 1
  471. this.worksList = []
  472. window.scroll({ top: 0 })
  473. this._getWorksList()
  474. },
  475. /**
  476. * 点击 mobile 每一项列表
  477. */
  478. handleClickWorkItem (wid) {
  479. if (this.deviceType.ios || this.deviceType.android) {
  480. let jumpUrl = `${this.baseUrl}/w/${wid}`
  481. location.href = `proginn://webview?url=${jumpUrl}`
  482. } else {
  483. location.href = `${this.baseUrl}/w/${wid}`
  484. }
  485. }
  486. }
  487. }
  488. </script>
  489. <style lang="scss" scoped>
  490. @import "@/assets/css/work_down/index.scss";
  491. </style>
  492. <style lang="scss">
  493. .category-drawer {
  494. .el-drawer {
  495. height: 100vh !important;
  496. .el-drawer__body {
  497. position: relative;
  498. width: 100%;
  499. display: flex;
  500. }
  501. }
  502. .drawer-category-one {
  503. width: 100px;
  504. height: 100vh;
  505. padding-bottom: 34px;
  506. background: #f4f5f9;
  507. overflow-x: hidden;
  508. overflow-y: auto;
  509. -webkit-overflow-scrolling: touch;
  510. &::-webkit-scrollbar {
  511. display: none;
  512. }
  513. .drawer-category-one-item {
  514. width: 100%;
  515. height: 50px;
  516. line-height: 50px;
  517. text-align: center;
  518. font-size: 15px;
  519. font-family: PingFangSC, PingFangSC-Medium;
  520. font-weight: 500;
  521. color: #222222;
  522. background: inherit;
  523. &.active {
  524. color: #308eff;
  525. background: #ffffff;
  526. }
  527. }
  528. }
  529. .drawer-category-two {
  530. width: calc(100% - 100px);
  531. height: 100vh;
  532. padding: 4px 10px 34px;
  533. background: #ffffff;
  534. overflow-x: hidden;
  535. overflow-y: auto;
  536. -webkit-overflow-scrolling: touch;
  537. &::-webkit-scrollbar {
  538. display: none;
  539. }
  540. .drawer-category-two-wrapper {
  541. width: 100%;
  542. display: flex;
  543. flex-wrap: wrap;
  544. .drawer-category-two-item {
  545. margin: 8px 8px 0 0;
  546. padding: 0 12px;
  547. height: 35px;
  548. line-height: 35px;
  549. background: rgba(244,245,249,.8);
  550. border-radius: 4px;
  551. // opacity: 0.8;
  552. font-size: 13px;
  553. font-family: PingFangSC, PingFangSC-Regular;
  554. font-weight: 400;
  555. color: #222222;
  556. &.active {
  557. height: 33px;
  558. line-height: 33px;
  559. border: 1px solid #308eff;
  560. background: #ffffff;
  561. font-size: 12px;
  562. font-family: PingFangSC, PingFangSC-Medium;
  563. font-weight: 500;
  564. color: #308eff;
  565. }
  566. }
  567. }
  568. }
  569. }
  570. .wx-header {
  571. position: fixed;
  572. z-index: 11;
  573. }
  574. </style>