Bladeren bron

完成校友信息管理接口 广场信息管理发布动态接口调整

hzj18279462576@163.com 4 maanden geleden
bovenliggende
commit
64d47b7600

+ 2 - 2
src/App.vue

@@ -219,8 +219,7 @@ onBeforeMount(async () => {
 
 .viewer-container,      /* v-viewer 根容器 */
 .el-image-viewer__wrapper, /* Element 预览层 */
-.photo-preview-modal    /* vue-photo-preview 根容器 */
-{
+.photo-preview-modal    /* vue-photo-preview 根容器 */ {
   z-index: 9999 !important; /* 远高于所有弹窗/表格 */
   position: fixed !important; /* 脱离文档流,不继承父层级 */
   top: 0 !important;
@@ -228,6 +227,7 @@ onBeforeMount(async () => {
   right: 0 !important;
   bottom: 0 !important;
 }
+
 </style>
 <style scoped lang="scss">
 .body-box {

+ 118 - 0
src/api/alumni-info.js

@@ -0,0 +1,118 @@
+// 校友信息管理
+// 引入axios请求实例(已封装好baseURL、请求拦截器携带token)
+import request from '@/utils/request'
+
+// 7.7.	校友分页列表数据
+export function queryUsersPage(params) {
+  return request({
+    url: `/api/alumniUser/queryUsersPage`,
+    method: 'get',
+    params
+  })
+}
+
+// 7.8.	创建校友信息
+export function insertUserData(data) {
+  return request({
+    url: `/api/alumniUser/insertUserData`,
+    method: 'post',
+    data
+  })
+}
+
+// 7.9.	编辑校友信息
+export function updateUserData(data) {
+  return request({
+    url: '/api/alumniUser/updateUserData',
+    method: 'post',
+    data
+  })
+}
+
+// 13.4.	删除新闻分类数据
+export function deleteUserDataById(params) {
+  return request({
+    url: '/api/alumniUser/deleteUserDataById',
+    method: 'get',
+    params
+  })
+}
+
+// 7.11.	校友信息导入模板下载
+export function downloadUserExcel() {
+  return request({
+    url: '/api/alumniUser/downloadUserExcel',
+    method: 'get',
+  })
+}
+
+// 7.12.	导入校友信息数据
+export function importUserExcel(data) {
+  return request({
+    url: '/api/alumniUser/importUserExcel',
+    method: 'post',
+    data // 传修改后的菜单对象,必须带id
+  })
+}
+
+// 7.13.	导出校友信息数据
+export function alumniUserExport(data) {
+  return request({
+    url: `/api/alumniUser/alumniUserExport`,
+    method: 'post',
+    data,
+    responseType: 'blob',
+  })
+}
+
+// 7.1.	获取毕业年份下拉列表数据
+export function queryGraduate() {
+  return request({
+    url: '/api/alumniUser/queryGraduate',
+    method: 'get',
+  })
+}
+
+// 7.2.	获取学院下拉列表数据
+export function queryColleges() {
+  return request({
+    url: '/api/alumniOrg/queryColleges',
+    method: 'get',
+  })
+}
+
+// 7.3.	根据学院ID获取入学年下拉列表数据
+export function queryPeriods(params) {
+  return request({
+    url: '/api/alumniOrg/queryPeriods',
+    method: 'get',
+    params
+  })
+}
+
+// 7.4.	根据入学年ID获取专业下拉列表数据
+export function queryMajors(params) {
+  return request({
+    url: '/api/alumniOrg/queryMajors',
+    method: 'get',
+    params
+  })
+}
+
+// 7.5.	根据专业ID获取班级下拉列表数据
+export function queryClasses(params) {
+  return request({
+    url: '/api/alumniOrg/queryClasses',
+    method: 'get',
+    params
+  })
+}
+
+// 7.6.	获取身份认证下拉列表数据
+export function queryIdentitys(params) {
+  return request({
+    url: '/api/alumniOrg/queryIdentitys',
+    method: 'get',
+    params
+  })
+}

+ 83 - 0
src/api/alumni-new.js

@@ -0,0 +1,83 @@
+// 新闻聚焦管理
+// 引入axios请求实例(已封装好baseURL、请求拦截器携带token)
+import request from '@/utils/request'
+
+// 13.1.	获取新闻分类分页数据
+export function queryCategoryNewsPage(params) {
+  return request({
+    url: `/api/alumniCategoryNews/queryCategoryNewsPage`,
+    method: 'get',
+    params
+  })
+}
+
+// 13.2.	新增新闻分类数据
+export function insertCategoryNews(data) {
+  return request({
+    url: `/api/alumniCategoryNews/insertCategoryNews`,
+    method: 'post',
+    data
+  })
+}
+
+// 13.3.	更新新闻分类数据
+export function updateCategoryNews(data) {
+  return request({
+    url: '/api/alumniCategoryNews/updateCategoryNews',
+    method: 'post',
+    data
+  })
+}
+
+// 13.4.	删除新闻分类数据
+export function deleteCategoryNews(params) {
+  return request({
+    url: '/api/alumniCategoryNews/deleteCategoryNews',
+    method: 'get',
+    params
+  })
+}
+
+// 13.5.	获取新闻分类下拉列表数据
+export function queryCategoryNewss() {
+  return request({
+    url: '/api/alumniCategoryNews/queryCategoryNewss ',
+    method: 'get',
+  })
+}
+
+// 13.6.	获取新闻分页数据
+export function queryAlumniNewsPage(params) {
+  return request({
+    url: '/api/alumniNews/queryAlumniNewsPage',
+    method: 'get',
+    params // 传修改后的菜单对象,必须带id
+  })
+}
+
+// 13.7.	发布新闻数据
+export function insertAlumniNews(data) {
+  return request({
+    url: `/api/alumniNews/insertAlumniNews`,
+    method: 'post',
+    data
+  })
+}
+
+// 13.8.	更新新闻数据
+export function updateAlumniNews(data) {
+  return request({
+    url: '/api/alumniNews/updateAlumniNews',
+    method: 'post',
+    data
+  })
+}
+
+// 13.4.	删除新闻分类数据
+export function deleteAlumniNews(params) {
+  return request({
+    url: '/api/alumniNews/deleteAlumniNews',
+    method: 'get',
+    params
+  })
+}

+ 7 - 7
src/components/richtext.vue

@@ -30,7 +30,7 @@ import { ElMessage, ElMessageBox } from "element-plus";
 import { Calendar } from "@element-plus/icons-vue";
 import { dayjs } from "element-plus";
 import lodash, { reduce } from "lodash";
-import { https } from "@/utils/request"; // 绝对路径
+import { uploadFile } from "@/api/uploadFile";
 
 import "@wangeditor/editor/dist/css/style.css"; // 引入 css
 
@@ -68,10 +68,10 @@ const uploadImg = async (file, insertFn) => {
   let srcImg = file;
   let data = new FormData();
   data.set("file", srcImg);
-  let res = await https.post("/files/upload", "data", data);
+  let res = await uploadFile(data);
   console.log(res, "导入照片");
   if (res.code == 200) {
-    let href = res.data;
+    let href = res.data.fileUrl;
     insertFn(href);
     ElMessage({
       type: "success",
@@ -224,15 +224,15 @@ onBeforeUnmount(() => {
 <style scoped lang="scss">
 .richText {
   width: 100%;
-  min-height: 300px;
+  min-height: 500px;
   .box {
-    height: 100%;
-    .boxToolbar{
+    height: 500px;
+    .boxToolbar {
       border-top: 1px solid #ccc;
       border-left: 1px solid #ccc;
       border-right: 1px solid #ccc;
     }
-    .boxEditor{
+    .boxEditor {
       height: calc(100% - 80px) !important;
       border: 1px solid #ccc;
     }

+ 2 - 0
src/views/alumni-album/PhotoList.vue

@@ -514,11 +514,13 @@ const tableRowClassName = ({ row, rowIndex }) => {
 const handleSizeChange = (value) => {
   console.log(value, "每页显示条数");
   pageSize.value = value;
+  getList();
 };
 // 分页
 const handleCurrentChange = (value) => {
   // console.log(value);
   currentPage.value = value;
+  getList();
 };
 
 const categoryList = async () => {

File diff suppressed because it is too large
+ 683 - 186
src/views/alumni-info/alumni-info.vue


+ 95 - 39
src/views/alumni-new/NewsClassification.vue

@@ -67,20 +67,24 @@
     <div class="footer" v-loading="loading">
       <div class="card_all">
         <el-space wrap>
-          <el-card style="max-width: 480px" v-for="o in 16" :key="o">
+          <el-card
+            style="max-width: 480px"
+            v-for="i in tableData.list"
+            :key="i.id"
+          >
             <template #header>
               <div class="card-header">
-                <span>学校要闻</span>
+                <span>{{ i.name }}</span>
                 <span><span class="number">1 </span>篇新闻</span>
               </div>
             </template>
-            <p>创建时间: 2026-01-06 14:26:00</p>
-            <p>创建人: 张三</p>
+            <p>创建时间: {{ i.createTime }}</p>
+            <p>创建人: {{ i.createUser }}</p>
             <template #footer>
               <div class="card-footer">
-                <el-button type="primary" link>编辑</el-button>
+                <el-button type="primary" @click="updateS(i)" link>编辑</el-button>
                 <span class="line">|</span>
-                <el-button type="danger" link>删除</el-button>
+                <el-button type="danger" @click="deleteS(i)" link>删除</el-button>
               </div>
             </template>
           </el-card>
@@ -125,10 +129,10 @@
       label-position="right"
       status-icon
     >
-      <el-form-item label="分类名称 :" prop="dormitory">
+      <el-form-item label="分类名称 :" prop="name">
         <el-input
           clearable
-          v-model.trim="ruleForm.dormitory"
+          v-model.trim="ruleForm.name"
           class="w-50 m-2"
           placeholder="请输入分类名称"
         />
@@ -165,6 +169,18 @@ import lodash from "lodash";
 import { storeToRefs } from "pinia";
 import { useCounterStore } from "@/stores/index";
 
+import {
+  queryCategoryNewsPage,
+  insertCategoryNews,
+  updateCategoryNews,
+  deleteCategoryNews,
+  queryCategoryNewss,
+  queryAlumniNewsPage,
+  insertAlumniNews,
+  updateAlumniNews,
+  deleteAlumniNews,
+} from "@/api/alumni-new.js";
+
 const router = useRouter();
 const store = useCounterStore();
 
@@ -198,26 +214,12 @@ const addDialogVisible = ref(false); // 控制添加账号弹窗
 const formSize = ref("default");
 const ruleFormRef = ref();
 const ruleForm = reactive({
-  school: "靖安校区", //校区名称
-  build: "", //楼栋名称
-  dormitory: "", //寝室号
-  sex: "男", //寝室性别
-  college: "", //所属学院
-  major: "", //所属专业
-  bedNumber: "", //床位数
-  // "gradestr": "",              //所属年级
-  remark: "", //备注
+  name: "",
   id: "",
 });
 // 表单验证
 const rules = reactive({
-  school: [{ required: true, message: "校区名称不能为空", trigger: "blur" }],
-  build: [{ required: true, message: "楼栋名称不能为空", trigger: "blur" }],
-  dormitory: [{ required: true, message: "寝室号不能为空", trigger: "blur" }],
-  sex: [{ required: true, message: "寝室性别不能为空", trigger: "blur" }],
-  college: [{ required: true, message: "所属学院不能为空", trigger: "blur" }],
-  major: [{ required: true, message: "专业不能为空", trigger: "blur" }],
-  bedNumber: [{ required: true, message: "床位数不能为空", trigger: "blur" }],
+  name: [{ required: true, message: "分类名称不能为空", trigger: "blur" }],
 });
 
 // 获取账户列表
@@ -226,9 +228,24 @@ const getList = async () => {
   let params = {
     currentPage: currentPage.value, // 当前页
     pageCount: pageSize.value, // 一页数据条数
-    schoolId: searchInput.schoolId,
-    buildId: searchInput.buildId,
+    userName: searchInput.userName,
+    clubId: searchInput.clubId,
+    isPass: searchInput.isPass,
   };
+  if (searchInput.createTime) {
+    params.startTime = searchInput.createTime[0];
+    params.endTime = searchInput.createTime[1];
+  }
+  queryCategoryNewsPage(params).then((res) => {
+    console.log(res, "获取新闻分类分页数据");
+    if (res.code == 200) {
+      tableData.list = res.data.list;
+      total.value = res.data.totalCount;
+      loading.value = false;
+    } else {
+      loading.value = false;
+    }
+  });
 };
 
 // 搜索功能
@@ -239,13 +256,15 @@ const resetBtn = lodash.debounce(async () => {}, 300);
 const addlist = () => {
   dialongTitle.value = "创建分类";
   addDialogVisible.value = true;
-  ruleForm.school = null;
+  ruleForm.name = null;
 };
 // 添加账号
 const updateS = (row) => {
   console.log(row);
   dialongTitle.value = "编辑分类";
   addDialogVisible.value = true;
+  ruleForm.name = row.name;
+  ruleForm.id = row.id;
 };
 const deleteS = async (row) => {
   ElMessageBox.confirm("是否删除此数据?", "提示!!!", {
@@ -254,29 +273,64 @@ const deleteS = async (row) => {
     type: "warning",
   })
     .then(async () => {
-      loading.value = true;
-      let data = {
-        dormitoryId: row.id, // 当前页
+      let params = {
+        id: row.id,
       };
+      let res = await deleteCategoryNews(params);
+      if (res.code == 200) {
+        getList();
+        ElMessage({
+          type: "success",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+      } else {
+        ElMessage({
+          type: "error",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+      }
     })
     .catch(() => {
       loading.value = false;
     });
 };
-// 保留
-const retainS = async (row, flag) => {
-  let data = {
-    dormitoryIds: [row.id], // 当前页
-    retentionState: flag, //保留状态 1:开放,2:保留
-  };
-};
 
 // 确认添加员工
 const submitAdd = lodash.debounce(async (formEl) => {
   if (!formEl) return;
   await formEl.validate(async (valid, fields) => {
     if (valid) {
-      console.log(data);
+      let data = {
+        name: ruleForm.name,
+      };
+      let res = "";
+      if (dialongTitle.value == "创建分类") {
+        res = await insertCategoryNews(data);
+      } else {
+        data.id = ruleForm.id;
+        res = await updateCategoryNews(data);
+      }
+      if (res.code == 200) {
+        addDialogVisible.value = false;
+        ElMessage({
+          type: "success",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+        getList();
+      } else {
+        ElMessage({
+          type: "error",
+          showClose: true,
+          message: res.message,
+          center: true,
+        });
+      }
     } else {
       console.log("error submit!", fields);
     }
@@ -322,7 +376,9 @@ const cancelProjectImport = () => {
   }
 };
 
-onBeforeMount(() => {});
+onBeforeMount(() => {
+  getList();
+});
 onUnmounted(() => {
   // document.removeEventListener("keyup", Enters);
 });

+ 118 - 28
src/views/alumni-new/NewsFocus.vue

@@ -10,7 +10,7 @@
             placeholder="请选择新闻分类"
           >
             <el-option
-              v-for="i in collegeData"
+              v-for="i in newTypeData"
               :key="i.id"
               :label="i.name"
               :value="i.id"
@@ -77,22 +77,27 @@
         }"
       >
         <!-- <el-table-column type="selection" align="center" width="55" /> -->
-        <el-table-column align="center" prop="school" label="新闻标题" />
+        <el-table-column align="center" prop="theme" label="新闻标题" />
         <el-table-column width="100" align="center" label="相册分类">
           <template #default="{ row }">
-            <span v-if="row.retentionState == 2">是</span>
-            <span v-if="row.retentionState == 1">否</span>
+            <span>{{ row.categoryName }}</span>
           </template>
         </el-table-column>
-        <el-table-column
-          show-overflow-tooltip
-          align="center"
-          prop="dormitory"
-          label="新闻内容"
-        />
-        <el-table-column align="center" prop="sex" label="发布人" />
+        <el-table-column align="center" prop="content" label="新闻内容">
+          <template #default="{ row }">
+            <!-- 容器1:用于渲染 HTML 内容(隐藏溢出,配合 tooltip) -->
+            <div
+              class="html-content"
+              style="color: #2697ff; cursor: pointer"
+              @click="handleTooltipShow(row.content)"
+            >
+              详情
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="userName" label="发布人" />
         <el-table-column align="center" prop="college" label="联系方式" />
-        <el-table-column align="center" prop="major" label="发布时间" />
+        <el-table-column align="center" prop="createTime" label="发布时间" />
         <el-table-column align="center" label="操作" fixed="right" width="200">
           <template #default="{ row }">
             <el-button type="primary" @click="updateS(row)" link
@@ -117,6 +122,19 @@
         />
       </div>
     </div>
+    <el-dialog
+      class="tooltips"
+      v-model="tooltipVisible"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      title="新闻内容"
+      align-center
+      width="1000"
+      destroy-on-close
+      draggable
+    >
+      <span v-html="tooltipContent"></span>
+    </el-dialog>
   </div>
   <!-- 添加账号弹窗 -->
   <el-dialog
@@ -126,9 +144,10 @@
     :close-on-press-escape="false"
     :title="dialongTitle"
     align-center
-    width="560"
+    width="890"
     :before-close="cancelAdd"
     destroy-on-close
+    
     draggable
   >
     <el-form
@@ -157,21 +176,25 @@
           placeholder="请选择新闻分类"
         >
           <el-option
-            v-for="i in schoolData"
+            v-for="i in newTypeData"
             :key="i.id"
-            :label="i.school"
-            :value="`${i.school},${i.id}`"
+            :label="i.name"
+            :value="`${i.name},${i.id}`"
           />
         </el-select>
       </el-form-item>
       <el-form-item label="新闻内容 :" prop="bedNumber">
-        <el-input
+        <!-- <el-input
           v-model.trim="ruleForm.bedNumber"
           placeholder="请输入新闻内容"
           clearable
           :autosize="{ minRows: 4 }"
           type="textarea"
-        />
+        /> -->
+        <Richtext
+          @richtextClick="richtextClick"
+          :fatherMessage="fatherMessage"
+        ></Richtext>
       </el-form-item>
       <el-form-item class="options">
         <el-button @click="cancelAdd">取消</el-button>
@@ -253,6 +276,16 @@ import lodash from "lodash";
 import { storeToRefs } from "pinia";
 import { useCounterStore } from "@/stores/index";
 
+import Richtext from "@/components/Richtext.vue";
+
+import {
+  queryCategoryNewss,
+  queryAlumniNewsPage,
+  insertAlumniNews,
+  updateAlumniNews,
+  deleteAlumniNews,
+} from "@/api/alumni-new.js";
+
 const router = useRouter();
 const store = useCounterStore();
 
@@ -279,6 +312,7 @@ const currentPage = ref(1); // 当前页
 const pageSize = ref(10);
 const total = ref(0); // 当前总数
 const selectIds = ref([]); // 勾选的全部数据
+const newTypeData = ref([]); //新闻分类下拉数据
 
 const addDialogVisible = ref(false); // 控制添加账号弹窗
 
@@ -308,15 +342,40 @@ const rules = reactive({
   bedNumber: [{ required: true, message: "床位数不能为空", trigger: "blur" }],
 });
 
+// Tooltip 相关响应式变量
+const tooltipVisible = ref(false);
+const tooltipContent = ref("");
+
+// 处理 Tooltip 显示(判断是否溢出 + 更新内容)
+const handleTooltipShow = (htmlContent) => {
+  tooltipVisible.value = true;
+  tooltipContent.value = htmlContent;
+};
+
 // 获取账户列表
 const getList = async () => {
   loading.value = true;
   let params = {
     currentPage: currentPage.value, // 当前页
     pageCount: pageSize.value, // 一页数据条数
-    schoolId: searchInput.schoolId,
-    buildId: searchInput.buildId,
+    userName: searchInput.userName,
+    clubId: searchInput.clubId,
+    isPass: searchInput.isPass,
   };
+  if (searchInput.createTime) {
+    params.startTime = searchInput.createTime[0];
+    params.endTime = searchInput.createTime[1];
+  }
+  queryAlumniNewsPage(params).then((res) => {
+    console.log(res, "获取新闻分页数据");
+    if (res.code == 200) {
+      tableData.list = res.data.list;
+      total.value = res.data.totalCount;
+      loading.value = false;
+    } else {
+      loading.value = false;
+    }
+  });
 };
 
 // 搜索功能
@@ -351,13 +410,6 @@ const deleteS = async (row) => {
       loading.value = false;
     });
 };
-// 保留
-const retainS = async (row, flag) => {
-  let data = {
-    dormitoryIds: [row.id], // 当前页
-    retentionState: flag, //保留状态 1:开放,2:保留
-  };
-};
 
 // 确认添加员工
 const submitAdd = lodash.debounce(async (formEl) => {
@@ -410,7 +462,37 @@ const cancelProjectImport = () => {
   }
 };
 
-onBeforeMount(() => {});
+const newTypeList = async () => {
+  let res = await queryCategoryNewss();
+  console.log(res, "新闻分类下拉列表数据");
+  if (res.code == 200) {
+    newTypeData.value = res.data;
+  } else {
+    ElMessage({
+      type: "error",
+      showClose: true,
+      message: res.message,
+      center: true,
+    });
+  }
+};
+
+const fatherMessage = ref({
+  data: "",
+  flag: false,
+});
+// 富文本传过来的数据
+const richtextClick = (data) => {
+  console.log(data, "富文本传过来的数据");
+  // params.value.safetyNotice = data.html;
+  // fatherMessage.value.data=data.html
+  // accountRuleForm.contentText = data.text;
+};
+
+onBeforeMount(() => {
+  getList();
+  newTypeList();
+});
 onUnmounted(() => {
   // document.removeEventListener("keyup", Enters);
 });
@@ -596,4 +678,12 @@ onUnmounted(() => {
     }
   }
 }
+
+:deep(.tooltips) {
+  .el-dialog__body {
+    height: 500px;
+    overflow: auto;
+    padding: 0px 20px 10px 20px;
+  }
+}
 </style>

+ 1 - 1
src/views/alumni-new/alumni-new.vue

@@ -30,7 +30,7 @@ const store = useCounterStore();
 // 为避免解构时失去响应性
 const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
 
-const activeName = ref("second");
+const activeName = ref("first");
 
 const handleClick = (tab, event) => {
   console.log(tab.props.name, event);

+ 204 - 15
src/views/alumni-square/alumni-square.vue

@@ -86,6 +86,29 @@
               <p @click="viewDetails(i)" class="content">
                 {{ i.content }}
               </p>
+              <div class="img-preview-list" style="height: 92px;">
+                <div
+                  class="img-item"
+                  v-for="(url, index) in i.imageLists"
+                  :key="index"
+                   style="height: 80px;margin-bottom: 10px;"
+                >
+                  <video
+                    v-if="isMp4Link(url)"
+                    class="preview-img"
+                    :src="url"
+                    controls
+                  ></video>
+                  <img
+                    v-else
+                    :src="url"
+                    alt="图片预览"
+                    class="preview-img"
+                    v-viewer
+                    @click="handlePreview(i.imageLists, index)"
+                  />
+                </div>
+              </div>
               <div class="dianzan">
                 <div class="icon">
                   <img src="../../assets/img/pinglun.png" alt="" />
@@ -218,6 +241,44 @@
             type="textarea"
           />
         </el-form-item>
+        <el-form-item label="照片 :" prop="imageLists">
+          <div class="img-preview-list">
+            <div
+              class="img-item"
+              v-for="(url, index) in ruleForm.imageLists"
+              :key="index"
+            >
+              <video
+                v-if="isMp4Link(url)"
+                class="preview-img"
+                :src="url"
+                controls
+              ></video>
+              <img
+                v-else
+                :src="url"
+                alt="图片预览"
+                class="preview-img"
+                v-viewer
+                @click="handlePreview(ruleForm.imageLists, index)"
+              />
+              <span class="delete-btn" @click="handleDelete(index)">
+                <el-icon><Delete /></el-icon>
+              </span>
+            </div>
+            <el-upload
+              action="#"
+              :auto-upload="false"
+              :on-change="handleFileChange"
+              :before-upload="beforeUpload"
+              class="upload-btn"
+              accept=".jpg,.jpeg,.png,.gif,.mp4,.avi,.mov,.wmv,.flv"
+            >
+              <el-icon><Plus /></el-icon>
+              <span class="upload-txt">点击图片或视频</span>
+            </el-upload>
+          </div>
+        </el-form-item>
         <el-form-item class="options">
           <el-button @click="cancelAdd">取消</el-button>
           <el-button
@@ -304,13 +365,35 @@
         <p style="text-indent: 2em; line-height: 1.8">
           {{ detailData.content }}
         </p>
-        <p class="comment-count">{{ detailData.commentNum }}条评论数</p>
-        <div class="card-footer" v-loading="commentLoading">
+        <div class="img-preview-list" style="margin-bottom: 15px;">
           <div
-            class="user"
-            v-for="(i, index) in commentData"
-            :key="i.id"
+            class="img-item"
+            v-for="(url, index) in detailData.imageLists"
+            :key="index"
           >
+            <video
+              v-if="isMp4Link(url)"
+              class="preview-img"
+              :src="url"
+              controls
+            ></video>
+            <img
+              v-else
+              :src="url"
+              alt="图片预览"
+              class="preview-img"
+              v-viewer
+              @click="handlePreview(detailData.imageLists, index)"
+            />
+            <span class="delete-btn" @click="handleDelete(index)">
+              <el-icon><Delete /></el-icon>
+            </span>
+          </div>
+        </div>
+
+        <p class="comment-count">{{ detailData.commentNum }}条评论数</p>
+        <div class="card-footer" v-loading="commentLoading">
+          <div class="user" v-for="(i, index) in commentData" :key="i.id">
             <img style="border-radius: 0" :src="i.image" alt="" />
             <div class="user-info">
               <div class="upvote">
@@ -346,7 +429,11 @@
                     v-for="j in i.children"
                     :key="j.id"
                   >
-                    <img style="border-radius: 0;margin: 10px 10px 0 0;" :src="j.image" alt="" />
+                    <img
+                      style="border-radius: 0; margin: 10px 10px 0 0"
+                      :src="j.image"
+                      alt=""
+                    />
                     <div class="user-info">
                       <div class="upvote">
                         <span class="username">{{ j.commentName }}</span>
@@ -402,7 +489,12 @@ import { useRouter } from "vue-router";
 import { genFileId, ElMessage, ElMessageBox } from "element-plus";
 import { dayjs } from "element-plus";
 import lodash from "lodash";
-import { MoreFilled, ArrowRightBold } from "@element-plus/icons-vue";
+import {
+  MoreFilled,
+  ArrowRightBold,
+  Delete,
+  Plus,
+} from "@element-plus/icons-vue";
 import { storeToRefs } from "pinia";
 import { useCounterStore } from "@/stores/index";
 import {
@@ -413,6 +505,8 @@ import {
   queryPostsPage,
   queryCommetns,
 } from "@/api/alumni-square";
+import { uploadFile } from "@/api/uploadFile";
+import { api as viewerApi } from "v-viewer";
 
 const router = useRouter();
 const store = useCounterStore();
@@ -447,6 +541,7 @@ const ruleFormRef = ref();
 const ruleForm = reactive({
   categoryId: "",
   content: "",
+  imageLists: [],
   id: "",
 });
 // 表单验证
@@ -455,6 +550,7 @@ const rules = reactive({
     { required: true, message: "组织分类不能为空", trigger: "blur" },
   ],
   content: [{ required: true, message: "内容不能为空", trigger: "blur" }],
+  // imageLists: [{ required: true, message: "图片或视频不能为空", trigger: "blur" }],
 });
 
 const detailsVisible = ref(false); // 详情弹窗
@@ -499,6 +595,97 @@ const getList = async () => {
   });
 };
 
+// 完整的MP4链接判断函数
+const isMp4Link = (url) => {
+  if (!url || typeof url !== "string") return false;
+
+  // 步骤1:去掉URL中的参数和哈希(? 或 # 之后的内容)
+  const pureUrl = url.split(/[?#]/)[0]; // 按 ? 或 # 拆分,取第一部分
+
+  // 步骤2:转为小写 + 判断是否以 .mp4 结尾
+  return pureUrl.toLowerCase().endsWith(".mp4");
+};
+const handleDelete = (index) => {
+  ruleForm.imageLists.splice(index, 1);
+};
+
+const handlePreview = (images, index) => {
+  // 核心:复制数组,把点击的图片移到第一位
+  const newImages = [...images]; // 拷贝原数组,避免修改原数据
+  const currentImg = newImages.splice(index, 1)[0]; // 取出当前点击的图片
+  newImages.unshift(currentImg); // 放到数组开头
+
+  // 传给预览器,此时插件显示的第一张就是点击的图片
+  // viewerApi({
+  //   images: newImages,
+  //   zIndex: 3000,
+  // });
+};
+
+// 可选:限制上传文件大小(单位:MB)
+const MAX_SIZE = 50; // 图片/视频最大50MB
+// 上传前的校验
+const beforeUpload = (file) => {
+  // 定义允许的文件类型(MIME类型 + 后缀名双重校验)
+  // const allowTypes = [
+  //   // 图片类型
+  //   'image/jpeg', 'image/png', 'image/gif', 'image/jpg',
+  //   // 视频类型
+  //   'video/mp4', 'video/avi', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv'
+  // ]
+  // const allowExts = ['jpg', 'jpeg', 'png', 'gif', 'mp4', 'avi', 'mov', 'wmv', 'flv']
+
+  const allowTypes = [
+    // 图片类型
+    "image/jpeg",
+    "image/png",
+    "image/gif",
+    "image/jpg",
+    // 视频类型
+    "video/mp4",
+  ];
+  const allowExts = ["jpg", "jpeg", "png", "gif", "mp4"];
+
+  // 获取文件后缀名(小写)
+  const fileExt = file.name.split(".").pop().toLowerCase();
+  // 获取文件MIME类型
+  const fileType = file.type;
+
+  // 校验格式
+  if (!allowTypes.includes(fileType) && !allowExts.includes(fileExt)) {
+    ElMessage.error("仅支持上传 jpg/jpeg/png/gif 图片或 mp4 视频!");
+    return false; // 阻止上传
+  }
+
+  // 校验大小(可选)
+  // const fileSize = file.size / 1024 / 1024 // 转MB
+  // if (fileSize > MAX_SIZE) {
+  //   ElMessage.error(`文件大小不能超过 ${MAX_SIZE}MB!`)
+  //   return false // 阻止上传
+  // }
+
+  return true; // 校验通过
+};
+
+// 文件选择变化时触发
+const handleFileChange = async (file, newFileList) => {
+  console.log(file);
+  let formData = new FormData();
+  formData.append("file", file.raw);
+  let res = await uploadFile(formData);
+  console.log(res);
+  if (res.code == 200) {
+    ruleForm.imageLists.push(res.data.fileUrl); // 赋值给响应式fileList,页面自动刷新
+  } else {
+    ElMessage({
+      type: "error",
+      showClose: true,
+      message: res.message,
+      center: true,
+    });
+  }
+};
+
 const categoryData = ref();
 const categoryList = async () => {
   let res = await queryCategoryDatas();
@@ -534,6 +721,7 @@ const addlist = () => {
   ruleForm.categoryId = "";
   ruleForm.content = "";
   ruleForm.id = "";
+  ruleForm.imageLists = [];
 };
 
 const deleteS = async (row) => {
@@ -577,6 +765,7 @@ const submitAdd = lodash.debounce(async (formEl) => {
       let data = {
         categoryId: ruleForm.categoryId,
         content: ruleForm.content,
+        imageLists: ruleForm.imageLists,
       };
       let res = await insertPosts(data);
       if (res.code == 200) {
@@ -843,10 +1032,10 @@ onUnmounted(() => {
           padding: 0 20px 10px;
           font-size: 13px;
           .content {
-            height: 78px;
+            height: 50px;
             overflow: hidden;
             display: -webkit-box;
-            -webkit-line-clamp: 3;
+            -webkit-line-clamp: 2;
             -webkit-box-orient: vertical;
             line-height: 1.6;
             cursor: pointer;
@@ -1013,12 +1202,12 @@ onUnmounted(() => {
       }
     }
     .comment-count {
-        padding: 10px ;
-        margin: 0;
-        font-weight: 800;
-        background-color: #f5f7fa;
-        border-bottom: 0.5px solid #e0e0e0;
-      }
+      padding: 10px;
+      margin: 0;
+      font-weight: 800;
+      background-color: #f5f7fa;
+      border-bottom: 0.5px solid #e0e0e0;
+    }
     .card-footer {
       max-height: 450px;
       overflow: auto;

+ 2 - 0
src/views/operation-log/operation-log.vue

@@ -230,11 +230,13 @@ const tableRowClassName = ({ row, rowIndex }) => {
 const handleSizeChange = (value) => {
   console.log(value, "每页显示条数");
   pageSize.value = value;
+  getList();
 };
 // 分页
 const handleCurrentChange = (value) => {
   // console.log(value);
   currentPage.value = value;
+  getList();
 };
 const allLogLevel = async () => {
   let res = await getQueryLogLevel();

+ 2 - 0
src/views/permission/Account.vue

@@ -490,11 +490,13 @@ const tableRowClassName = ({ row, rowIndex }) => {
 const handleSizeChange = (value) => {
   console.log(value, "每页显示条数");
   pageSize.value = value;
+  getList();
 };
 // 分页
 const handleCurrentChange = (value) => {
   // console.log(value);
   currentPage.value = value;
+  getList();
 };
 
 onBeforeMount(() => {