index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <template>
  2. <div class="reporter">
  3. <Header
  4. :headerBg="'#00ADEF'"
  5. :headerBorder="'#5C5C5C'"
  6. :userBg="'rgba(0, 0, 0, 0.24)'"
  7. :LoginNavIndex="3"
  8. />
  9. <!-- <ul class="option">
  10. <li class="option-item" :class="[typeValue===indexo?'active':'']" v-for="(itemo,indexo) in optionList" :key="indexo" @click="handleClick(indexo)">
  11. <span>{{itemo.label}}</span>
  12. </li>
  13. </ul> -->
  14. <div class="content-top">
  15. <img src="../../assets/reporter-logo.png" />
  16. <el-input placeholder="搜索" v-model="searchInput" maxlength="100">
  17. <i
  18. slot="suffix"
  19. class="el-input__icon el-icon-search"
  20. @click="getData(1)"
  21. style="cursor: pointer"
  22. ></i>
  23. </el-input>
  24. <el-button
  25. type="primary"
  26. @click="changePublist"
  27. size="small"
  28. v-if="userMessage"
  29. >发布</el-button
  30. >
  31. <span v-else></span>
  32. </div>
  33. <ul>
  34. <li
  35. class="label-item"
  36. :class="[labelActiveIndex === indexL ? 'active' : '']"
  37. v-for="(itemL, indexL) in labelList"
  38. :key="indexL"
  39. @click="changeLabelIndex(indexL)"
  40. >
  41. # {{ itemL }}
  42. </li>
  43. </ul>
  44. <div class="waterfall">
  45. <vue-waterfall-easy
  46. ref="waterfall"
  47. :imgsArr="imgsArr"
  48. @scrollReachBottom="getData"
  49. >
  50. <div class="info" slot-scope="props">
  51. <div @click="lookDetail(props.value.id)">
  52. <el-image
  53. class="image"
  54. :src="props.value.cover_img_url"
  55. :fit="'cover'"
  56. :style="{
  57. width: '246px',
  58. height: Math.random() * (260 - 180) + 180 + 'px',
  59. borderRadius: '8px',
  60. }"
  61. v-if="props.value.cover_img_url"
  62. >
  63. <div
  64. slot="placeholder"
  65. class="image-slot"
  66. :style="'line-height:130px'"
  67. >
  68. 加载中<span class="dot">...</span>
  69. </div>
  70. </el-image>
  71. <h3>
  72. {{ props.value.art_title }}
  73. </h3>
  74. <p>
  75. {{ props.value.art_content }}
  76. </p>
  77. </div>
  78. <!-- <p>鼓浪屿实行最大承载量控制,每天最高5万人次,其中,游客3.5万人次,市民1.5万人次。鼓浪屿派出所出动无人机开展高空巡查,对重点区域动态监测客流,靠前化解风险隐患,守护群众安全。</p> -->
  79. <div class="creator-info">
  80. <el-image
  81. :src="
  82. props.value.creator_img_url
  83. ? props.value.creator_img_url
  84. : require('../../assets/avatar.png')
  85. "
  86. fit="cover"
  87. style="width: 24px; height: 24px; margin-right: 12px"
  88. >
  89. </el-image>
  90. <span class="name">{{ props.value.creator_name }}</span>
  91. <div class="ding-box">
  92. <svg-icon
  93. @click="handleLike(props.value)"
  94. icon-class="like"
  95. className="like-icon"
  96. v-if="props.value.ding_opt === 1"
  97. ></svg-icon>
  98. <svg-icon
  99. @click="handleLike(props.value)"
  100. icon-class="like-line"
  101. className="chat"
  102. v-else
  103. ></svg-icon>
  104. <span>{{ props.value.ding_count }}</span>
  105. <svg-icon
  106. @click="lookDetail(props.value.id)"
  107. icon-class="chat-line"
  108. className="chat"
  109. ></svg-icon>
  110. <span>{{ props.value.comment_count }}</span>
  111. </div>
  112. <el-dropdown trigger="click" @command="handleChange">
  113. <span class="el-dropdown-link">
  114. <img src="../../assets/dropdown-icon.png" />
  115. </span>
  116. <el-dropdown-menu slot="dropdown">
  117. <el-dropdown-item :command="'edit&&&' + props.value.id"
  118. >编辑</el-dropdown-item
  119. >
  120. <el-dropdown-item
  121. :command="'delete&&&' + props.value.id"
  122. class="red-btn"
  123. >删除</el-dropdown-item
  124. >
  125. </el-dropdown-menu>
  126. </el-dropdown>
  127. </div>
  128. </div>
  129. <div slot="waterfall-over"></div>
  130. </vue-waterfall-easy>
  131. </div>
  132. <div class="nodata" v-if="imgsArr.length === 0">
  133. <img src="../../assets/nodata.png" />
  134. <p>还没有发布内容</p>
  135. </div>
  136. <el-dialog
  137. :visible.sync="publishFlag"
  138. :show-close="false"
  139. :close-on-click-modal="false"
  140. width="800px"
  141. :modal="false"
  142. class="login-dialog publish-report-box"
  143. v-if="publishFlag"
  144. >
  145. <publish-report
  146. :editId="editId"
  147. :info="reportInfo"
  148. @closeDialog="closeDialog"
  149. ></publish-report>
  150. </el-dialog>
  151. <el-dialog
  152. :visible.sync="reportDetailFlag"
  153. :show-close="false"
  154. :close-on-click-modal="false"
  155. width="1286px"
  156. :modal="false"
  157. class="login-dialog"
  158. v-if="reportDetailFlag"
  159. >
  160. <report-detail
  161. :info="reportInfo"
  162. @closeDetail="closeDetail"
  163. ></report-detail>
  164. </el-dialog>
  165. </div>
  166. </template>
  167. <script>
  168. //这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  169. //例如:import 《组件名称》from ‘《组件路径》';
  170. import Header from "../../components/Header.vue";
  171. import vueWaterfallEasy from "vue-waterfall-easy";
  172. import { getLogin } from "@/api/ajax";
  173. import PublishReport from "./components/PublishReport.vue";
  174. import ReportDetail from "./components/ReportDetail.vue";
  175. import { getToken } from "@/utils/auth";
  176. export default {
  177. //import引入的组件需要注入到对象中才能使用
  178. components: { Header, vueWaterfallEasy, PublishReport, ReportDetail },
  179. props: {},
  180. data() {
  181. //这里存放数据
  182. return {
  183. optionList: [
  184. {
  185. label: "栏目 1",
  186. },
  187. {
  188. label: "栏目 2",
  189. },
  190. {
  191. label: "栏目 3",
  192. },
  193. {
  194. label: "栏目 4",
  195. },
  196. {
  197. label: "栏目 5",
  198. },
  199. // ,
  200. // {
  201. // label: '合刊',
  202. // img: 'hekan',
  203. // number: '6'
  204. // }
  205. ],
  206. typeValue: 0,
  207. loading: false,
  208. imgsArr: [],
  209. page: 0,
  210. pageSize: 50,
  211. pageNumber: 1,
  212. publishFlag: false, // 发布弹窗
  213. searchInput: "",
  214. labelList: [],
  215. labelActiveIndex: null,
  216. reportDetailFlag: false,
  217. reportInfo: null,
  218. userMessage: getToken() ? JSON.parse(getToken()) : null,
  219. };
  220. },
  221. //计算属性 类似于data概念
  222. computed: {},
  223. //监控data中数据变化
  224. watch: {},
  225. //方法集合
  226. methods: {
  227. handleClick(value) {
  228. this.typeValue = value;
  229. },
  230. getData(page) {
  231. if (page) {
  232. this.pageNumber = page;
  233. this.imgsArr = [];
  234. }
  235. let MethodName = "/PaperServer/Client/Xjz/XjzArticleList";
  236. let data = {
  237. page_capacity: this.pageSize,
  238. cur_page: this.pageNumber,
  239. art_tag:
  240. this.labelActiveIndex !== null
  241. ? this.labelList[this.labelActiveIndex]
  242. : "",
  243. };
  244. getLogin(MethodName, data).then((res) => {
  245. if (res.status === 1) {
  246. this.labelList = res.tags;
  247. this.imgsArr = this.imgsArr.concat(res.data.list);
  248. if (this.imgsArr.length === 0) return;
  249. if (this.pageNumber === res.data.total_page) {
  250. this.$refs.waterfall.waterfallOver();
  251. } else {
  252. this.pageNumber++;
  253. }
  254. }
  255. });
  256. },
  257. // 点击发布按钮
  258. changePublist() {
  259. this.editId = "";
  260. this.reportInfo = null;
  261. this.publishFlag = true;
  262. },
  263. // 点击label
  264. changeLabelIndex(index) {
  265. if (this.labelActiveIndex === index) {
  266. this.labelActiveIndex = null;
  267. } else {
  268. this.labelActiveIndex = index;
  269. }
  270. this.getData(1);
  271. },
  272. closeDialog() {
  273. this.publishFlag = false;
  274. this.getData(1);
  275. },
  276. // 查看详情
  277. lookDetail(id, flag) {
  278. let MethodName = "/PaperServer/Client/Xjz/XjzArticleDetail";
  279. let data = {
  280. id: id,
  281. };
  282. getLogin(MethodName, data).then((res) => {
  283. if (res.status === 1) {
  284. this.reportInfo = res.data;
  285. if (flag) {
  286. this.publishFlag = true;
  287. } else {
  288. this.reportDetailFlag = true;
  289. }
  290. }
  291. });
  292. },
  293. closeDetail() {
  294. this.reportDetailFlag = false;
  295. },
  296. async handleChange(com) {
  297. const arr = com.split("&&&");
  298. if (arr[0] === "edit") {
  299. await this.lookDetail(arr[1], true);
  300. this.editId = arr[1];
  301. } else {
  302. this.handleDel(arr[1]);
  303. }
  304. },
  305. //删除小记者文章
  306. handleDel(id) {
  307. this.$confirm("确定删除吗?", "提示", {
  308. confirmButtonText: "确定",
  309. cancelButtonText: "取消",
  310. type: "warning",
  311. }).then(() => {
  312. let MethodName = "/PaperServer/Client/Xjz/XjzArticleDel";
  313. let data = {
  314. id: id,
  315. };
  316. getLogin(MethodName, data).then((res) => {
  317. if (res.status === 1) {
  318. this.getData(1);
  319. }
  320. });
  321. });
  322. },
  323. // 点赞/取消赞
  324. handleLike(item) {
  325. let MethodName = "/PaperServer/Client/Xjz/XjzArticleOptDing";
  326. let data = {
  327. bound_id: item.id,
  328. ding_opt: item.ding_opt === 1 ? 0 : 1,
  329. };
  330. getLogin(MethodName, data).then((res) => {
  331. if (res.status === 1) {
  332. item.ding_count =
  333. item.ding_opt === 1 ? item.ding_count - 1 : item.ding_count + 1;
  334. item.ding_opt = item.ding_opt === 1 ? 0 : 1;
  335. this.$forceUpdate();
  336. }
  337. });
  338. },
  339. },
  340. //生命周期 - 创建完成(可以访问当前this实例)
  341. created() {},
  342. //生命周期 - 挂载完成(可以访问DOM元素)
  343. mounted() {
  344. this.getData();
  345. let _this = this;
  346. let input = document.querySelector("input");
  347. input.addEventListener("keyup", function (event) {
  348. // 判断是否按下回车键
  349. if (event.keyCode === 13) {
  350. // 回车键被按下,执行你想要的操作
  351. _this.getData(1);
  352. }
  353. });
  354. },
  355. //生命周期-创建之前
  356. beforeCreated() {},
  357. //生命周期-挂载之前
  358. beforeMount() {},
  359. //生命周期-更新之前
  360. beforUpdate() {},
  361. //生命周期-更新之后
  362. updated() {},
  363. //生命周期-销毁之前
  364. beforeDestory() {},
  365. //生命周期-销毁完成
  366. destoryed() {},
  367. //如果页面有keep-alive缓存功能,这个函数会触发
  368. activated() {},
  369. };
  370. </script>
  371. <style lang="scss" scoped>
  372. /* @import url(); 引入css类 */
  373. .reporter {
  374. background: #f7f8fa;
  375. height: calc(100vh - 64px);
  376. .option {
  377. list-style: none;
  378. display: flex;
  379. justify-content: center;
  380. margin: 0;
  381. padding: 0;
  382. background: #00adef;
  383. li {
  384. display: flex;
  385. align-items: center;
  386. border-radius: 30px;
  387. height: 36px;
  388. padding: 7px 20px;
  389. margin: 8px 4px;
  390. cursor: pointer;
  391. &:hover {
  392. background: rgba(255, 255, 255, 0.08);
  393. }
  394. &.active {
  395. background: rgba(255, 255, 255, 0.08);
  396. .icon-img,
  397. span,
  398. b {
  399. color: rgba(255, 255, 255, 0.9);
  400. }
  401. }
  402. .icon-img {
  403. width: 14px;
  404. height: 14px;
  405. margin: 1px 8px 0 0;
  406. color: rgba(255, 255, 255, 0.5);
  407. }
  408. span {
  409. color: rgba(255, 255, 255, 0.5);
  410. font-size: 14px;
  411. line-height: 22px;
  412. }
  413. b {
  414. font-weight: 400;
  415. font-size: 14px;
  416. line-height: 22px;
  417. color: rgba(255, 255, 255, 0.5);
  418. margin-left: 5px;
  419. }
  420. }
  421. }
  422. .main {
  423. width: 1200px;
  424. margin: 0 auto;
  425. padding: 24px 0 0 0;
  426. .searchChangebox {
  427. display: flex;
  428. justify-content: space-between;
  429. .searchChange-box {
  430. display: flex;
  431. }
  432. .searchChange {
  433. display: flex;
  434. align-items: center;
  435. justify-content: space-between;
  436. padding: 4px 12px;
  437. height: 32px;
  438. margin-right: 16px;
  439. border: 1px solid #e5e6eb;
  440. border-radius: 20px;
  441. &.active {
  442. background: #175dff;
  443. > span {
  444. color: #ffffff;
  445. }
  446. .sort {
  447. > div {
  448. svg {
  449. color: #5e89ef;
  450. &.active {
  451. color: #ffffff;
  452. }
  453. }
  454. }
  455. }
  456. }
  457. > span {
  458. font-weight: 400;
  459. font-size: 16px;
  460. line-height: 22px;
  461. color: #000;
  462. margin-right: 4px;
  463. }
  464. .sort {
  465. cursor: pointer;
  466. height: 20px;
  467. > div {
  468. font-size: 0;
  469. svg {
  470. width: 11px;
  471. height: 11px;
  472. color: #c2c2c2;
  473. padding: 3px 2px 2px 2px;
  474. &.icon-down {
  475. height: 9px;
  476. padding: 0 2px 2px 2px;
  477. }
  478. }
  479. }
  480. }
  481. }
  482. .input-search {
  483. width: 220px;
  484. }
  485. }
  486. .show-title {
  487. color: #1f2c5c;
  488. margin: 24px 0 0 0;
  489. font-weight: 500;
  490. font-size: 24px;
  491. line-height: 32px;
  492. b {
  493. margin-left: 16px;
  494. color: #ed5f00;
  495. }
  496. }
  497. .list {
  498. margin-top: 28px;
  499. display: flex;
  500. flex-wrap: wrap;
  501. height: calc(100vh - 256px);
  502. overflow-y: scroll;
  503. &::-webkit-scrollbar {
  504. display: none;
  505. }
  506. > div {
  507. width: 200px;
  508. border-radius: 8px;
  509. overflow: hidden;
  510. background: #ffffff;
  511. margin-bottom: 24px;
  512. }
  513. .tips {
  514. width: 100%;
  515. text-align: center;
  516. font-size: 12px;
  517. color: #929ca8;
  518. }
  519. }
  520. }
  521. .waterfall {
  522. position: absolute;
  523. top: 216px;
  524. bottom: 0;
  525. left: 0;
  526. width: 100%;
  527. }
  528. .info {
  529. text-align: center;
  530. font-size: 0;
  531. h3 {
  532. margin: 8px 0;
  533. overflow: hidden;
  534. color: #000;
  535. font-size: 14px;
  536. font-weight: 500;
  537. line-height: 22px;
  538. word-break: break-word;
  539. display: -webkit-box;
  540. -webkit-box-orient: vertical;
  541. -webkit-line-clamp: 2;
  542. text-overflow: ellipsis;
  543. overflow: hidden;
  544. text-align: left;
  545. padding: 0 8px;
  546. }
  547. > div {
  548. > p {
  549. color: rgba(0, 0, 0, 0.65);
  550. font-size: 14px;
  551. font-weight: 400;
  552. line-height: 22px;
  553. word-break: break-word;
  554. display: -webkit-box;
  555. -webkit-box-orient: vertical;
  556. -webkit-line-clamp: 2;
  557. text-overflow: ellipsis;
  558. overflow: hidden;
  559. text-align: left;
  560. padding: 0 8px;
  561. margin: 0 0 8px 0;
  562. }
  563. }
  564. .creator-info {
  565. text-align: left;
  566. padding: 0 8px;
  567. display: flex;
  568. align-items: center;
  569. > span {
  570. color: #2f3742;
  571. font-size: 14px;
  572. font-weight: 400;
  573. line-height: 22px;
  574. flex: 1;
  575. overflow: hidden;
  576. }
  577. .ding-box {
  578. color: rgba(0, 0, 0, 0.3);
  579. font-size: 12px;
  580. font-weight: 400;
  581. line-height: 20px;
  582. display: flex;
  583. align-items: center;
  584. .svg-icon {
  585. width: 16px;
  586. height: 16px;
  587. &.chat {
  588. color: rgba(0, 0, 0, 0.65);
  589. }
  590. &.like-icon {
  591. color: #f62727;
  592. }
  593. }
  594. span {
  595. margin: 0 8px 0 3px;
  596. }
  597. }
  598. }
  599. }
  600. .content-top {
  601. display: flex;
  602. justify-content: space-between;
  603. padding: 32px 0;
  604. max-width: 1440px;
  605. margin: 0 auto;
  606. > img {
  607. height: 32px;
  608. }
  609. .el-input {
  610. width: 480px;
  611. border-radius: 40px;
  612. background: #fff;
  613. }
  614. .el-button {
  615. width: 108px;
  616. text-align: center;
  617. border-radius: 40px;
  618. font-size: 14px;
  619. }
  620. }
  621. ul {
  622. padding: 0;
  623. max-width: 1440px;
  624. margin: 0 auto;
  625. display: flex;
  626. li.label-item {
  627. padding: 4px 12px;
  628. border-radius: 20px;
  629. margin-right: 8px;
  630. cursor: pointer;
  631. color: #787878;
  632. font-size: 12px;
  633. font-weight: 400;
  634. line-height: 20px;
  635. &.active {
  636. background: #ececec;
  637. color: #000000;
  638. }
  639. }
  640. }
  641. .el-dropdown-link {
  642. width: 16px;
  643. height: 16px;
  644. border-radius: 4px;
  645. display: inline-block;
  646. margin-top: 2px;
  647. &.el-dropdown-selfdefine:focus:active {
  648. background: #e6e6e6;
  649. }
  650. > img {
  651. width: 16px;
  652. height: 16px;
  653. }
  654. }
  655. }
  656. :deep .el-dropdown-menu__item {
  657. line-height: 24px;
  658. padding: 2px 8px;
  659. border-radius: 3px;
  660. width: 56px;
  661. text-align: center;
  662. &:hover {
  663. color: #000;
  664. }
  665. }
  666. .red-btn {
  667. color: #ec1f1f;
  668. &:hover {
  669. color: #ec1f1f;
  670. }
  671. }
  672. </style>
  673. <style lang="scss">
  674. .reporter {
  675. .el-input__inner {
  676. border-radius: 40px;
  677. border: none;
  678. }
  679. }
  680. .publish-report-box {
  681. .el-dialog__body {
  682. padding: 24px;
  683. }
  684. }
  685. .vue-waterfall-easy {
  686. // width: 1440px !important;
  687. // margin-left: -720px !important;
  688. .img-inner-box {
  689. box-shadow: none !important;
  690. }
  691. .img-box {
  692. padding: 12px !important;
  693. width: 270px !important;
  694. }
  695. }
  696. </style>