1
0

2 Ревизии d807958af9 ... b4f2357e6a

Автор SHA1 Съобщение Дата
  yanglingling b4f2357e6a Merge remote-tracking branch 'origin/master' into feature/master преди 1 година
  yanglingling 0fb1c42cf5 feature(遵义人民):资料下载\规章制度\新闻动态页面开发 преди 1 година

+ 4 - 3
public/config.js

@@ -7,12 +7,13 @@
  * @FilePath: \labsop_website\public\config.js
  */
 const $GlobalConfig = {
-  VUE_APP_TENANT: 'biobankV4dev',
+  // VUE_APP_TENANT: 'biobankV4dev',
   VUE_APP_MicroSrvProxy_API: 'http://192.168.0.219:9983/',
   // 登录验证微服务名称
   VUE_APP_AdminPath: 'dashoo.labsop.admin',
   VUE_APP_SETTING_PATH: 'dashoo.labsop.finance-zzh',
   VUE_APP_INSTR_PATH: 'dashoo.labsop.apparatus',
+  VUE_APP_SCIENTIFIC_PATH: 'dashoo.labsop.scientific-yll',
   // 租户码
-  VUE_APP_TENANT: 'default '
-}
+  VUE_APP_TENANT: 'default'
+}

+ 24 - 0
src/api/document.js

@@ -0,0 +1,24 @@
+import request from "@/utils/micro_request";
+
+const basePath = $GlobalConfig.VUE_APP_SCIENTIFIC_PATH;
+
+// 获取资料分类列表
+export function getDocClassList(data) {
+    return request.postRequestWithClientInfo(basePath, "SciAuthExclude", "GetAllParentClassList", data);
+}
+// 获取资料列表
+export function getDocListByClassId(data) {
+    return request.postRequestWithClientInfo(basePath, "SciAuthExclude", "GetEntityByParentId", data);
+}
+// 获取资料列表
+export function getEntityByClassName(data) {
+    return request.postRequestWithClientInfo(basePath, "SciAuthExclude", "GetEntityByClassName", data);
+}
+// 更新点击量
+export function updateClickCountById(data) {
+    return request.postRequestWithClientInfo(basePath, "SciAuthExclude", "UpdateClickCountById", data);
+}
+// 更新下载量
+export function updateDownloadCountById(data) {
+    return request.postRequestWithClientInfo(basePath, "SciAuthExclude", "UpdateDownloadCountById", data);
+}

+ 2 - 1
src/api/introduce.js

@@ -57,4 +57,5 @@ export function updateCenterPlatform(data) {
 // 更新平台简介点击量
 export function viewCenterPlatform(data) {
   return request.postRequest(basePath, "WesCenterPlatform", "ViewCenterPlatform", data);
-}
+}
+

+ 29 - 0
src/api/news.js

@@ -0,0 +1,29 @@
+import request from "@/utils/micro_request";
+
+const basePath = $GlobalConfig.VUE_APP_SETTING_PATH;
+const adminPath = $GlobalConfig.VUE_APP_AdminPath;
+
+// 获取新闻动态列表
+export function getNewsInformationList(data) {
+    return request.postRequestWithClientInfo(basePath, "WesNewsInformation", "GetNewsInformationList", data);
+}
+// 获取详情
+export function getNewsInformation(data) {
+    return request.postRequestWithClientInfo(basePath, "WesNewsInformation", "GetNewsInformation", data);
+}
+// 更新点击量
+export function viewNewsInformation(data) {
+    return request.postRequestWithClientInfo(basePath, "WesNewsInformation", "ViewNewsInformation", data);
+}
+// 新增+修改
+export function updateNewsInformation(data) {
+    return request.postRequestWithClientInfo(basePath, "WesNewsInformation", "UpdateNewsInformation", data);
+}
+// 获取通知公告列表
+export function getNoticeList(data) {
+    return request.postRequestWithClientInfo(adminPath, "Notice", "GetList", data);
+}
+// 获取通知公告详情
+export function getNoticeEntity(data) {
+    return request.postRequestWithClientInfo(adminPath, "Notice", "GetEntityById", data);
+}

BIN
src/assets/img/isTop.png


+ 81 - 9
src/components/RightContent.vue

@@ -17,26 +17,50 @@
                             :to="item.path ? { path: item.path } : null">{{ item.name }} </el-breadcrumb-item>
       </el-breadcrumb>
     </div>
-    <div v-if="selectTab.type == 'institution'"
+    <div v-if="selectTab.type == 'institution' && pageType === 'list'"
          class="link-list">
       <ul>
         <li v-for="(item, index) in list"
             :key="index">
-          <div>
+          <div @click="getDetails(item)">
             <img src=""
                  alt="" />
-            {{ item.title }}
+            {{ item.docName }}
           </div>
-          <span>{{ item.time }}</span>
+          <span>{{ parseTime(item.updatedTime, "{y}-{m}-{d}") }}</span>
         </li>
       </ul>
       <el-pagination background
+                     @size-change="handleSizeChange"
+                     @current-change="handleCurrentChange"
                      :current-page.sync="pageOptions.pageNum"
                      :page-size.sync="pageOptions.pageSize"
                      :total="pageOptions.total"
-                     layout="prev, pager, next">
+                     layout="total, prev, pager, next">
       </el-pagination>
     </div>
+    <div class="article" v-else-if="selectTab.type == 'institution' && pageType === 'details'">
+      <h4>{{ document.docName }}</h4>
+      <div class="snd-title">
+        <p>
+          <strong>发布人:</strong><span>{{ document.updatedName }}</span>
+        </p>
+        <p>
+          <strong>发布时间:</strong><span>{{ parseTime(document.updatedTime, "{y}-{m}-{d}") }}</span>
+        </p>
+        <p>
+          <strong>点击量:</strong><span>{{ document.clickCount }}</span>
+        </p>
+      </div>
+      <el-divider class="mt6"></el-divider>
+      <div class="text"
+           v-html="document.remark"></div>
+      <div slot="footer" class="card-footer">
+        附件【
+        <el-link @click="toDownload(document)">{{ document.docUrlName }}</el-link>
+        】已下载{{document.downloadCount}}次
+      </div>
+    </div>
     <div class="article"
          v-else-if="selectTab.type == 'intro'">
       <h4>{{ article.centerName }}</h4>
@@ -73,6 +97,12 @@ import {
   viewCenterStaff,
   getCenterPlatformList
 } from "@/api/introduce";
+import {
+  getEntityByClassName,
+  updateClickCountById,
+  updateDownloadCountById,
+} from "@/api/document";
+import {parseTime} from "@/utils/ruoyi";
 export default {
   name: "RightContent",
   props: {
@@ -100,6 +130,19 @@ export default {
         total: 100,
       },
       list: [],
+      pageType: 'list', // list details
+      document: {
+        id: 0,
+        docName: "平台简介",
+        docUrl: 'www.baidu.com',
+        docUrlName: '.docx',
+        docClassName: "A类",
+        updatedName: "张佳乐",
+        updatedTime: "2024-04-28 14:13:53",
+        clickCount: 100,
+        downloadCount: 100,
+        remark: "<strong>文章内容</strong>",
+      },
     };
   },
   watch: {
@@ -108,11 +151,18 @@ export default {
     },
   },
   methods: {
+    parseTime,
     async init() {
       if (this.selectTab.type == "intro") this.getIntro();
       else if (this.selectTab.type == "staff") this.getStaff();
       else if (this.selectTab.type == "institution") this.getInstitution();
     },
+    handleSizeChange () {
+      this.init()
+    },
+    handleCurrentChange () {
+      this.init()
+    },
     // 获取平台简介
     async getIntro() {
       const [err, res] = await to(getCenterIntroduction());
@@ -129,10 +179,32 @@ export default {
     },
     // 获取规章制度
     async getInstitution() {
-      const [err, res] = await to(getCenterPlatformList());
+      this.pageType = 'list'
+      let params = {
+        docClassName: '规章制度',
+        pageNum: this.pageOptions.pageNum,
+        pageSize: this.pageOptions.pageSize,
+      }
+      const [err, res] = await to(getEntityByClassName(params));
       if (err) return;
-      this.list = res.data;
-    }
+      this.list = res.data.list
+      this.pageOptions.total = res.data.total
+    },
+    // 获取详情
+    async getDetails(item) {
+      this.pageType = "details"
+      // 更新点击量
+      const [err, res] = await to(updateClickCountById({ id: item.id }))
+      if (err) return;
+      this.document = res.data
+    },
+    // 下载
+    async toDownload(item) {
+      const [err, res] = await to(updateDownloadCountById({ id: item.id }))
+      if (err) return;
+      this.document = res.data
+      window.open(res.data.docUrl, '_blank')
+    },
   },
 };
 </script>
@@ -206,4 +278,4 @@ export default {
     }
   }
 }
-</style>
+</style>

+ 1 - 1
src/router.js

@@ -23,7 +23,7 @@ let router = new Router({
       path: "/news",
       name: "news",
       meta: {
-        requireAuth: true,
+        // requireAuth: true
       },
       component: () => import("./views/News.vue"),
     },

+ 130 - 0
src/utils/ruoyi.js

@@ -0,0 +1,130 @@
+/**
+ * 通用js方法封装处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+// 日期格式化
+export function parseTime(time, pattern) {
+	if (arguments.length === 0 || !time) {
+		return null
+	}
+	const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+	let date
+	if (typeof time === 'object') {
+		date = time
+	} else {
+		if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+			time = parseInt(time)
+		} else if (typeof time === 'string') {
+			time = time.replace(new RegExp(/-/gm), '/');
+		}
+		if ((typeof time === 'number') && (time.toString().length === 10)) {
+			time = time * 1000
+		}
+		date = new Date(time)
+	}
+	const formatObj = {
+		y: date.getFullYear(),
+		m: date.getMonth() + 1,
+		d: date.getDate(),
+		h: date.getHours(),
+		i: date.getMinutes(),
+		s: date.getSeconds(),
+		a: date.getDay()
+	}
+	const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+		let value = formatObj[key]
+		// Note: getDay() returns 0 on Sunday
+		if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+		if (result.length > 0 && value < 10) {
+			value = '0' + value
+		}
+		return value || 0
+	})
+	return time_str
+}
+// 有效日期格式化
+export function formatValidity(time) {
+  if(time == '5000-01-01 23:59:59') return '永久'
+  return parseTime(time, '{y}-{m}-{d}')
+}
+// 表单重置
+export function resetForm(refName) {
+	if (this.$refs[refName]) {
+		this.$refs[refName].resetFields();
+	}
+}
+
+// 添加日期范围
+export function addDateRange(params, dateRange) {
+	var search = params;
+	search.beginTime = "";
+	search.endTime = "";
+	if (null != dateRange && '' != dateRange) {
+		search.beginTime = this.dateRange[0];
+		search.endTime = this.dateRange[1];
+	}
+	return search;
+}
+
+// 回显数据字典
+export function selectDictLabel(datas, value) {
+	var actions = [];
+	Object.keys(datas).map((key) => {
+		if (datas[key].key == ('' + value)) {
+			actions.push(datas[key].value);
+			return false;
+		}
+	})
+	return actions.join('');
+}
+
+// 字符串格式化(%s )
+export function sprintf(str) {
+	var args = arguments, flag = true, i = 1;
+	str = str.replace(/%s/g, function () {
+		var arg = args[i++];
+		if (typeof arg === 'undefined') {
+			flag = false;
+			return '';
+		}
+		return arg;
+	});
+	return flag ? str : '';
+}
+
+// 转换字符串,undefined,null等转化为""
+export function praseStrEmpty(str) {
+    if (!str || str == "undefined" || str == "null") {
+        return "";
+    }
+    return str;
+}
+
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ * @param {*} rootId 根Id 默认 0
+ */
+export function handleTree(data, id, parentId, children, rootId) {
+	id = id || 'id'
+	parentId = parentId || 'parentId'
+	children = children || 'children'
+	rootId = rootId || 0
+	//对源数据深度克隆
+	const cloneData = JSON.parse(JSON.stringify(data))
+	//循环所有项
+	const treeData =  cloneData.filter(father => {
+	  let branchArr = cloneData.filter(child => {
+		//返回每一项的子级数组
+		return father[id] === child[parentId]
+	  });
+	  branchArr.length > 0 ? father.children = branchArr : '';
+	  //返回第一层
+	  return father[parentId] == rootId;
+	});
+	return treeData != '' ? treeData : data;
+  }

+ 46 - 112
src/views/Case.vue

@@ -1,132 +1,66 @@
 <template>
-  <div class="case">
-    <banner img="../assets/img/bgtop.jpg" title="精典案例" />
-    <div class="case-section" v-loading="loading">
-      <div class="case-section-content">
-        <div class="case-section-content-list" v-for="(cas,index) in caseList" :key="index">
-          <img v-lazy="imgserver+cas.Img" />
-          <div class="content-list-abstract" :class="{'abstract-active' : index%2!=1}">
-            <p class="abstract-title">{{cas.Title}}</p>
-            <p class="abstract-content">{{cas.Content}}</p>
-            <div class="more">
-              <router-link
-                class="text-decoration"
-                :to="{ name: 'casedetails', params: { id: cas.Id }}"
-              >
-                <span>more</span>
-                <img src="../assets/img/sanjiao.png" />
-              </router-link>
-            </div>
-          </div>
-        </div>
-      </div>
+  <div class="news">
+    <Banner :img="require('@/assets/img/center-introduce.png')" />
+    <div class="common-container">
+      <el-container>
+        <CaseLeftTabs title="资料下载" :options="options" @tabSelect="tabSelect" />
+        <CaseRightContent :selectTab="selectTab" :breadList="breadList" />
+      </el-container>
     </div>
   </div>
 </template>
+
 <script>
+import {
+  getDocClassList,
+} from "@/api/document";
 import Banner from "../components/Banner";
+import CaseLeftTabs from '@/views/Case/LeftTabs'
+import CaseRightContent from '@/views/Case/RightContent'
+import to from "await-to-js";
 export default {
+  name: "Introduce",
   components: {
-    Banner
+    Banner,
+    CaseLeftTabs,
+    CaseRightContent
   },
   data() {
     return {
       loading: true,
-      caseList: []
+      selectTab: {},
+      options: [],
+      routeList: [
+        {
+          name: '首页',
+          path: '/'
+        },
+        {
+          name: '中心介绍'
+        }
+      ],
+      breadList: []
     };
   },
   mounted() {
-    window.console.log("case");
-    this.$http
-      .get("Cases/GetCasesAll")
-      .then(response => {
-        //console.log(response);
-        this.caseList = response.data;
-        //window.console.log(this.caseList);
-        this.loading = false;
-      })
-      .catch(function(error) {
-        window.console.log(error);
-      });
+    this.getDocClassList();
+  },
+  methods: {
+    // 选择tab
+    tabSelect(row) {
+      this.selectTab = { ...row }
+      this.breadList = [...this.routeList, { name: this.selectTab.name }]
+    },
+    // 获取资料类型
+    async getDocClassList() {
+      const [err, res] = await to(getDocClassList());
+      if (err) return;
+      this.options = res.data;
+    },
   }
 };
 </script>
 
- <style lang="scss" scoped>
-.case {
-  width: 100%;
-  height: 100%;
-  position: relative;
-  overflow: hidden;
-  background-color: #14679f;
+<style lang="scss" scoped>
 
-  &-section {
-    width: 100%;
-    &-content {
-      width: 1240px;
-      min-height: 1000px;
-      margin: 0 auto;
-      background-color: #fff;
-
-      &-list {
-        width: 100%;
-        height: 500px;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        border: 1px solid pink;
-
-        img {
-          width: 612px;
-          height: 314px;
-        }
-        .content-list-abstract {
-          width: 290px;
-          height: 350px;
-          padding: 0 20px;
-          display: flex;
-          flex-direction: column;
-          justify-content: space-around;
-          .abstract-title {
-            line-height: 30px;
-            font-size: 22px;
-            color: #e13834;
-          }
-          .abstract-content {
-            height: 150px;
-            color: #484848;
-            font-size: 15px;
-
-            overflow: hidden;
-            text-overflow: ellipsis;
-            display: -webkit-box;
-            -webkit-line-clamp: 7;
-            -webkit-box-orient: vertical;
-            white-space: normal !important;
-            word-wrap: break-word;
-            //border: 1px solid pink;
-          }
-          .more {
-            display: flex;
-            justify-content: flex-start;
-            .text-decoration {
-              text-decoration: none;
-
-              span {
-                color: #000;
-              }
-              img {
-                width: 12px;
-                height: 12px;
-              }
-            }
-          }
-        }
-        .abstract-active {
-          order: -1;
-        }
-      }
-    }
-  }
-}
-</style>
+</style>

+ 206 - 0
src/views/Case/DocDetails.vue

@@ -0,0 +1,206 @@
+<!--
+ * @Author: wanglj wanglijie@dashoo.cn
+ * @Date: 2025-01-09 10:52:48
+ * @LastEditors: wanglj
+ * @LastEditTime: 2025-01-09 19:55:04
+ * @Description: file content
+ * @FilePath: \labsop_website\src\components\RightContent.vue
+-->
+<template>
+  <el-card class="right-content">
+    <div slot="header"
+         class="header">
+      <h4>{{ selectTab.name }}</h4>
+      <el-breadcrumb separator-class="el-icon-d-arrow-right">
+        <el-breadcrumb-item v-for="(item, index) in breadList"
+                            :key="index"
+                            :to="item.path ? { path: item.path } : null">{{ item.name }} </el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <div class="document">
+      <h4>{{ document.docName }}</h4>
+      <div class="snd-title">
+        <p>
+          <strong>发布人:</strong><span>{{ document.updatedName }}</span>
+        </p>
+        <p>
+          <strong>发布时间:</strong><span>{{ parseTime(document.updatedTime, "{y}-{m}-{d}") }}</span>
+        </p>
+        <p>
+          <strong>点击量:</strong><span>{{ document.clickCount }}</span>
+        </p>
+      </div>
+      <el-divider class="mt6"></el-divider>
+      <div class="text"
+           v-html="document.remark"></div>
+      <div slot="footer" class="card-footer">
+        附件【
+        <el-link @click="toDownload(document)">{{ document.docUrlName }}</el-link>
+        】已下载{{document.downloadCount}}次
+      </div>
+    </div>
+  </el-card>
+</template>
+
+<script>
+import to from "await-to-js";
+import {
+  getDocListByClassId,
+  updateClickCountById,
+  updateDownloadCountById,
+} from "@/api/document";
+import {parseTime} from "@/utils/ruoyi";
+export default {
+  name: "CaseRightContent",
+  props: {
+    selectTab: {
+      type: Object,
+      default: () => {},
+    },
+    breadList: {
+      type: Array,
+      default: () => [],
+    },
+    docData: {
+      type: Object,
+      default: () => {},
+    }
+  },
+  data() {
+    return {
+      document: {
+        id: 0,
+        docName: "平台简介",
+        docUrl: 'www.baidu.com',
+        docUrlName: '.docx',
+        docClassName: "A类",
+        updatedName: "张佳乐",
+        updatedTime: "2024-04-28 14:13:53",
+        clickCount: 100,
+        downloadCount: 100,
+        remark: "<strong>文章内容</strong>",
+      },
+      pageOptions: {
+        pageSize: 10,
+        pageNum: 1,
+        total: 0,
+      },
+      list: [],
+      pageType: 'list', // list details
+    };
+  },
+  watch: {
+    document() {
+      this.getDetails();
+    },
+  },
+  methods: {
+    parseTime,
+    // 获取详情
+    async getDetails() {
+      this.pageType = "details"
+      // 更新点击量
+      const [err, res] = await to(updateClickCountById({ id: this.docData.id }))
+      if (err) return;
+      this.document = res.data
+    },
+    // 下载
+    async toDownload(item) {
+      const [err, res] = await to(updateDownloadCountById({ id: item.id }))
+      if (err) return;
+      this.document = res.data
+      window.open(res.data.docUrl, '_blank')
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.right-content {
+  flex: 1;
+  border-radius: 8px;
+  overflow: hidden;
+  height: 550px;
+  box-shadow: 0px 3px 6px 1px rgba(1, 64, 100, 0.16);
+  ::v-deep .el-card__body {
+    height: calc(100% - 100px);
+  }
+  .header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    h4 {
+      font-weight: bold;
+      font-size: 18px;
+      color: #2c405e;
+    }
+  }
+  .document {
+    h4 {
+      //text-align: center;
+      //font-weight: bold;
+      //font-size: 30px;
+      //line-height: 50px;
+      //color: #cc3333;
+      text-align: center;
+      font-weight: bold;
+      font-size: 24px;
+      color: #386afe;
+    }
+    .snd-title {
+      font-weight: 400;
+      line-height: 35px;
+      font-size: 14px;
+      color: #666666;
+      background: #f5f5f5;
+      display: flex;
+      justify-content: center;
+      margin: 15px auto 0 auto;
+      p {
+        margin: 8px;
+      }
+    }
+    .text {
+      height: 250px + 50px;
+    }
+    .card-footer {
+      text-align: left; /* 根据需要调整对齐方式 */
+      padding: 10px; /* 根据需要调整内边距 */
+    }
+  }
+  .link-list {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    overflow-y: auto;
+    ul {
+      flex: 1;
+      li {
+        display: flex;
+        justify-content: space-between;
+        padding: 12px;
+        border-bottom: 1px dashed #ebf1f6;
+        cursor: pointer;
+        transition: all 0.3s;
+        &:hover {
+          background-color: #e7f1ff;
+        }
+        div {
+          font-weight: 400;
+          font-size: 16px;
+          color: #585858;
+        }
+        span {
+          font-weight: 400;
+          font-size: 16px;
+          color: #b5c1d8;
+        }
+      }
+    }
+    .el-pagination {
+      display: flex;
+      justify-content: center;
+    }
+  }
+}
+</style>

+ 102 - 0
src/views/Case/LeftTabs.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="left-tabs">
+    <h4>{{ title }}</h4>
+    <ul>
+      <li v-for="(item, index) in options"
+          :key="item.id"
+          :class="{ active: index === active }"
+          @click="tabSelect(item, index)">
+        {{ item.name }}
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "CaseLeftTabs",
+  props: {
+    title: String,
+    options: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  watch: {
+    options: {
+      handler(val) {
+        if(val && val.length) {
+          this.tabSelect(val[0], 0)
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      active: -1,
+    };
+  },
+  methods: {
+    tabSelect(row, index) {
+      this.active = index;
+      this.$emit("tabSelect", row);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.left-tabs {
+  width: 266px;
+  border-radius: 8px;
+  overflow: hidden;
+  background-color: #fff;
+  box-shadow: 0px 3px 6px 1px rgba(1, 64, 100, 0.16);
+  margin-right: 24px;
+  height: 550px;
+  overflow-y: auto;
+  display: flex;
+  flex-direction: column;
+  h4 {
+    height: 72px;
+    line-height: 72px;
+    font-weight: bold;
+    font-size: 24px;
+    color: #ffffff;
+    text-align: center;
+    background: linear-gradient(99deg, #1964fe 0%, #19abff 100%);
+  }
+  ul {
+    flex: 1;
+    li {
+      height: 60px;
+      font-weight: 400;
+      font-size: 16px;
+      color: #323232;
+      cursor: pointer;
+      transition: all 0.3s;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      &:before {
+        content: "";
+        display: inline-block;
+        width: 8px;
+        height: 8px;
+        background: transparent;
+        border-radius: 4px;
+        margin-right: 8px;
+      }
+      &:hover,
+      &.active {
+        background-color: #e7f1ff;
+        &:before {
+          background: #2C78FF;
+        }
+      }
+    }
+  }
+}
+</style>

+ 248 - 0
src/views/Case/RightContent.vue

@@ -0,0 +1,248 @@
+<!--
+ * @Author: wanglj wanglijie@dashoo.cn
+ * @Date: 2025-01-09 10:52:48
+ * @LastEditors: wanglj
+ * @LastEditTime: 2025-01-09 19:55:04
+ * @Description: file content
+ * @FilePath: \labsop_website\src\components\RightContent.vue
+-->
+<template>
+  <el-card class="right-content">
+    <div slot="header"
+         class="header">
+      <h4>{{ selectTab.name }}</h4>
+      <el-breadcrumb separator-class="el-icon-d-arrow-right">
+        <el-breadcrumb-item v-for="(item, index) in breadList"
+                            :key="index"
+                            :to="item.path ? { path: item.path } : null">{{ item.name }} </el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <div v-if="pageType === 'list'"
+         class="link-list">
+      <ul>
+        <li v-for="(item, index) in list"
+            :key="index">
+          <div @click="getDetails(item)">
+            <img src=""
+                 alt="" />
+            {{ item.docName }}
+          </div>
+          <span>{{ parseTime(item.updatedTime, "{y}-{m}-{d}") }}</span>
+        </li>
+      </ul>
+      <el-pagination background
+                     @size-change="handleSizeChange"
+                     @current-change="handleCurrentChange"
+                     :current-page.sync="pageOptions.pageNum"
+                     :page-size.sync="pageOptions.pageSize"
+                     :total="pageOptions.total"
+                     layout="total, prev, pager, next">
+      </el-pagination>
+    </div>
+    <div class="article"
+         v-else-if="pageType === 'details'">
+      <h4>{{ article.docName }}</h4>
+      <div class="snd-title">
+        <p>
+          <strong>发布人:</strong><span>{{ article.updatedName }}</span>
+        </p>
+        <p>
+          <strong>发布时间:</strong><span>{{ parseTime(article.updatedTime, "{y}-{m}-{d}") }}</span>
+        </p>
+        <p>
+          <strong>点击量:</strong><span>{{ article.clickCount }}</span>
+        </p>
+      </div>
+      <el-divider class="mt6"></el-divider>
+      <div class="text"
+           v-html="article.remark"></div>
+      <div slot="footer" class="card-footer">
+        附件【
+        <el-link @click="toDownload(article)">{{ article.docUrlName }}</el-link>
+        】已下载{{article.downloadCount}}次
+      </div>
+    </div>
+  </el-card>
+</template>
+
+<script>
+import to from "await-to-js";
+import {
+  getDocListByClassId,
+  updateClickCountById,
+  updateDownloadCountById,
+} from "@/api/document";
+import {parseTime} from "@/utils/ruoyi";
+export default {
+  name: "CaseRightContent",
+  props: {
+    selectTab: {
+      type: Object,
+      default: () => {},
+    },
+    breadList: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      article: {
+        id: 0,
+        docName: "平台简介",
+        docUrl: 'www.baidu.com',
+        docUrlName: '.docx',
+        docClassName: "A类",
+        updatedName: "张佳乐",
+        updatedTime: "2024-04-28 14:13:53",
+        clickCount: 100,
+        downloadCount: 100,
+        remark: "<strong>文章内容</strong>",
+      },
+      pageOptions: {
+        pageSize: 10,
+        pageNum: 1,
+        total: 0,
+      },
+      list: [],
+      pageType: 'list', // list details
+    };
+  },
+  watch: {
+    selectTab() {
+      this.init();
+    },
+  },
+  methods: {
+    parseTime,
+    async init() {
+      this.pageType = 'list'
+      await this.getInstitutionList(this.selectTab.id);
+    },
+    // 获取资料下载列表
+    async getInstitutionList(classId) {
+      this.list = []
+      let params = {
+        docClassId: classId,
+        pageNum: this.pageOptions.pageNum,
+        pageSize: this.pageOptions.pageSize,
+      }
+      const [err, res] = await to(getDocListByClassId(params));
+      if (err) return;
+      this.pageOptions.total = res.data.total
+      this.list = res.data.list
+    },
+    handleSizeChange () {
+      this.init()
+    },
+    handleCurrentChange () {
+      this.init()
+    },
+    // 获取详情
+    async getDetails(item) {
+      this.pageType = "details"
+      // 更新点击量
+      const [err, res] = await to(updateClickCountById({ id: item.id }))
+      if (err) return;
+      this.article = res.data
+    },
+    // 下载
+    async toDownload(item) {
+      const [err, res] = await to(updateDownloadCountById({ id: item.id }))
+      if (err) return;
+      this.article = res.data
+      window.open(res.data.docUrl, '_blank')
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.right-content {
+  flex: 1;
+  border-radius: 8px;
+  overflow: hidden;
+  height: 550px;
+  box-shadow: 0px 3px 6px 1px rgba(1, 64, 100, 0.16);
+  ::v-deep .el-card__body {
+    height: calc(100% - 100px);
+  }
+  .header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    h4 {
+      font-weight: bold;
+      font-size: 18px;
+      color: #2c405e;
+    }
+  }
+  .article {
+    h4 {
+      //text-align: center;
+      //font-weight: bold;
+      //font-size: 30px;
+      //line-height: 50px;
+      //color: #cc3333;
+      text-align: center;
+      font-weight: bold;
+      font-size: 24px;
+      color: #386afe;
+    }
+    .snd-title {
+      font-weight: 400;
+      line-height: 35px;
+      font-size: 14px;
+      color: #666666;
+      background: #f5f5f5;
+      display: flex;
+      justify-content: center;
+      margin: 15px auto 0 auto;
+      p {
+        margin: 8px;
+      }
+    }
+    .text {
+      height: 250px + 50px;
+    }
+    .card-footer {
+      text-align: left; /* 根据需要调整对齐方式 */
+      padding: 10px; /* 根据需要调整内边距 */
+    }
+  }
+  .link-list {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    overflow-y: auto;
+    ul {
+      flex: 1;
+      li {
+        display: flex;
+        justify-content: space-between;
+        padding: 12px;
+        border-bottom: 1px dashed #ebf1f6;
+        cursor: pointer;
+        transition: all 0.3s;
+        &:hover {
+          background-color: #e7f1ff;
+        }
+        div {
+          font-weight: 400;
+          font-size: 16px;
+          color: #585858;
+        }
+        span {
+          font-weight: 400;
+          font-size: 16px;
+          color: #b5c1d8;
+        }
+      }
+    }
+    .el-pagination {
+      display: flex;
+      justify-content: center;
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/Introduce.vue

@@ -63,4 +63,4 @@ export default {
 
 <style lang="scss" scoped>
 
-</style>
+</style>

+ 9 - 7
src/views/News.vue

@@ -4,7 +4,7 @@
     <div class="common-container">
       <el-container>
         <LeftTabs title="新闻动态" :options="options" @tabSelect="tabSelect" />
-        <RightContent :selectTab="selectTab" :breadList="breadList" />
+        <NewsRightContent :selectTab="selectTab" :breadList="breadList" />
       </el-container>
     </div>
   </div>
@@ -13,13 +13,13 @@
 <script>
 import Banner from "../components/Banner";
 import LeftTabs from '@/components/LeftTabs'
-import RightContent from '@/components/RightContent'
+import NewsRightContent from '@/views/News/RightContent'
 export default {
-  name: "Introduce",
+  name: "News",
   components: {
     Banner,
     LeftTabs,
-    RightContent
+    NewsRightContent
   },
   data() {
     return {
@@ -27,10 +27,12 @@ export default {
       selectTab: {},
       options: [
         {
-          label: '中心新闻'
+          label: '中心新闻',
+          type:'newsInfo',
         },
         {
-          label: '通知公告'
+          label: '通知公告',
+          type:'notice',
         }
       ],
       routeList: [
@@ -57,4 +59,4 @@ export default {
 
 <style lang="scss" scoped>
 
-</style>
+</style>

+ 290 - 0
src/views/News/RightContent.vue

@@ -0,0 +1,290 @@
+<!--
+ * @Author: wanglj wanglijie@dashoo.cn
+ * @Date: 2025-01-09 10:52:48
+ * @LastEditors: wanglj
+ * @LastEditTime: 2025-01-09 19:55:04
+ * @Description: file content
+ * @FilePath: \labsop_website\src\components\RightContent.vue
+-->
+<template>
+  <el-card class="right-content">
+    <div slot="header"
+         class="header">
+      <h4>{{ selectTab.label }}</h4>
+      <el-breadcrumb separator-class="el-icon-d-arrow-right">
+        <el-breadcrumb-item v-for="(item, index) in breadList"
+                            :key="index"
+                            :to="item.path ? { path: item.path } : null">{{ item.name }} </el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <!--  中心新闻  -->
+    <div v-if="selectTab.type == 'newsInfo' && pageType === 'list'"
+         class="link-list">
+      <ul>
+        <li v-for="(item, index) in list"
+            :key="index">
+          <div @click="getDetails(item)">
+            <img src=""
+                 alt="" />
+            {{ item.newsTitle }}
+          </div>
+          <span>{{ parseTime(item.updatedTime, "{y}-{m}-{d}") }}</span>
+        </li>
+      </ul>
+      <el-pagination background
+                     @size-change="handleSizeChange"
+                     @current-change="handleCurrentChange"
+                     :current-page.sync="pageOptions.pageNum"
+                     :page-size.sync="pageOptions.pageSize"
+                     :total="pageOptions.total"
+                     layout="total, prev, pager, next">
+      </el-pagination>
+    </div>
+    <div class="article" v-else-if="selectTab.type == 'newsInfo' && pageType === 'details'">
+      <h4>{{ news.newsTitle }}</h4>
+      <div class="snd-title">
+        <p>
+          <strong>发布人:</strong><span>{{ news.updatedName }}</span>
+        </p>
+        <p>
+          <strong>发布时间:</strong><span>{{ parseTime(news.updatedTime, "{y}-{m}-{d}") }}</span>
+        </p>
+        <p>
+          <strong>来源:</strong><span>{{ news.newsSource }}</span>
+        </p>
+        <p>
+          <strong>点击量:</strong><span>{{ news.clickNum }}</span>
+        </p>
+      </div>
+      <el-divider class="mt6"></el-divider>
+      <div class="text"
+           v-html="news.newsContent"></div>
+    </div>
+    <!--  通知公告  -->
+    <div v-if="selectTab.type == 'notice' && pageType === 'list'"
+         class="link-list">
+      <ul>
+        <li v-for="(item, index) in list"
+            :key="index">
+          <div @click="getDetails(item)">
+            <img v-if="item.isTop === '10'" src="@/assets/img/isTop.png" alt />
+            【{{ item.noticeType === '10' ? '公告' : '通知' }}】{{ item.noticeTitle }}
+          </div>
+          <span>{{ parseTime(item.noticeTime, "{y}-{m}-{d}") }}</span>
+        </li>
+      </ul>
+      <el-pagination background
+                     @size-change="handleSizeChange"
+                     @current-change="handleCurrentChange"
+                     :current-page.sync="pageOptions.pageNum"
+                     :page-size.sync="pageOptions.pageSize"
+                     :total="pageOptions.total"
+                     layout="total, prev, pager, next">
+      </el-pagination>
+    </div>
+    <div class="article" v-else-if="selectTab.type == 'notice' && pageType === 'details'">
+      <h4>{{ notice.noticeTitle }}</h4>
+      <div class="snd-title">
+        <p>
+          <strong>发布人:</strong><span>{{ notice.createdName }}</span>
+        </p>
+        <p>
+          <strong>发布时间:</strong><span>{{ parseTime(notice.noticeTime, "{y}-{m}-{d}") }}</span>
+        </p>
+      </div>
+      <el-divider class="mt6"></el-divider>
+      <div class="text"
+           v-html="notice.noticeContent"></div>
+    </div>
+  </el-card>
+</template>
+
+<script>
+import to from "await-to-js";
+import {
+  getNewsInformationList,
+  getNewsInformation,
+  viewNewsInformation,
+  getNoticeList,
+  getNoticeEntity,
+} from "@/api/news";
+import { parseTime } from "@/utils/ruoyi";
+export default {
+  name: "NewsRightContent",
+  props: {
+    selectTab: {
+      type: Object,
+      default: () => {},
+    },
+    breadList: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      pageOptions: {
+        pageSize: 10,
+        pageNum: 1,
+        total: 100,
+      },
+      list: [],
+      pageType: 'list', // list details
+      news: {
+        id: 0,
+        newsTitle: "平台简介",
+        newsContent: 'www.baidu.com',
+        newsSource: '.docx',
+        clickNum: 100,
+        remark: "<strong>文章内容</strong>",
+      },
+      notice: {
+        id: 100011,
+        isTop: "10",
+        noticeType: "10",
+        fileType: "",
+        imageUrl: "http://192.168.0.218:9390/4,0d84095983bbd6",
+        noticeContent: "<p>1</p>",
+        noticeLevel: "10",
+        noticeStatus: "10",
+        noticeTime: "2024-11-28 11:46:48",
+        noticeTitle: "2",
+        platId: 100001,
+        platName: "仪器共享",
+        readTime: "2024-11-28 11:21:09",
+        redirectUrl: "",
+        createdName: '',
+      },
+    };
+  },
+  watch: {
+    selectTab() {
+      this.init();
+    },
+  },
+  methods: {
+    parseTime,
+    async init() {
+      if (this.selectTab.type == "newsInfo") this.getNewsInfoList()
+      else if (this.selectTab.type == "notice") this.getNoticeList()
+    },
+    handleSizeChange () {
+      this.init()
+    },
+    handleCurrentChange () {
+      this.init()
+    },
+    // 获取详情
+    async getDetails(item) {
+      this.pageType = "details"
+      if (this.selectTab.type == "newsInfo") {
+        const [err, res] = await to(getNewsInformation({ id: item.id }))
+        if (err) return;
+        // 修改点击量
+        const [e] = await to(viewNewsInformation({ id: item.id }))
+        if (e) return
+        this.news = res.data
+      } else if (this.selectTab.type == "notice") {
+        const [err, res] = await to(getNoticeEntity({ id: item.id }))
+        if (err) return;
+        this.notice = res.data
+      }
+    },
+    // 获取中心新闻
+    async getNewsInfoList() {
+      this.pageType = 'list'
+      let params = {
+        pageNum: this.pageOptions.pageNum,
+        pageSize: this.pageOptions.pageSize,
+      }
+      const [err, res] = await to(getNewsInformationList(params));
+      if (err) return;
+      this.list = res.data.list
+      this.pageOptions.total = res.data.total
+    },
+    // 获取通知公告
+    async getNoticeList() {
+      this.pageType = 'list'
+      let params = {
+        pageNum: this.pageOptions.pageNum,
+        pageSize: this.pageOptions.pageSize,
+      }
+      const [err, res] = await to(getNoticeList(params));
+      if (err) return;
+      this.list = res.data.list
+      this.pageOptions.total = res.data.total
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.right-content {
+  flex: 1;
+  border-radius: 8px;
+  overflow: hidden;
+  min-height: 550px;
+  box-shadow: 0px 3px 6px 1px rgba(1, 64, 100, 0.16);
+  ::v-deep .el-card__body {
+    height: calc(100% - 100px);
+  }
+  .header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    h4 {
+      font-weight: bold;
+      font-size: 18px;
+      color: #2c405e;
+    }
+  }
+  .article {
+    h4 {
+      text-align: center;
+      font-weight: bold;
+      font-size: 24px;
+      color: #386afe;
+    }
+    .snd-title {
+      font-weight: 400;
+      font-size: 14px;
+      color: #565656;
+      display: flex;
+      justify-content: center;
+      p {
+        margin: 8px;
+      }
+    }
+  }
+  .link-list {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    overflow-y: auto;
+    ul {
+      flex: 1;
+      li {
+        display: flex;
+        justify-content: space-between;
+        padding: 12px;
+        border-bottom: 1px dashed #ebf1f6;
+        cursor: pointer;
+        transition: all 0.3s;
+        &:hover {
+          background-color: #e7f1ff;
+        }
+        div {
+          font-weight: 400;
+          font-size: 16px;
+          color: #585858;
+        }
+        span {
+          font-weight: 400;
+          font-size: 16px;
+          color: #b5c1d8;
+        }
+      }
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/Register.vue

@@ -356,4 +356,4 @@ a {
   background-color: #fff;
   width: 40%;
 }
-</style>
+</style>