重构新闻列表 配置动态浏览器图标 问题修改

base
JayChou 6 months ago
parent 4c504f76d4
commit 3a6254d1cc
  1. 3
      index.html
  2. BIN
      public/favicon.ico
  3. 18
      src/Layout/main/index.vue
  4. 36
      src/Layout/tabbar/index.vue
  5. 10
      src/api/news.ts
  6. 3
      src/directives/defaultImage.ts
  7. 19
      src/store/module/setting.ts
  8. 3
      src/styles/index.scss
  9. 2
      src/views/competition/index.vue
  10. 101
      src/views/home/index.vue
  11. 2
      src/views/news/components/newsDetail.vue
  12. 308
      src/views/news/index.vue
  13. 114
      src/views/raceInfo/index.vue

@ -2,7 +2,8 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>高赛通</title>
</head>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -4,20 +4,24 @@
<router-view :key="$route.path" />
</transition>
</section> -->
<router-view></router-view>
<!-- <router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component"></component>
<!-- <router-view></router-view> -->
<router-view v-slot="{ Component }">
<keep-alive :include="cachedRoutes">
<component :is="Component"></component>
</keep-alive>
</router-view> -->
</router-view>
</template>
<script lang="ts" setup>
import {} from 'vue'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import settingStore from '@/store/module/setting'
const $route = useRoute()
const useSettingStore = settingStore()
console.log($route)
//
const cachedRoutes = ref(['Home']) // name
useSettingStore.setLogo()
</script>
<style lang="scss" scoped></style>

@ -4,11 +4,7 @@
<div class="left">
<div class="logo-box">
<div class="lesson">
<img
src="../../assets/images/LOGO.png"
alt=""
/>
<img :src="logoUrl" alt="" />
<!-- <img src="../../assets/images/LOGO.png" alt=""> -->
</div>
</div>
@ -30,7 +26,10 @@
</div>
</div>
<div class="right" v-if="!useUserStore.token">
<div class="registered gradient" @click="$router.push('/login?registered=true')">
<div
class="registered gradient"
@click="$router.push('/login?registered=true')"
>
注册
</div>
<div class="login" @click="$router.push('/login')">登录</div>
@ -40,7 +39,7 @@
<img
:src="setImageUrl(useUserStore.userInfo.avatar)"
alt=""
v-default-image="defaultUserAvater"
/>
</div>
<el-dropdown style="width: 0.625rem">
@ -67,11 +66,13 @@
<script lang="ts" setup>
import { constRouter } from '@/router/module/constRouter'
import { useRouter, useRoute } from 'vue-router'
import { onMounted, ref } from 'vue'
import { onMounted, ref, watch } from 'vue'
import userStore from '@/store/module/user'
import settingStore from '@/store/module/setting'
import Item from './components/item.vue'
import { getLogo } from '@/api/setting'
import defaultUserAvater from '@/assets/images/default.png'
const useUserStore = userStore()
const useSettingStore = settingStore()
const $router = useRouter()
const $route = useRoute()
const flog = ref(false)
@ -89,17 +90,24 @@ const layout = async () => {
$router.push('/login')
}
const setImageUrl = (url: string) => {
return import.meta.env.VITE_APP_BASE_API + '/sys/common/static/' + url
return import.meta.env.VITE_APP_BASE_API + '/' + url
}
// logo
const logoUrl = ref<string>('')
const getLogoSetting = async () => {
const res: any = await getLogo()
console.log(res, 'res')
logoUrl.value = res.result.logo
setTimeout(() => {
console.log(useSettingStore.logo, 'useSettingStore.logo')
logoUrl.value = setImageUrl(useSettingStore.logo)
}, 100)
}
getLogoSetting()
watch(
() => useSettingStore.logo,
() => {
getLogoSetting()
},
)
// getLogoSetting()
</script>
<style lang="scss" scoped>

@ -6,10 +6,16 @@ export const getColumnListApi = () => {
})
}
//根据栏目id获取新闻列表
export function queryEssayListApi(columnId) {
export function queryEssayListApi(columnId:any) {
return request.get(`/cms/front/getArticleListByColumn?columnId=${columnId}`)
}
//根据点击的新闻id获取新闻详细信息
export function queryEssayApi(id) {
export function queryEssayApi(id:any) {
return request.get(`/cms/front/getByArticleTitle?id=${id}`)
}
// 获取新闻列表
export const getNewsListApi = () => {
return request({
url: '/cms/cmsArticle/getColumArt',
})
}

@ -1,8 +1,9 @@
import defaultImage from '@/assets/images/item.png';
export default {
mounted(el: any, binding: any) {
el.onerror = () => {
// 当图片加载失败时,设置默认图片
el.src = binding.value || '/student/src/assets/images/item.png' // 默认图片
el.src = binding.value || defaultImage // 默认图片
}
},
}

@ -0,0 +1,19 @@
import { defineStore } from 'pinia'
import { getLogo } from '@/api/setting'
const settingStore = defineStore('setting', {
state: () => ({
logo: '',
}),
actions: {
setLogo() {
getLogo().then((res: any) => {
console.log(res, 'this.logo')
this.logo = res.result.logo
document.querySelector("link[rel~='icon']").href = import.meta.env.VITE_APP_BASE_API + '/' + this.logo
})
},
},
})
export default settingStore

@ -43,4 +43,7 @@
color: #6da0ff !important;
font-weight: 700;
opacity: .5;
}
img{
width: 100%;
}

@ -96,7 +96,7 @@
<div class="top">2024年度</div>
<div class="center">
<div class="text">{{ i.name }}</div>
<img src="../../assets/images/编组.png" alt="" />
<img style="width: 35px;" src="../../assets/images/编组.png" alt="" />
</div>
<div class="bottom">
报名时间{{ i.starttime }} - {{ i.endtime }}

@ -2,24 +2,28 @@
<div class="container-1420" v-if="isLoading">
<div class="banner">
<div class="title">{{ reacProjectList[0].compName }}火热报名中</div>
<!-- <div class="description">
<div v-html="reacProjectList[0].compName"></div>
</div> -->
<div class="description">
<div v-html="reacProjectList[0].compInfo"></div>
</div>
<div
class="application gradient"
@click="toDetail(reacProjectList[0].id)"
>
立即报名
</div>
</div>
<!-- 比赛列表 -->
<!-- 新闻列表 -->
<div class="news-list">
<div class="news-title">
<div class="top">新闻资讯</div>
<div class="bottom">30+项目登陆后报名</div>
<div class="top">
<div>新闻资讯</div>
<div @click="router.push('/news')">
<el-icon><ArrowRightBold /></el-icon>
</div>
</div>
<!-- <div class="bottom">30+项目登陆后报名</div> -->
</div>
<div class="newa-panel">
<div class="tab">
@ -34,12 +38,7 @@
</div>
<div class="newa-main">
<div class="left">
<img
src=""
alt=""
style="width: 100%; height: 100%"
/>
<img src="" alt="" style="width: 100%; height: 100%" />
</div>
<div class="right">
<div class="title">{{ newInfo.name }}</div>
@ -48,10 +47,14 @@
</div>
<div class="newa-main-list">
<ul>
<li v-for="item in childrenNewList" :key="item.id">
<div class="time">{{ item.createTime }}</div>
<li v-for="item in childrenNewList" :key="item.id" @click="toNewsDetail(item.id)">
<div class="info">
{{ item.info }}
{{ item.columnName }}
</div>
<div class="time">{{ item.createTime }}</div>
<div class="name">
{{ item.createBy_dictText }}
</div>
</li>
</ul>
@ -64,6 +67,7 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { getRaceList } from '@/api/race'
import { useRouter } from 'vue-router'
@ -109,7 +113,12 @@ const toDetail = (id: number) => {
},
})
}
const toNewsDetail = (id: number) => {
router.push({
path: '/detail/' + id,
})
}
//
const newList = ref<any>([])
const getNewsList = async () => {
@ -139,7 +148,11 @@ const toggleTab = (item: any, index: number) => {
getNewInfo(newInfo.value.id)
}
</script>
<script lang="ts">
export default {
name: 'Home', //
};
</script>
<style lang="scss" scoped>
.banner {
position: relative;
@ -167,6 +180,12 @@ const toggleTab = (item: any, index: number) => {
font-size: 20px;
color: #666;
margin-top: 37px;
line-height: 32px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.application {
width: 272px;
@ -263,6 +282,25 @@ const toggleTab = (item: any, index: number) => {
font-size: 40px;
font-weight: 600;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
div {
display: flex;
align-items: center;
justify-content: center;
margin: 0 10px;
}
div:last-child {
cursor: pointer;
transition: all 0.2s;
&:hover {
color: #0bd7c6;
transform: scale(1.2);
}
}
}
.bottom {
font-size: 16px;
@ -346,20 +384,22 @@ const toggleTab = (item: any, index: number) => {
ul {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
// display: flex;
// flex-wrap: wrap;
justify-content: space-between;
// align-items: center;
li {
width: 227px;
// width: 227px;
width: 100%;
height: 65px;
cursor: pointer;
display: flex;
.time {
position: relative;
font-size: 14px;
color: #1e2033;
padding-left: 13px;
margin-left: 20px;
}
.time::before {
.info::before {
content: ' ';
display: block;
position: absolute;
@ -370,10 +410,19 @@ const toggleTab = (item: any, index: number) => {
background-color: #319245;
}
.info {
margin-top: 12px;
font-size: 12px;
position: relative;
// margin-top: 12px;
font-size: 14px;
color: #1e2033;
line-height: 18px;
// line-height: 18px;
padding-left: 13px;
}
.name{
font-size: 14px;
margin-left: 20px;
}
}
}

@ -49,7 +49,7 @@ const completeImageUrl = computed(() => {
width: 60%;
margin: auto;
height: 98vh;
overflow-y: scroll;
/* overflow-y: scroll; */
padding: 0;
display: block;
margin-top: 100px;

@ -1,183 +1,161 @@
<template>
<div class="main">
<el-tabs
v-model="activeName"
style="max-width: 70%; margin: auto"
class="container"
@tab-click="handleTabClick"
>
<el-tab-pane
v-for="category in categories"
:key="category.id"
:label="category.name"
:name="category.id"
>
<ul>
<li
v-for="newsItem in getNewsItemsForCategory(category)"
:key="newsItem.id"
>
<div class="box-list" @click.stop="handleNewsClick(newsItem)">
<div class="left-box-list">
<p class="list-title">{{ newsItem.title }}</p>
<p class="list-summary">
{{ stripHtmlTags(newsItem.summary) }}
</p>
<p class="list-time">{{ newsItem.date }}</p>
<div class="container">
<div class="news-list">
<div class="item" v-for="(item,index) in newsList" :key="item.id">
<div class="news-title" :id="index.toString()">{{ item.name }}</div>
<div class="children">
<div class="son-item" v-for="obj in item.cmsArticleList" :key="obj.id" @click="toNewsDetail(obj.id)">
<div class="left">
<div class="title">{{ obj.title }}</div>
<div class="content">
{{ obj.info }}
</div>
<img
class="news-image"
:src="newsItem.imageUrl"
alt="News Image"
/>
<div class="time"><div>{{ obj.publishTime }}</div> <div style="margin-left: 20px;">发布人{{ obj.createBy }}</div></div>
</div>
<el-divider />
</li>
</ul>
</el-tab-pane>
</el-tabs>
<div class="right">
<img :src="setImageUrl(obj.comimg)" alt="" v-default-image/>
</div>
</div>
<el-empty description="无新闻" v-if="item.cmsArticleList.length === 0" style="height: 200px;"/>
</div>
</div>
</div>
<!-- 右侧栏目 -->
</div>
<div class="right-coulom">
<div :class="active === index ? 'item active' : 'item' " @click="scrollById(index)" v-for="(item,index) in columnList" :key="item">{{ item }}</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { getColumnListApi, queryEssayListApi } from '@/api/news'
let categories = ref([])
let newsItems = ref({})
let activeName = ref('')
const router = useRouter()
//使html
function stripHtmlTags(html) {
return html.replace(/<[^>]*>/g, '')
}
//
const fetchColumnList = async () => {
const response = await getColumnListApi()
if (response.success && response.result) {
categories.value = response.result.filter(
(category) => category.isShow === '1',
)
//
if (categories.value.length > 0) {
await fetchNewsList(categories.value[0].id)
activeName.value = categories.value[0].id
}
}
}
import { getNewsListApi } from '@/api/news'
//
const fetchNewsList = async (categoryId) => {
try {
const response = await queryEssayListApi(categoryId)
// console.log(response.success,'')
// console.log(response.result.records,'')
if (response.success && response.result.records) {
newsItems.value[categoryId] = response.result.records.map((data) => ({
id: data.id,
title: data.title,
date: data.publishTime,
summary: data.content,
imageUrl: data.comimg ? getAbsoluteImagePath(data.comimg) : '',
}))
}
} catch (error) {
console.error('获取新闻列表失败', error)
}
}
//
const getAbsoluteImagePath = (relativePath) => {
const baseImageUrl = 'https://localhost:18085/jeecg-boot/' //
return baseImageUrl + relativePath
}
//
const getNewsItemsForCategory = (category) => {
return newsItems.value[category.id] || []
}
//
onMounted(() => {
fetchColumnList()
})
//
const handleTabClick = async (tab) => {
const categoryId = tab.props.name
if (!newsItems.value[categoryId]?.length) {
await fetchNewsList(categoryId)
}
activeName.value = categoryId
}
//
const handleNewsClick = (newsItem) => {
const router = useRouter()
const newsList = ref<any>([])
const columnList = ref<any>([])
const active = ref(0)
const getNewsListApiEvent = async () => {
const res:any = await getNewsListApi()
console.log(res, '212121')
columnList.value = res.result.map(item => item.name)
newsList.value = res.result
}
getNewsListApiEvent()
const scrollById = (index: number) => {
active.value = index
const targetPosition = (document.getElementById(index.toString()) as HTMLElement).offsetTop - 120;
window.scrollTo({
top: targetPosition,
behavior: 'smooth', //
});
}
const toNewsDetail = (id: number) => {
router.push({
name: 'newsDetail',
params: { id: newsItem.id.toString() },
path: '/detail/' + id
})
}
</script>
<style scoped>
.main {
margin-top: 100px;
const setImageUrl = (url: string) => {
return import.meta.env.VITE_APP_BASE_API + '/sys/common/static/' + url
}
</script>
<style scoped lang="scss">
.container {
width: 1200px;
margin: auto;
height: 98vh;
overflow-y: scroll;
padding: 0;
display: block;
}
.container::-webkit-scrollbar {
width: 0;
}
.box-list {
display: flex;
width: 95%;
height: 100px;
margin-left: 30px;
margin-bottom: 10px;
align-items: center;
cursor: pointer; /* 默认鼠标指针形状 */
}
.box-list:hover {
background-color: lightgrey; /* 鼠标悬停时改变背景颜色 */
}
.left-box-list {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
padding-right: 10px;
}
.list-title {
font-size: 22px;
margin-left: 60px;
}
.list-summary {
font-size: 16px;
margin-left: 60px;
margin-top: 15px;
color: #999999;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-overflow: ellipsis; /* 溢出部分显示为省略号 */
max-width: calc(100% - 130px); /* 减去右侧图片宽度和内边距 */
}
.list-time {
margin-left: 60px;
margin-top: 20px;
color: #999999;
margin-top: 100px;
.news-list {
width: 100%;
// height: 900px;
// background-color: #f2f3f5;
padding: 15px;
border: 1px solid #f2f3f5;
border-radius: 5px;
.item {
.news-title {
font-size: 24px;
font-weight: 700;
}
.children {
margin: 20px 0;
.son-item {
width: 100%;
height: 100px;
background-color: #fff;
padding: 15px;
display: flex;
border-bottom: 1px solid rgba(228, 230, 235, 0.5);
justify-content: space-between;
cursor: pointer;
.left {
width: 1000px;
.title {
font-size: 18px;
font-weight: 700;
color: #4f5153;
}
.content {
margin-top: 8px;
font-size: 13px;
color: #8a919f;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
}
.time {
margin-top: 8px;
font-size: 12px;
color: #8a919f;
display: flex;
}
}
.right {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
img {
width: 100%;
height: 100%;
}
}
&:hover {
background-color: #f7f8fa;
}
}
}
}
}
}
.news-image {
width: 100px;
height: 80px;
margin-right: 30px;
.right-coulom {
position: fixed;
left: 200px;
top: 100px;
z-index: 999;
width: 150px;
// height: 300px;
background-color: #f2f3f5;
padding: 10px;
border-radius: 5px;
.item {
height: 45px;
// text-align: center;
line-height: 22px;
font-size: 16px;
padding: 10px;
border-radius: 5px;
cursor: pointer;
margin: 5px 0;
&:hover {
background-color: #0bd7c628;
color: #0bd7c6;
}
}
.active {
background-color: #0bd7c628;
color: #0bd7c6;
}
}
</style>

@ -1,6 +1,5 @@
<template>
<div class="container-1420 container">
<el-card v-if="reacProjectList.length === 0">
<div
style="
@ -21,15 +20,18 @@
<div class="left-info">
<el-card>
<template #header>
<el-breadcrumb>
<el-breadcrumb-item
v-for="item in Route.matched"
:key="item.path"
:to="{ path: item.path }"
>
{{ item.meta.title }}
</el-breadcrumb-item>
</el-breadcrumb>
<div style="display: flex;justify-content: space-between;">
<el-breadcrumb>
<el-breadcrumb-item
v-for="item in Route.matched"
:key="item.path"
:to="{ path: item.path }"
>
{{ item.meta.title }}
</el-breadcrumb-item>
</el-breadcrumb>
<div><el-button @click="scrollToPosition">查看详情</el-button></div>
</div>
</template>
<div>
<!-- {{ raceInfo }} -->
@ -51,11 +53,11 @@
<div class="label">比赛名称:</div>
<div class="text">{{ raceInfo.compName }}</div>
</li>
<li style="width: 40%;">
<div class="label" >负责人:</div>
<li style="width: 40%">
<div class="label">负责人:</div>
<div class="text">{{ raceInfo.createBy }}</div>
</li>
<li style="width: 60%;">
<li style="width: 60%">
<div class="label">负责部门:</div>
<div class="text">{{ raceInfo.comporderc }}</div>
</li>
@ -77,6 +79,7 @@
<div class="center">
<div class="label">比赛简介:</div>
<div class="deaceiption">
<!-- <div v-html="raceInfo.compDetail"></div> -->
{{ raceInfo.compInfo }}
<!-- 亲爱的同学们老师们以及各位编程爱好者们
在这个充满创新与挑战的时代一场精彩纷呈的大学生编程大赛即将拉开帷幕
@ -88,7 +91,13 @@
</div>
<div class="label">附件:</div>
<div class="file">
<el-tag v-for="item in fileList" :key="item" type="primary" @click="doLoadFile(item)" style="margin-right: 15px;">
<el-tag
v-for="item in fileList"
:key="item"
type="primary"
@click="doLoadFile(item)"
style="margin-right: 15px"
>
{{ item }}
</el-tag>
</div>
@ -121,10 +130,11 @@
</el-card>
</div>
</div>
<!-- 年度比赛列表 -->
<div style="margin-top: 30px;font-size: 24px;font-weight: 600;">年度比赛列表:</div>
<!-- 年度比赛列表 -->
<div style="margin-top: 30px; font-size: 24px; font-weight: 600">
年度比赛列表:
</div>
<div class="race-list">
<div
class="item"
v-for="item in reacProjectList"
@ -132,21 +142,25 @@
@click="goToCompetition(item.id)"
>
<div class="image">
<img
:src="setImageUrl(item.image)"
alt=""
/>
<img :src="setImageUrl(item.image)" alt="" v-default-image/>
</div>
<div class="reac-info">
<div class="niandu">{{item.annualname}}年度</div>
<div class="reac-title" style="font-weight: 600;color: #000;font-size: 16px;">{{ item.name }}</div>
<div class="niandu">{{ item.annualname }}年度</div>
<div
class="reac-title"
style="font-weight: 600; color: #000; font-size: 16px"
>
{{ item.name }}
</div>
<div class="reac-title">负责部门{{ item.compOrgan }}</div>
<!-- <div class="reac-project">{{ item.introduction }}</div> -->
<div class="time" style="display: flex;justify-content: space-between;">
<div> 开始时间:{{ item.starttime }} </div>
结束时间:{{ item.endtime }}
<div></div>
<div
class="time"
style="display: flex; justify-content: space-between"
>
<div>开始时间:{{ item.starttime }}</div>
结束时间:{{ item.endtime }}
<div></div>
</div>
<!-- <div class="time">
@ -154,6 +168,13 @@
</div>
</div>
</div>
<h3
style="margin-top: 20px; font-size: 24px; font-weight: 700"
id="introduction"
>
比赛详情
</h3>
<div class="race-description" v-html="raceInfo.compDetail"></div>
</div>
</template>
@ -196,7 +217,7 @@ getraceInfoEvent()
//
const goToCompetition = (id: any) => {
Router.push({ path: '/competition', query: { id ,raceId:Route.query.id } })
Router.push({ path: '/competition', query: { id, raceId: Route.query.id } })
}
const doLoadFile = (url: any) => {
@ -215,13 +236,20 @@ getHistoryRaceListEvent()
const fileList = ref<any>([])
const createfileLink = (url: any) => {
console.log(url);
const list = url.split(",")
console.log(list);
console.log(url)
const list = url.split(',')
console.log(list)
fileList.value = list
}
const scrollToPosition = () => {
const targetPosition = (document.getElementById('introduction')as HTMLElement).offsetTop - 100;
window.scrollTo({
top: targetPosition,
behavior: 'smooth', //
});
}
</script>
<style lang="scss" scoped>
@ -284,7 +312,7 @@ const createfileLink = (url: any) => {
color: #8c8b8b;
margin-top: 30px;
}
.niandu{
.niandu {
color: #1e2033;
font-size: 18px;
margin-top: 20px;
@ -434,9 +462,25 @@ const createfileLink = (url: any) => {
}
}
}
.race-description {
width: 100%;
font-size: 14px;
line-height: 22px;
border: 1px solid #ccc;
padding: 10px;
margin-top: 20px;
p {
img {
width: 100%;
}
}
}
}
:deep(.el-card) {
width: 100%;
height: 100%;
}
img {
width: 100%;
}
</style>

Loading…
Cancel
Save