alumni-square.vue 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354
  1. <template>
  2. <div class="content-box">
  3. <div class="left">
  4. <!-- <el-icon :size="23" class="camera"><VideoCameraFilled /></el-icon> -->
  5. <span class="cameratxt">广场信息管理</span>
  6. </div>
  7. <div class="scroll">
  8. <div class="middle">
  9. <div class="filter">
  10. <div class="condition">
  11. <span>发帖人 :</span>
  12. <el-input
  13. clearable
  14. v-model.trim="searchInput.userName"
  15. class="w-50 m-2"
  16. placeholder="请输入发帖人"
  17. style="width: 180px"
  18. />
  19. </div>
  20. <div class="condition">
  21. <span>审核状态 :</span>
  22. <el-select
  23. clearable
  24. v-model="searchInput.isPass"
  25. placeholder="请选择审核状态"
  26. >
  27. <el-option label="待审核" :value="1" />
  28. <el-option label="已通过" :value="2" />
  29. <el-option label="已拒绝" :value="3" />
  30. </el-select>
  31. </div>
  32. <div class="condition">
  33. <span>创建时间 :</span>
  34. <el-date-picker
  35. v-model="searchInput.createTime"
  36. unlink-panels
  37. type="datetimerange"
  38. range-separator="-"
  39. start-placeholder="起始时间"
  40. end-placeholder="结束时间"
  41. format="YYYY-MM-DD HH:mm:ss"
  42. value-format="YYYY-MM-DD HH:mm:ss"
  43. placeholder="请选择日期"
  44. />
  45. </div>
  46. <el-button
  47. style="margin-left: 20px"
  48. color="rgba(38, 151, 255, 1)"
  49. type="primary"
  50. class="search"
  51. @click="searchBtn"
  52. ><span>查询</span></el-button
  53. >
  54. <el-button @click="resetBtn" plain color="rgba(43, 153, 255, 1)"
  55. >重置</el-button
  56. >
  57. </div>
  58. <!-- 按钮列表 -->
  59. <div class="gongneng">
  60. <el-button
  61. type="primary"
  62. style="margin-left: 0"
  63. color="rgba(38, 151, 255, 1)"
  64. @click="addlist"
  65. >发布动态</el-button
  66. >
  67. </div>
  68. </div>
  69. <div class="footer" v-loading="loading">
  70. <div class="card_all">
  71. <el-space wrap>
  72. <el-card
  73. style="max-width: 480px"
  74. v-for="i in tableData.list"
  75. :key="i.id"
  76. >
  77. <template #header>
  78. <div class="card-header">
  79. <img v-viewer :src="i.image" alt="" />
  80. <div class="issuer">
  81. <p>{{ i.userName }}</p>
  82. <span>{{ i.updateTime }}</span>
  83. </div>
  84. </div>
  85. </template>
  86. <p @click="viewDetails(i)" class="content">
  87. {{ i.content }}
  88. </p>
  89. <div class="img-preview-list" style="height: 92px;overflow: hidden;">
  90. <div
  91. class="img-item"
  92. v-for="(url, index) in i.imageLists"
  93. :key="index"
  94. style="height: 80px;margin-bottom: 10px;"
  95. >
  96. <video
  97. v-if="isMp4Link(url)"
  98. class="preview-img"
  99. :src="url"
  100. controls
  101. ></video>
  102. <img
  103. v-else
  104. :src="url"
  105. alt="图片预览"
  106. class="preview-img"
  107. v-viewer
  108. @click="handlePreview(i.imageLists, index)"
  109. />
  110. </div>
  111. </div>
  112. <div class="dianzan">
  113. <div class="icon">
  114. <img src="../../assets/img/pinglun.png" alt="" />
  115. <span>{{ i.commentNum }}</span>
  116. </div>
  117. <div class="icon">
  118. <img src="../../assets/img/dianzan.png" alt="" />
  119. <span>{{ i.likeNum }}</span>
  120. </div>
  121. </div>
  122. <template #footer>
  123. <div class="card-footer">
  124. <div class="footer_left">
  125. <img
  126. v-if="i.passName == '待审核'"
  127. style="width: 25px; margin-right: 5px"
  128. src="../../assets/img/yuandian.png"
  129. alt=""
  130. />
  131. <img
  132. v-if="i.passName == '已通过'"
  133. style="width: 25px; margin-right: 5px"
  134. src="../../assets/img/yuandian2.png"
  135. alt=""
  136. />
  137. <img
  138. v-if="i.passName == '已拒绝'"
  139. style="width: 25px; margin-right: 5px"
  140. src="../../assets/img/yuandian3.png"
  141. alt=""
  142. />
  143. <span style="margin-right: 20px">{{ i.passName }}</span>
  144. <span>{{ i.passTime }}</span>
  145. </div>
  146. <el-dropdown placement="bottom" :hide-on-click="false">
  147. <el-icon :size="20"><MoreFilled /></el-icon>
  148. <template #dropdown>
  149. <el-dropdown-menu v-if="i.passName == '待审核'">
  150. <el-dropdown-item @click="operationPassChange(i)"
  151. ><span style="color: #0095ff"
  152. >通过</span
  153. ></el-dropdown-item
  154. >
  155. <el-dropdown-item @click="operationRefuseChange(i)"
  156. ><span style="color: #ff8d1a"
  157. >拒绝</span
  158. ></el-dropdown-item
  159. >
  160. <el-dropdown-item @click="deleteS(i)"
  161. ><span style="color: #d43030"
  162. >删除</span
  163. ></el-dropdown-item
  164. >
  165. </el-dropdown-menu>
  166. <el-dropdown-menu
  167. v-if="i.passName == '已通过' || i.passName == '已拒绝'"
  168. >
  169. <el-dropdown-item @click="deleteS(i)"
  170. ><span style="color: #d43030"
  171. >删除</span
  172. ></el-dropdown-item
  173. >
  174. </el-dropdown-menu>
  175. </template>
  176. </el-dropdown>
  177. </div>
  178. </template>
  179. </el-card>
  180. </el-space>
  181. </div>
  182. <!-- 分页组件 -->
  183. <div class="pageSize">
  184. <span></span>
  185. <el-pagination
  186. background
  187. :current-page="currentPage"
  188. :page-size="pageSize"
  189. :page-sizes="[10, 20, 30, 40]"
  190. layout="total,sizes, prev, pager, next, jumper, slot"
  191. :total="total"
  192. @size-change="handleSizeChange"
  193. @update:current-page="handleCurrentChange"
  194. />
  195. </div>
  196. </div>
  197. </div>
  198. <!-- 添加账号弹窗 -->
  199. <el-dialog
  200. class="addStaff"
  201. v-model="addDialogVisible"
  202. :close-on-click-modal="false"
  203. :close-on-press-escape="false"
  204. :title="dialongTitle"
  205. align-center
  206. width="650"
  207. :before-close="cancelAdd"
  208. destroy-on-close
  209. draggable
  210. >
  211. <el-form
  212. ref="ruleFormRef"
  213. :model="ruleForm"
  214. :rules="rules"
  215. label-width="100px"
  216. class="demo-ruleForm"
  217. :size="formSize"
  218. label-position="right"
  219. status-icon
  220. >
  221. <el-form-item label="组织分类 :" prop="categoryId">
  222. <!-- <el-select
  223. v-model="ruleForm.categoryId"
  224. clearable
  225. placeholder="请选择组织分类"
  226. >
  227. <el-option
  228. v-for="i in categoryData"
  229. :key="i.id"
  230. :label="i.name"
  231. :value="i.id"
  232. />
  233. </el-select> -->
  234. <el-select
  235. v-model="ruleForm.categoryId"
  236. filterable
  237. clearable
  238. remote
  239. reserve-keyword
  240. placeholder="请搜索或选择组织"
  241. :remote-method="remoteMethod"
  242. :loading="clubLoading"
  243. >
  244. <el-option
  245. v-for="i in clubData"
  246. :key="i.id"
  247. :label="i.name"
  248. :value="i.id"
  249. />
  250. </el-select>
  251. </el-form-item>
  252. <el-form-item label="内容 :" prop="content">
  253. <el-input
  254. v-model.trim="ruleForm.content"
  255. placeholder="请输入内容"
  256. clearable
  257. :autosize="{ minRows: 4 }"
  258. type="textarea"
  259. />
  260. </el-form-item>
  261. <el-form-item label="照片 :" prop="imageLists">
  262. <div class="img-preview-list">
  263. <div
  264. class="img-item"
  265. v-for="(url, index) in ruleForm.imageLists"
  266. :key="index"
  267. >
  268. <video
  269. v-if="isMp4Link(url)"
  270. class="preview-img"
  271. :src="url"
  272. controls
  273. ></video>
  274. <img
  275. v-else
  276. :src="url"
  277. alt="图片预览"
  278. class="preview-img"
  279. v-viewer
  280. @click="handlePreview(ruleForm.imageLists, index)"
  281. />
  282. <span class="delete-btn" @click="handleDelete(index)">
  283. <el-icon><Delete /></el-icon>
  284. </span>
  285. </div>
  286. <el-upload
  287. action="#"
  288. :auto-upload="false"
  289. :on-change="handleFileChange"
  290. :before-upload="beforeUpload"
  291. class="upload-btn"
  292. accept=".jpg,.jpeg,.png,.gif,.mp4,.avi,.mov,.wmv,.flv"
  293. >
  294. <el-icon><Plus /></el-icon>
  295. <span class="upload-txt">点击图片或视频</span>
  296. </el-upload>
  297. </div>
  298. </el-form-item>
  299. <el-form-item class="options">
  300. <el-button @click="cancelAdd">取消</el-button>
  301. <el-button
  302. color="rgba(0, 97, 255, 1)"
  303. class="queding"
  304. type="primary"
  305. @click="submitAdd(ruleFormRef)"
  306. >
  307. 确定
  308. </el-button>
  309. </el-form-item>
  310. </el-form>
  311. </el-dialog>
  312. <el-dialog
  313. class="addStaff"
  314. v-model="operationVisible"
  315. :close-on-click-modal="false"
  316. :close-on-press-escape="false"
  317. :title="operationTitle"
  318. align-center
  319. width="540"
  320. :before-close="cancelOperation"
  321. destroy-on-close
  322. draggable
  323. >
  324. <el-form
  325. ref="operationRef"
  326. :model="operationRuleForm"
  327. :rules="operationRules"
  328. label-width="90px"
  329. class="demo-ruleForm"
  330. :size="formSize"
  331. label-position="right"
  332. status-icon
  333. >
  334. <el-form-item
  335. label="审批意见 :"
  336. :prop="operationTitle == '拒绝审批' ? 'passValue' : ''"
  337. >
  338. <el-input
  339. v-model.trim="operationRuleForm.passValue"
  340. placeholder="请输入审批意见"
  341. clearable
  342. :autosize="{ minRows: 4 }"
  343. type="textarea"
  344. />
  345. </el-form-item>
  346. <el-form-item class="options">
  347. <el-button @click="cancelOperation">取消</el-button>
  348. <el-button
  349. color="rgba(0, 97, 255, 1)"
  350. class="queding"
  351. type="primary"
  352. @click="operationSubmitAdd(operationRef)"
  353. >
  354. 确定
  355. </el-button>
  356. </el-form-item>
  357. </el-form>
  358. </el-dialog>
  359. <!-- 详情弹窗 -->
  360. <el-dialog
  361. class="details"
  362. v-model="detailsVisible"
  363. :close-on-click-modal="false"
  364. :close-on-press-escape="false"
  365. title="详情"
  366. align-center
  367. width="680"
  368. :before-close="cancelDetails"
  369. destroy-on-close
  370. draggable
  371. >
  372. <div>
  373. <div class="card-header">
  374. <img style="border-radius: 50%" :src="detailData.image" alt="" />
  375. <div class="issuer">
  376. <p>{{ detailData.userName }}</p>
  377. <span>{{ detailData.updateTime }}</span>
  378. </div>
  379. </div>
  380. <p style="text-indent: 2em; line-height: 1.8">
  381. {{ detailData.content }}
  382. </p>
  383. <div class="img-preview-list" style="margin-bottom: 15px;">
  384. <div
  385. class="img-item"
  386. v-for="(url, index) in detailData.imageLists"
  387. :key="index"
  388. >
  389. <video
  390. v-if="isMp4Link(url)"
  391. class="preview-img"
  392. :src="url"
  393. controls
  394. ></video>
  395. <img
  396. v-else
  397. :src="url"
  398. alt="图片预览"
  399. class="preview-img"
  400. v-viewer
  401. @click="handlePreview(detailData.imageLists, index)"
  402. />
  403. <span class="delete-btn" @click="handleDelete(index)">
  404. <el-icon><Delete /></el-icon>
  405. </span>
  406. </div>
  407. </div>
  408. <p class="comment-count">{{ detailData.commentNum }}条评论数</p>
  409. <div class="card-footer" v-loading="commentLoading">
  410. <div class="user" v-for="(i, index) in commentData" :key="i.id">
  411. <img style="border-radius: 0" :src="i.image" alt="" />
  412. <div class="user-info">
  413. <div class="upvote">
  414. <span class="username">{{ i.commentName }}</span>
  415. <div class="num">
  416. <img src="../../assets/img/upvote.png" alt="" />
  417. <span>{{ i.likeNum }}</span>
  418. </div>
  419. </div>
  420. <div class="comment">
  421. <p style="margin: 5px 0">{{ i.content }}</p>
  422. <span style="font-size: 12px; margin-bottom: 10px">{{
  423. i.createTime
  424. }}</span>
  425. <div
  426. v-if="i.commentNum > 0 && !i.children"
  427. style="
  428. font-size: 12px;
  429. margin-bottom: 10px;
  430. cursor: pointer;
  431. display: flex;
  432. align-items: center;
  433. "
  434. @click="openComment(i, index)"
  435. >
  436. 查看全部 {{ i.commentNum }} 回复
  437. <el-icon><ArrowRightBold /></el-icon>
  438. </div>
  439. <div v-else>
  440. <div
  441. v-loading="commentLoading"
  442. class="user"
  443. v-for="j in i.children"
  444. :key="j.id"
  445. >
  446. <img
  447. style="border-radius: 0; margin: 10px 10px 0 0"
  448. :src="j.image"
  449. alt=""
  450. />
  451. <div class="user-info">
  452. <div class="upvote">
  453. <span class="username">{{ j.commentName }}</span>
  454. <div class="num">
  455. <img src="../../assets/img/upvote.png" alt="" />
  456. <span>{{ j.likeNum }}</span>
  457. </div>
  458. </div>
  459. <div class="comment">
  460. <p style="margin: 5px 0">{{ j.content }}</p>
  461. <span style="font-size: 12px; margin-bottom: 10px">{{
  462. j.createTime
  463. }}</span>
  464. </div>
  465. </div>
  466. </div>
  467. </div>
  468. </div>
  469. </div>
  470. </div>
  471. <!-- <div class="user">
  472. <img src="../../assets/img/nanchang.png" alt="" />
  473. <div class="user-info">
  474. <div class="upvote">
  475. <span class="username">用户名</span>
  476. <div class="num">
  477. <img src="../../assets/img/upvote.png" alt="" />
  478. <span>1</span>
  479. </div>
  480. </div>
  481. <div class="comment">
  482. <p>内容内容内容内容内容内容内容内容内容内容</p>
  483. <span>2016-12-12 12:30:00</span>
  484. </div>
  485. </div>
  486. </div> -->
  487. </div>
  488. </div>
  489. </el-dialog>
  490. </div>
  491. </template>
  492. <script setup>
  493. import {
  494. ref,
  495. watch,
  496. reactive,
  497. nextTick,
  498. onBeforeMount,
  499. onUnmounted,
  500. } from "vue";
  501. import { useRouter } from "vue-router";
  502. import { genFileId, ElMessage, ElMessageBox } from "element-plus";
  503. import { dayjs } from "element-plus";
  504. import lodash from "lodash";
  505. import {
  506. MoreFilled,
  507. ArrowRightBold,
  508. Delete,
  509. Plus,
  510. } from "@element-plus/icons-vue";
  511. import { storeToRefs } from "pinia";
  512. import { useCounterStore } from "@/stores/index";
  513. import {
  514. insertPosts,
  515. queryCategoryDatas,
  516. toExaminePosts,
  517. deletePostsById,
  518. queryPostsPage,
  519. queryCommetns,
  520. } from "@/api/alumni-square";
  521. import { uploadFile } from "@/api/uploadFile";
  522. import { api as viewerApi } from "v-viewer";
  523. const router = useRouter();
  524. const store = useCounterStore();
  525. // 为避免解构时失去响应性
  526. const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
  527. // 表格数据
  528. const loading = ref(false);
  529. const tableData = reactive({
  530. list: [{}],
  531. });
  532. const activeIndex = ref(); // 默认跳转路由
  533. const dialongTitle = ref("新增账号"); // 弹窗标题
  534. const searchInput = reactive({
  535. userName: "",
  536. isPass: null,
  537. createTime: null,
  538. }); // 搜索按钮数据
  539. const currentPage = ref(1); // 当前页
  540. const pageSize = ref(10);
  541. const total = ref(0); // 当前总数
  542. const selectIds = ref([]); // 勾选的全部数据
  543. const addDialogVisible = ref(false); // 控制添加账号弹窗
  544. // 表单数据
  545. const formSize = ref("default");
  546. const ruleFormRef = ref();
  547. const ruleForm = reactive({
  548. categoryId: "",
  549. content: "",
  550. imageLists: [],
  551. id: "",
  552. });
  553. // 表单验证
  554. const rules = reactive({
  555. categoryId: [
  556. { required: true, message: "组织分类不能为空", trigger: "blur" },
  557. ],
  558. content: [{ required: true, message: "内容不能为空", trigger: "blur" }],
  559. // imageLists: [{ required: true, message: "图片或视频不能为空", trigger: "blur" }],
  560. });
  561. const detailsVisible = ref(false); // 详情弹窗
  562. const detailData = ref();
  563. const commentData = ref();
  564. const commentLoading = ref(false);
  565. const operationVisible = ref();
  566. const operationTitle = ref();
  567. const operationRef = ref(); // 操作按钮
  568. const operationRuleForm = reactive({
  569. passValue: "",
  570. id: "",
  571. });
  572. // 表单验证
  573. const operationRules = reactive({
  574. passValue: [{ required: true, message: "审批意见不能为空", trigger: "blur" }],
  575. });
  576. // 获取账户列表
  577. const getList = async () => {
  578. loading.value = true;
  579. let params = {
  580. currentPage: currentPage.value, // 当前页
  581. pageCount: pageSize.value, // 一页数据条数
  582. userName: searchInput.userName,
  583. isPass: searchInput.isPass,
  584. };
  585. if (searchInput.createTime) {
  586. params.startTime = searchInput.createTime[0];
  587. params.endTime = searchInput.createTime[1];
  588. }
  589. queryPostsPage(params).then((res) => {
  590. console.log(res, "获取帖子分页数据");
  591. if (res.code == 200) {
  592. tableData.list = res.data.list;
  593. total.value = res.data.totalCount;
  594. loading.value = false;
  595. } else {
  596. loading.value = false;
  597. ElMessage({
  598. type: "error",
  599. showClose: true,
  600. message: res.message,
  601. center: true,
  602. });
  603. }
  604. });
  605. };
  606. // 完整的MP4链接判断函数
  607. const isMp4Link = (url) => {
  608. if (!url || typeof url !== "string") return false;
  609. // 步骤1:去掉URL中的参数和哈希(? 或 # 之后的内容)
  610. const pureUrl = url.split(/[?#]/)[0]; // 按 ? 或 # 拆分,取第一部分
  611. // 步骤2:转为小写 + 判断是否以 .mp4 结尾
  612. return pureUrl.toLowerCase().endsWith(".mp4");
  613. };
  614. const handleDelete = (index) => {
  615. ruleForm.imageLists.splice(index, 1);
  616. };
  617. const handlePreview = (images, index) => {
  618. // 核心:复制数组,把点击的图片移到第一位
  619. const newImages = [...images]; // 拷贝原数组,避免修改原数据
  620. const currentImg = newImages.splice(index, 1)[0]; // 取出当前点击的图片
  621. newImages.unshift(currentImg); // 放到数组开头
  622. // 传给预览器,此时插件显示的第一张就是点击的图片
  623. // viewerApi({
  624. // images: newImages,
  625. // zIndex: 3000,
  626. // });
  627. };
  628. // 可选:限制上传文件大小(单位:MB)
  629. const MAX_SIZE = 50; // 图片/视频最大50MB
  630. // 上传前的校验
  631. const beforeUpload = (file) => {
  632. // 定义允许的文件类型(MIME类型 + 后缀名双重校验)
  633. // const allowTypes = [
  634. // // 图片类型
  635. // 'image/jpeg', 'image/png', 'image/gif', 'image/jpg',
  636. // // 视频类型
  637. // 'video/mp4', 'video/avi', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv'
  638. // ]
  639. // const allowExts = ['jpg', 'jpeg', 'png', 'gif', 'mp4', 'avi', 'mov', 'wmv', 'flv']
  640. const allowTypes = [
  641. // 图片类型
  642. "image/jpeg",
  643. "image/png",
  644. "image/gif",
  645. "image/jpg",
  646. // 视频类型
  647. "video/mp4",
  648. ];
  649. const allowExts = ["jpg", "jpeg", "png", "gif", "mp4"];
  650. // 获取文件后缀名(小写)
  651. const fileExt = file.name.split(".").pop().toLowerCase();
  652. // 获取文件MIME类型
  653. const fileType = file.type;
  654. // 校验格式
  655. if (!allowTypes.includes(fileType) && !allowExts.includes(fileExt)) {
  656. ElMessage.error("仅支持上传 jpg/jpeg/png/gif 图片或 mp4 视频!");
  657. return false; // 阻止上传
  658. }
  659. // 校验大小(可选)
  660. // const fileSize = file.size / 1024 / 1024 // 转MB
  661. // if (fileSize > MAX_SIZE) {
  662. // ElMessage.error(`文件大小不能超过 ${MAX_SIZE}MB!`)
  663. // return false // 阻止上传
  664. // }
  665. return true; // 校验通过
  666. };
  667. // 文件选择变化时触发
  668. const handleFileChange = async (file, newFileList) => {
  669. console.log(file);
  670. let formData = new FormData();
  671. formData.append("file", file.raw);
  672. let res = await uploadFile(formData);
  673. console.log(res);
  674. if (res.code == 200) {
  675. ruleForm.imageLists.push(res.data.fileUrl); // 赋值给响应式fileList,页面自动刷新
  676. } else {
  677. ElMessage({
  678. type: "error",
  679. showClose: true,
  680. message: res.message,
  681. center: true,
  682. });
  683. }
  684. };
  685. const clubData = ref();
  686. const clubLoading = ref(false); // 加载状态
  687. const pageParams = reactive({
  688. pageNum: 1, // 当前页
  689. pageSize: 500, // 每页条数
  690. keyword: "", // 搜索关键词(可选)
  691. });
  692. // 获取组织下拉列表数据
  693. const clubList = async () => {
  694. let params = {
  695. currentPage: pageParams.pageNum,
  696. pageCount: pageParams.pageSize,
  697. keyword: pageParams.keyword,
  698. };
  699. let res = await queryCategoryDatas(params);
  700. console.log(res, "获取组织下拉列表数据");
  701. if (res.code == 200) {
  702. clubData.value = res.data.list;
  703. } else {
  704. ElMessage({
  705. type: "error",
  706. showClose: true,
  707. message: res.message,
  708. center: true,
  709. });
  710. }
  711. };
  712. const remoteMethod = (query) => {
  713. console.log(query);
  714. pageParams.keyword = query;
  715. clubLoading.value = true;
  716. clubList().then(() =>{
  717. clubLoading.value = false;
  718. })
  719. };
  720. // const categoryData = ref();
  721. // const categoryList = async () => {
  722. // let params = {
  723. // currentPage: 1,
  724. // pageCount: 1000,
  725. // }
  726. // let res = await queryCategoryDatas(params);
  727. // if (res.code == 200) {
  728. // categoryData.value = res.data.list;
  729. // } else {
  730. // ElMessage({
  731. // type: "error",
  732. // showClose: true,
  733. // message: res.message,
  734. // center: true,
  735. // });
  736. // }
  737. // };
  738. // 搜索功能
  739. const searchBtn = lodash.debounce(async () => {
  740. currentPage.value = 1;
  741. getList();
  742. }, 300);
  743. const resetBtn = lodash.debounce(async () => {
  744. searchInput.userName = "";
  745. searchInput.isPass = null;
  746. searchInput.createTime = null;
  747. currentPage.value = 1;
  748. getList();
  749. }, 300);
  750. // 添加账号
  751. const addlist = () => {
  752. dialongTitle.value = "发布动态";
  753. addDialogVisible.value = true;
  754. ruleForm.categoryId = "";
  755. ruleForm.content = "";
  756. ruleForm.id = "";
  757. ruleForm.imageLists = [];
  758. };
  759. const deleteS = async (row) => {
  760. ElMessageBox.confirm("是否删除此数据?", "提示!!!", {
  761. confirmButtonText: "确认",
  762. cancelButtonText: "取消",
  763. type: "warning",
  764. })
  765. .then(async () => {
  766. let params = {
  767. id: row.id,
  768. };
  769. let res = await deletePostsById(params);
  770. if (res.code == 200) {
  771. getList();
  772. ElMessage({
  773. type: "success",
  774. showClose: true,
  775. message: res.message,
  776. center: true,
  777. });
  778. } else {
  779. ElMessage({
  780. type: "error",
  781. showClose: true,
  782. message: res.message,
  783. center: true,
  784. });
  785. }
  786. })
  787. .catch(() => {
  788. loading.value = false;
  789. });
  790. };
  791. // 确认添加员工
  792. const submitAdd = lodash.debounce(async (formEl) => {
  793. if (!formEl) return;
  794. await formEl.validate(async (valid, fields) => {
  795. if (valid) {
  796. let data = {
  797. categoryId: ruleForm.categoryId,
  798. content: ruleForm.content,
  799. imageLists: ruleForm.imageLists,
  800. };
  801. let res = await insertPosts(data);
  802. if (res.code == 200) {
  803. addDialogVisible.value = false;
  804. ElMessage({
  805. type: "success",
  806. showClose: true,
  807. message: res.message,
  808. center: true,
  809. });
  810. getList();
  811. } else {
  812. ElMessage({
  813. type: "error",
  814. showClose: true,
  815. message: res.message,
  816. center: true,
  817. });
  818. }
  819. } else {
  820. console.log("error submit!", fields);
  821. }
  822. });
  823. }, 1000);
  824. const cancelAdd = () => {
  825. addDialogVisible.value = false;
  826. };
  827. // 查看详情
  828. const viewDetails = async (i) => {
  829. console.log(i, "查看详情");
  830. commentLoading.value = true;
  831. detailsVisible.value = true;
  832. detailData.value = i;
  833. let params = {
  834. postsId: i.id,
  835. commentId: 0,
  836. };
  837. let res = await queryCommetns(params);
  838. if (res.code == 200) {
  839. commentLoading.value = false;
  840. console.log(res, "评论");
  841. commentData.value = res.data;
  842. } else {
  843. ElMessage({
  844. type: "error",
  845. showClose: true,
  846. message: res.message,
  847. center: true,
  848. });
  849. }
  850. };
  851. // 查看更多回复
  852. const openComment = async (i, index) => {
  853. commentLoading.value = true;
  854. let params = {
  855. postsId: i.id,
  856. commentId: i.id,
  857. };
  858. let res = await queryCommetns(params);
  859. if (res.code == 200) {
  860. // console.log(res, "回复评论");
  861. commentLoading.value = false;
  862. commentData.value[index].children = res.data;
  863. console.log(commentData.value, "全部评论");
  864. } else {
  865. ElMessage({
  866. type: "error",
  867. showClose: true,
  868. message: res.message,
  869. center: true,
  870. });
  871. }
  872. };
  873. // 通过
  874. const operationPassChange = async (row) => {
  875. operationTitle.value = "通过审批";
  876. operationVisible.value = true;
  877. operationRuleForm.passValue = null;
  878. operationRuleForm.id = row.id;
  879. };
  880. // 拒绝
  881. const operationRefuseChange = async (row) => {
  882. operationTitle.value = "拒绝审批";
  883. operationVisible.value = true;
  884. operationRuleForm.passValue = null;
  885. operationRuleForm.id = row.id;
  886. };
  887. // 确认审批
  888. const operationSubmitAdd = lodash.debounce(async (formEl) => {
  889. if (!formEl) return;
  890. await formEl.validate(async (valid, fields) => {
  891. if (valid) {
  892. let data = {
  893. id: operationRuleForm.id,
  894. isPass: operationTitle.value == "通过审批" ? 2 : 3,
  895. passValue: operationRuleForm.passValue,
  896. };
  897. let res = await toExaminePosts(data);
  898. if (res.code == 200) {
  899. operationVisible.value = false;
  900. ElMessage({
  901. type: "success",
  902. showClose: true,
  903. message: res.message,
  904. center: true,
  905. });
  906. getList();
  907. } else {
  908. ElMessage({
  909. type: "error",
  910. showClose: true,
  911. message: res.message,
  912. center: true,
  913. });
  914. }
  915. } else {
  916. console.log("error submit!", fields);
  917. }
  918. });
  919. }, 1000);
  920. const cancelOperation = () => {
  921. operationVisible.value = false;
  922. };
  923. // 每页显示条数
  924. const handleSizeChange = (value) => {
  925. console.log(value, "每页显示条数");
  926. pageSize.value = value;
  927. getList()
  928. };
  929. // 分页
  930. const handleCurrentChange = (value) => {
  931. // console.log(value);
  932. currentPage.value = value;
  933. getList()
  934. };
  935. onBeforeMount(() => {
  936. getList();
  937. clubList();
  938. // collegeList();
  939. });
  940. onUnmounted(() => {
  941. // document.removeEventListener("keyup", Enters);
  942. });
  943. </script>
  944. <style scoped lang="scss">
  945. .content-box {
  946. width: calc(100% - 40px);
  947. height: calc(100% - 105px);
  948. margin: 20px auto;
  949. background-color: #fff;
  950. color: #000;
  951. display: flex;
  952. flex-direction: column;
  953. .svg {
  954. width: 22px;
  955. height: 22px;
  956. }
  957. .left {
  958. width: calc(100% - 60px);
  959. height: 60px;
  960. margin: 0 auto;
  961. display: flex;
  962. align-items: center;
  963. border-bottom: 1px solid #ccc;
  964. color: #000;
  965. font-size: 18px;
  966. font-weight: 600;
  967. .camera {
  968. margin-right: 15px;
  969. color: #4392f7;
  970. }
  971. }
  972. .scroll {
  973. width: calc(100% - 60px);
  974. height: calc(100% - 61px);
  975. margin: 0 auto;
  976. display: flex;
  977. flex-direction: column;
  978. .middle {
  979. width: calc(100%);
  980. color: #000;
  981. .filter {
  982. display: flex;
  983. flex-wrap: wrap;
  984. align-items: center;
  985. .search {
  986. margin-left: 0 !important;
  987. color: #fff;
  988. }
  989. .condition {
  990. display: flex;
  991. align-items: center;
  992. margin: 10px 30px 10px 0;
  993. :deep(.el-input .el-input__inner) {
  994. font-size: 14px;
  995. }
  996. .el-select {
  997. width: 220px;
  998. }
  999. span {
  1000. margin: 0 10px 0 0;
  1001. }
  1002. }
  1003. }
  1004. .gongneng {
  1005. margin: 10px 0;
  1006. .el-button {
  1007. color: #fff;
  1008. margin-right: 15px;
  1009. }
  1010. }
  1011. }
  1012. .footer {
  1013. width: calc(100%);
  1014. flex: 1;
  1015. margin: 0 auto;
  1016. overflow: auto;
  1017. .card_all {
  1018. height: calc(100% - 60px);
  1019. overflow: auto;
  1020. // display: flex;
  1021. .el-card {
  1022. width: 360px !important;
  1023. // height: 184px;
  1024. }
  1025. :deep(.el-card__header) {
  1026. padding: 15px 20px 0;
  1027. border: 0;
  1028. .card-header {
  1029. display: flex;
  1030. // justify-content: space-between;
  1031. align-items: center;
  1032. font-weight: 800;
  1033. img {
  1034. width: 50px;
  1035. height: 50px;
  1036. margin-right: 20px;
  1037. border-radius: 50%;
  1038. }
  1039. .issuer {
  1040. p {
  1041. font-size: 18px;
  1042. margin: 5px 0;
  1043. }
  1044. span {
  1045. font-size: 12px;
  1046. color: #999;
  1047. }
  1048. }
  1049. }
  1050. }
  1051. :deep(.el-card__body) {
  1052. padding: 0 20px 10px;
  1053. font-size: 13px;
  1054. .content {
  1055. height: 50px;
  1056. overflow: hidden;
  1057. display: -webkit-box;
  1058. -webkit-line-clamp: 2;
  1059. -webkit-box-orient: vertical;
  1060. line-height: 1.6;
  1061. cursor: pointer;
  1062. font-size: 16px;
  1063. }
  1064. .dianzan {
  1065. margin: 0;
  1066. display: flex;
  1067. align-items: center;
  1068. justify-content: space-between;
  1069. .icon {
  1070. margin: 0 15px;
  1071. display: flex;
  1072. align-items: center;
  1073. justify-content: space-around;
  1074. img {
  1075. // cursor: pointer;
  1076. width: 18px;
  1077. height: 18px;
  1078. margin-right: 8px;
  1079. }
  1080. span {
  1081. font-size: 16px;
  1082. }
  1083. }
  1084. }
  1085. }
  1086. :deep(.el-card__footer) {
  1087. padding: 10px 20px;
  1088. .card-footer {
  1089. display: flex;
  1090. justify-content: space-between;
  1091. font-size: 14px;
  1092. .el-dropdown .el-icon:focus {
  1093. // outline: none !important;
  1094. // box-shadow: none !important;
  1095. outline: 2px solid rgba(38, 151, 255, 0.5) !important;
  1096. // outline-offset: 2px;
  1097. }
  1098. .footer_left {
  1099. display: flex;
  1100. align-items: center;
  1101. }
  1102. }
  1103. }
  1104. }
  1105. /* WebKit 内核浏览器(Chrome、Edge、Safari)的滚动条样式 */
  1106. .card_all::-webkit-scrollbar {
  1107. /* 滚动条宽度 */
  1108. width: 6px;
  1109. height: 6px;
  1110. }
  1111. /* 滚动条轨道 */
  1112. .card_all::-webkit-scrollbar-track {
  1113. background: #f5f7fa;
  1114. border-radius: 3px;
  1115. }
  1116. /* 滚动条滑块 */
  1117. .card_all::-webkit-scrollbar-thumb {
  1118. background: #c0c4cc;
  1119. border-radius: 3px;
  1120. /* 鼠标悬停时滑块变色 */
  1121. transition: background 0.3s;
  1122. }
  1123. .card_all::-webkit-scrollbar-thumb:hover {
  1124. background: #909399;
  1125. }
  1126. .pageSize {
  1127. display: flex;
  1128. align-items: center;
  1129. justify-content: space-between;
  1130. margin: 0 30px;
  1131. height: 60px;
  1132. span {
  1133. color: #000;
  1134. }
  1135. .el-pagination {
  1136. // width: 1600px;
  1137. :deep(.el-pagination__total) {
  1138. color: #000;
  1139. }
  1140. :deep(.el-pagination__goto) {
  1141. color: #000;
  1142. }
  1143. :deep(.el-pagination__classifier) {
  1144. color: #000;
  1145. }
  1146. :deep(.el-input__wrapper) {
  1147. border: 1px solid rgba(0, 0, 0, 1);
  1148. border-radius: 5px;
  1149. box-shadow: none;
  1150. }
  1151. :deep(.el-pager li) {
  1152. margin: 0 5px;
  1153. border: 1px solid rgba(0, 0, 0, 1);
  1154. border-radius: 5px;
  1155. background-color: transparent;
  1156. }
  1157. :deep(.el-pager li.is-active) {
  1158. // background-color: rgba(0, 97, 255, 0.8);
  1159. border: 1px solid rgba(0, 97, 255, 1);
  1160. color: rgba(0, 97, 255, 1);
  1161. }
  1162. :deep(.btn-prev) {
  1163. margin-right: 5px;
  1164. border: 1px solid rgba(0, 0, 0, 1);
  1165. border-radius: 5px;
  1166. background-color: transparent;
  1167. }
  1168. :deep(.btn-next) {
  1169. margin-left: 5px;
  1170. border: 1px solid rgba(0, 0, 0, 1);
  1171. border-radius: 5px;
  1172. background-color: transparent;
  1173. }
  1174. }
  1175. }
  1176. }
  1177. }
  1178. // 添加员工弹窗样式
  1179. .addStaff {
  1180. .el-select {
  1181. width: 400px;
  1182. }
  1183. .el-textarea {
  1184. width: 400px;
  1185. }
  1186. .options {
  1187. // border: 1px solid red;
  1188. margin-top: 40px;
  1189. }
  1190. }
  1191. // 添加员工弹窗样式
  1192. .details {
  1193. .card-header {
  1194. display: flex;
  1195. align-items: center;
  1196. img {
  1197. width: 80px;
  1198. height: 80px;
  1199. margin-right: 20px;
  1200. }
  1201. .issuer {
  1202. p {
  1203. font-size: 20px;
  1204. font-weight: 800;
  1205. margin: 0 0 10px;
  1206. }
  1207. }
  1208. }
  1209. .comment-count {
  1210. padding: 10px;
  1211. margin: 0;
  1212. font-weight: 800;
  1213. background-color: #f5f7fa;
  1214. border-bottom: 0.5px solid #e0e0e0;
  1215. }
  1216. .card-footer {
  1217. max-height: 450px;
  1218. overflow: auto;
  1219. background-color: #f5f7fa;
  1220. min-height: 100px;
  1221. margin-bottom: 20px;
  1222. .comment-count {
  1223. padding: 10px 10px 20px;
  1224. margin: 0;
  1225. font-weight: 800;
  1226. }
  1227. .user {
  1228. display: flex;
  1229. // align-items: center;
  1230. img {
  1231. width: 40px;
  1232. height: 40px;
  1233. margin: 10px 15px;
  1234. }
  1235. .user-info {
  1236. flex: 1;
  1237. // margin-bottom: 10px;
  1238. .upvote {
  1239. display: flex;
  1240. justify-content: space-between;
  1241. align-items: center;
  1242. margin: 8px 0 0;
  1243. .username {
  1244. font-weight: 800;
  1245. // color: #2A82E4;
  1246. // color: #aaabad;
  1247. }
  1248. img {
  1249. width: 19px;
  1250. height: 19px;
  1251. margin: 0 10px;
  1252. }
  1253. .num {
  1254. display: flex;
  1255. align-items: center;
  1256. margin-right: 20px;
  1257. }
  1258. }
  1259. .comment {
  1260. display: flex;
  1261. flex-direction: column;
  1262. }
  1263. }
  1264. }
  1265. }
  1266. /* WebKit 内核浏览器(Chrome、Edge、Safari)的滚动条样式 */
  1267. .card-footer::-webkit-scrollbar {
  1268. /* 滚动条宽度 */
  1269. width: 6px;
  1270. height: 6px;
  1271. }
  1272. /* 滚动条轨道 */
  1273. .card-footer::-webkit-scrollbar-track {
  1274. background: #f5f7fa;
  1275. border-radius: 3px;
  1276. }
  1277. /* 滚动条滑块 */
  1278. .card-footer::-webkit-scrollbar-thumb {
  1279. background: #c0c4cc;
  1280. border-radius: 3px;
  1281. /* 鼠标悬停时滑块变色 */
  1282. transition: background 0.3s;
  1283. }
  1284. .card-footer::-webkit-scrollbar-thumb:hover {
  1285. background: #909399;
  1286. }
  1287. .el-textarea {
  1288. width: 400px;
  1289. }
  1290. }
  1291. }
  1292. </style>