significative 8 months ago
commit e16e5f4cc5
  1. 2
      index.html
  2. 41
      src/Layout/footer/index.vue
  3. 2
      src/Layout/tabbar/index.vue
  4. 96
      src/api/race.ts
  5. 8
      src/api/user.ts
  6. 2
      src/permissions.ts
  7. 43
      src/router/module/constRouter/index.ts
  8. 24
      src/utils/requset.ts
  9. 26
      src/views/home/index.vue
  10. 67
      src/views/login/index.vue
  11. 280
      src/views/login/registered.vue
  12. 3
      src/views/news/components/newsDetail.vue
  13. 164
      src/views/news/components/newsList.vue
  14. 160
      src/views/news/index.vue
  15. 14
      src/views/raceInfo/index.vue
  16. 165
      src/views/raceList/index.vue
  17. 171
      src/views/userInfo/components/awardeList.vue
  18. 46
      src/views/userInfo/index.vue

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<title>高赛通</title>
</head>
<body>
<div id="app"></div>

@ -1,6 +1,17 @@
<template>
<div class="footer">
<h1>FOOTER</h1>
<div class="footer-nav">
<div class="item">关于我们</div>
<div class="item">联系我们</div>
<div class="item">服务协议</div>
</div>
<div class="copyright">
源码自然版权所有@2023 湘豫CP备 19005950-1
</div>
<div class="report">
违法和不良信息举报 举报电话0xxx-8xxxxxxx 举报邮箱xxxxxxxxx@qq.com
</div>
</div>
</template>
@ -18,8 +29,32 @@ import {} from 'vue'
background: url('../../assets//images/footer.png') no-repeat;
background-size: cover;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #000;
// justify-content: center;
color: #333333;
.footer-nav {
display: flex;
margin-top: 120px;
.item {
width: 180px;
text-align: center;
font-size: 18px;
cursor: pointer;
}
.item:nth-child(2) {
border-left: 1px solid #333333;
border-right: 1px solid #333333;
}
.item:hover {
color: #0bd7c6;
}
}
.copyright{
margin-top: 80px;
}
.report{
margin-top: .1042rem;
}
}
</style>

@ -23,7 +23,7 @@
</div>
</div>
<div class="right" v-if="!useUserStore.token">
<div class="registered gradient">注册</div>
<div class="registered gradient" @click="$router.push('/login')">注册</div>
<div class="login" @click="$router.push('/login')">登录</div>
</div>
<div class="right" v-else>

@ -1,53 +1,75 @@
import request from '@/utils/requset'
// 获取年度比赛项目列表
export const getRaceProjectList = (params:any) => {
return request({
url:'/AnnualCompPoint/annualCompPoint/listStudent',
params
})
export const getRaceProjectList = (params: any) => {
return request({
url: '/AnnualCompPoint/annualCompPoint/listStudent',
params,
})
}
// 获取年度比赛列表
export const getYearRaceList = (params:any) => {
return request({
url:'/annualcomp/annualComp/findndbswlj',
params
})
export const getYearRaceList = (params: any) => {
return request({
url: '/annualcomp/annualComp/findndbswlj',
params,
})
}
// 获取比赛列表
export const getRaceList = (params:any) => {
return request({
url:'/comp/comp/complistnolj',
params
})
export const getRaceList = (params: any) => {
return request({
url: '/comp/comp/complistnolj',
params,
})
}
// 获取比赛详细信息
export const getRaceInfo = (params:any) => {
return request({
url:'/comp/comp/complistnoxq',
params
})
export const getRaceInfo = (params: any) => {
return request({
url: '/comp/comp/complistnoxq',
params,
})
}
// 获取院系列表
export const getFaculties = (params:any) => {
return request({
url:'/sys/sysDepart/queryDepartStuTreeSync',
params
})
export const getFaculties = (params: any) => {
return request({
url: '/sys/sysDepart/queryDepartStuTreeSync',
params,
})
}
// 上传文件
export const uploadFile = (data:any) => {
return request({
url:'/sys/common/upload',
method:'POST',
data
})
export const uploadFile = (data: any) => {
return request({
url: '/sys/common/upload',
method: 'POST',
data,
})
}
// 修改用户信息
export const editUserInfoApi = (data:any) => {
return request({
url:'/sys/user/login/setting/userEdit',
method:'POST',
data
})
export const editUserInfoApi = (data: any) => {
return request({
url: '/sys/user/login/setting/userEdit',
method: 'POST',
data,
})
}
// 获取奖项
export const getAwardslist = (params: any) => {
return request({
url: '/awardpersion/awardPersion/list',
params,
})
}
// 上传证书
export const uploadFileZs = (data: any) => {
return request({
url: '/sys/common/uploadzs',
method: 'POST',
data,
})
}
export const saveSz = (data: any) => {
return request({
url: 'awardpersion/awardPersion/sczs',
method: 'POST',
data,
})
}

@ -22,4 +22,12 @@ export const logOut = () => {
return request({
url:'/sys/logout'
})
}
// 注册
export const sturegister = (data:any) => {
return request({
url:'/sys/user/sturegister',
method:"POST",
data
})
}

@ -13,7 +13,7 @@ const asyncRouter = (path: string) => {
}
router.beforeEach(async (to, form, next) => {
const useuserStore = userStore()
document.title = to.meta.title ? '高赛通-' + to.meta.title : '高赛通'
if (useuserStore.token) {
if (to.path === '/login') {
next({ path: '/' })

@ -49,6 +49,16 @@ export const constRouter: any = {
// hidden: false,
// },
// },
{
path: '/raceList',
name: 'RaceList',
component: () => import('@/views/raceList/index.vue'),
meta: {
icon: '',
title: '竞赛列表',
hidden: false,
},
},
{
path: '/competition',
name: 'Competition',
@ -88,29 +98,16 @@ export const constRouter: any = {
title: '竞赛新闻',
hidden: false,
},
children: [
{
path: '/newsList',
name: 'newsList',
component: () => import('@/views/news/components/newsList.vue'), // 新闻列表组件
meta: {
icon: '',
title: '新闻列表',
hidden: false,
},
},
{
// path: '/newsDetail',
path: 'detail/:id',
name: 'newsDetail',
component: () => import('@/views/news/components/newsDetail.vue'),
meta: {
icon: '',
title: '新闻内容详情',
hidden: true,
}
}
],
},
{
path: 'detail/:id',
name: 'newsDetail',
component: () => import('@/views/news/components/newsDetail.vue'),
meta: {
icon: '',
title: '新闻内容详情',
hidden: true,
}
},
{
path: '/user-info',

@ -5,23 +5,29 @@ import pinia from '@/store'
import userStore from '@/store/module/user'
// 创建axios实例
const server = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout:30000,
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 30000,
})
// 创建请求拦截器
server.interceptors.request.use((config) => {
const useuserStore = userStore(pinia)
const useuserStore = userStore(pinia)
config.headers.Authorization = useuserStore.token
config.headers['x-access-token'] = useuserStore.token
return config
config.headers.Authorization = useuserStore.token
config.headers['x-access-token'] = useuserStore.token
return config
})
// 创建相应拦截器
server.interceptors.response.use((response) => {
return response.data
const useuserStore = userStore(pinia)
if (response.data.code === 401) {
useuserStore.logout()
return
}
return response.data
})
// 暴露axios实例
export default server
export default server

@ -25,22 +25,23 @@
</div> -->
</div>
</div>
<div class="more" @click="router.push('/raceList')">更多</div>
</div>
<!-- 新闻列表 -->
<div class="news-list">
<div class="news-title">
<div class="top">竞赛导航</div>
<div class="top">新闻资讯</div>
<div class="bottom">30+项目登陆后报名</div>
</div>
<div class="newa-panel">
<div class="tab">
<div
:class="active === i ? 'item active gradient' : 'item'"
v-for="i in 5"
:key="i"
@click="active = i"
:class="active === index ? 'item active gradient' : 'item'"
v-for="(item,index) in News"
:key="index"
@click="active = index"
>
全部
{{ item }}
</div>
</div>
<div class="newa-main">
@ -75,6 +76,8 @@ import { ElLoading } from 'element-plus'
const router = useRouter()
const reacProjectList = ref<any>([])
const isLoading = ref(false)
const News =ref<any>(['全部','通知公告','赛事资讯','活动速递','政策文件'])
const getRaceProjectListEvent = async () => {
let page = {
column: 'createTime',
@ -96,7 +99,7 @@ const getRaceProjectListEvent = async () => {
loading.close()
}
getRaceProjectListEvent()
const active = ref(1)
const active = ref(0)
const setImageUrl = (url: string) => {
return import.meta.env.VITE_APP_BASE_API + url
}
@ -168,6 +171,7 @@ const toDetail = (id: number) => {
}
}
.race-list {
position: relative;
width: 100%;
display: grid;
grid-template-columns: repeat(4, 1fr);
@ -216,6 +220,14 @@ const toDetail = (id: number) => {
.item:nth-child(n) {
margin-top: 20px;
}
.more{
position: absolute;
right: 20px;
top: -20px;
color: #0bd7c6;
cursor: pointer;
font-size: 14px;
}
}
.news-list {
margin-top: 170px;

@ -1,20 +1,24 @@
<template>
<div class="login-content">
<div class="login-form">
<div class="login-form" v-if="status">
<div class="login-title">登录</div>
<div class="form">
<el-form :model="form" label-width="80">
<el-form-item label="账号">
<el-input v-model="form.account" style="height: .2344rem" />
<el-input v-model="form.account" style="height: 0.2344rem" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" style="height: .2344rem" />
<el-input
v-model="form.password"
style="height: 0.2344rem"
type="password"
/>
</el-form-item>
<el-form-item label="验证码">
<div class="captcha">
<el-input
v-model="form.captcha"
style="height: .2344rem"
style="height: 0.2344rem"
maxlength="4"
/>
<div class="code" @click="getcodeinfo">
@ -23,9 +27,13 @@
</div>
</el-form-item>
</el-form>
<div class="submit gradient" @click.enter="submit">登录</div>
<div class="submit gradient" @click="submit">
登录
</div>
</div>
<div class="registered">还没账号<span @click="registered">立即注册</span></div>
</div>
<RegisTered v-else @backLogin="backLoginEvent"/>
</div>
</template>
@ -35,7 +43,7 @@ import { getCode } from '@/api/user'
import userStore from '@/store/module/user'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import RegisTered from './registered.vue'
const useUserStore = userStore()
const form = ref({
account: '',
@ -52,7 +60,13 @@ getcodeinfo()
const Router = useRouter()
const submit = async () => {
console.log(111, useUserStore)
if (!form.value.account) {
return ElMessage('账号不能为空')
} else if (!form.value.password) {
return ElMessage('密码不能为空')
} else if (!form.value.captcha) {
return ElMessage('验证码不能为空')
}
let data = {
captcha: form.value.captcha,
checkKey: 1629428467008,
@ -67,10 +81,31 @@ const submit = async () => {
} else if (res === 1) {
ElMessage('账号或密码错误')
getcodeinfo()
}else{
} else {
Router.push('/')
}
}
onMounted(() => {
window.addEventListener('keydown', keyDown)
})
const keyDown = (e: any) => {
//
if (e.keyCode == 13) {
//
submit()
}
}
const status = ref(true)
const registered = () => {
console.log(111);
status.value = false
}
const backLoginEvent = () => {
status.value = true
}
</script>
<style lang="scss" scoped>
@ -102,8 +137,8 @@ const submit = async () => {
height: 100%;
position: relative;
.code {
width: 100%;
height: 100%;
width: 100%;
height: 100%;
position: absolute;
top: 0;
right: 0;
@ -112,7 +147,7 @@ const submit = async () => {
// background-color: pink;
display: flex;
align-items: center;
img{
img {
width: 100%;
height: 100%;
}
@ -132,6 +167,16 @@ const submit = async () => {
}
}
}
.registered{
margin-top: 25px;
text-align: center;
color: #666666;
font-size: 12px;
span{
color: #0bd7c6;
cursor: pointer;
}
}
}
:deep(.el-form-item) {
display: flex;

@ -0,0 +1,280 @@
<template>
<div class="login-form">
<div class="login-title">注册</div>
<div class="form">
<el-form :model="form" label-width="0">
<el-form-item>
<el-col :span="11">
<el-input
v-model="form.username"
:prefix-icon="User"
placeholder="账号"
style="height: 0.2344rem"
/>
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500"></span>
</el-col>
<el-col :span="11">
<el-input
v-model="form.realname"
:prefix-icon="User"
placeholder="姓名"
style="height: 0.2344rem"
/>
</el-col>
</el-form-item>
<el-form-item>
<el-input
v-model="form.workno"
placeholder="工号/学号"
:prefix-icon="Iphone"
></el-input>
</el-form-item>
<el-form-item>
<!-- <el-cascader
v-model="form.department"
placeholder="选择院系"
:options="options"
style="width: 100%; height: 0.2344rem"
/> -->
<el-cascader
:props="props"
style="width: 100%; height: 0.2344rem"
v-model="form.department"
/>
</el-form-item>
<el-form-item>
<el-input
placeholder="手机号码"
v-model="form.mobile"
:prefix-icon="Iphone"
></el-input>
</el-form-item>
<el-form-item>
<el-input
placeholder="密码"
v-model="form.password"
:prefix-icon="Lock"
></el-input>
</el-form-item>
<el-form-item>
<el-input
placeholder="确认密码"
v-model="form.confirmPassword"
:prefix-icon="Lock"
></el-input>
</el-form-item>
<el-form-item>
<!-- <el-input
placeholder="验证码"
v-model="form.smscode"
:prefix-icon="Lock"
></el-input> -->
<div class="captcha">
<el-input
v-model="form.smscode"
style="height: 0.2344rem"
maxlength="4"
:prefix-icon="Lock"
/>
<div class="code" @click="getcodeinfo">
<img :src="codeUrl" alt="" srcset="" />
</div>
</div>
</el-form-item>
</el-form>
<div class="btn">
<div @click="$emits('backLogin')">返回</div>
<div class="gradient" @click="ragistered">注册</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
import { User, Iphone, Lock } from '@element-plus/icons-vue'
import { getFaculties } from '@/api/race'
import { ElMessage } from 'element-plus'
import { getCode, sturegister } from '@/api/user'
const $emits = defineEmits(['backLogin'])
const form = reactive<any>({
username: '',
realname: '',
workno: '',
department: '',
mobile: '',
password: '',
confirmPassword: '' /*, policy: false*/,
smscode: '',
})
const KeyValue: any = {
username: '账号',
realname: '姓名',
workno: '学号',
department: '院系',
mobile: '手机号',
password: '密码',
confirmPassword: '确认密码' /*, policy: false*/,
smscode: '验证码',
}
const FacultiesList = ref([])
const getFacultiesList = async (data: any) => {
const res: any = await getFaculties(data)
console.log(res, 'res')
FacultiesList.value = res.result
}
//
const props = {
lazy: true,
checkStrictly: true,
emitPath: false,
async lazyLoad(node: any, resolve: any) {
await getFacultiesList({
primaryKey: 'key',
pid: node.value,
})
const nodes = FacultiesList.value.map((item: any) => ({
value: item.id,
label: item.title,
}))
resolve(nodes)
},
}
const ragistered = async () => {
for (const key in form) {
if (form[key] === '') {
ElMessage.warning(`${KeyValue[key]}不能为空`)
return console.log(KeyValue[key], '不能为空')
} else {
if (key === 'mobile') {
const phoneRegex = /^1[3-9]\d{9}$/
if (!phoneRegex.test(form[key])) {
return ElMessage.warning(`手机号格式不正确`)
}
}
}
}
if (!(form.password === form.confirmPassword)) {
ElMessage.warning(`两次密码不同`)
}
console.log(form)
let data = {
checkKey: 1629428467008,
departmentid:form.department,
password:form.password,
phone:form.mobile,
realname:form.realname,
smscode:form.smscode,
username:form.username,
workno:form.workno
}
const res:any = await sturegister(data)
if(res.code === 200){
ElMessage.success(`注册成功`)
$emits('backLogin')
}else{
ElMessage.warning(res.message)
}
console.log(res)
}
const codeUrl = ref('')
//
const getcodeinfo = async () => {
const res: any = await getCode(1629428467008)
codeUrl.value = res.result
console.log(codeUrl.value)
}
getcodeinfo()
</script>
<style lang="scss" scoped>
.login-form {
width: 640px;
height: 820px;
border-radius: 15px;
background-color: #ffffff1a !important;
padding: 70px 60px;
backdrop-filter: blur(10px);
box-shadow: 0 4px 8px 1px rgba(0, 0, 0, 0.2);
.login-title {
font-size: 32px;
font-weight: 700;
}
.form {
margin-top: 45px;
padding: 0 40px;
.captcha {
width: 100%;
height: 100%;
position: relative;
.code {
width: 100%;
height: 100%;
position: absolute;
top: 0;
right: 0;
width: 105px;
height: 100%;
// background-color: pink;
display: flex;
align-items: center;
img {
width: 100%;
height: 100%;
}
}
}
.submit {
width: 399px;
height: 50px;
text-align: center;
line-height: 50px;
font-size: 20px;
font-weight: 600;
cursor: pointer;
color: #fff;
border-radius: 10px;
margin-top: 35px;
}
}
.btn {
display: flex;
justify-content: space-between;
margin-top: 45px;
div {
width: 210px;
height: 42px;
text-align: center;
line-height: 42px;
font-size: 14px;
cursor: pointer;
border-radius: 10px;
}
div:nth-child(1) {
border: 1px solid #dbdbdb;
color: #3c3c3c;
}
div:nth-child(2) {
color: #fff;
}
}
}
:deep(.el-form-item) {
display: flex;
flex-direction: row !important;
height: 45px;
margin-top: 25px;
.el-input {
height: 100%;
}
input {
height: 100%;
}
}
</style>

@ -24,7 +24,7 @@ const data = ref({});
//id
queryEssayApi(route.params.id).then(res=>{
data.value = res.result[0]
console.log(data.value,'data')
console.log(`当前id为${route.params.id}新闻详细信息`,data.value)
})
//
@ -44,6 +44,7 @@ const completeImageUrl = computed(() => {
overflow-y: scroll;
padding: 0;
display: block;
margin-top: 100px;
}
.container::-webkit-scrollbar {
width: 0;

@ -1,164 +0,0 @@
<template>
<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>
<img class="news-image" :src="newsItem.imageUrl" alt="News Image" v-default-image>
</div>
<el-divider />
</li>
</ul>
</el-tab-pane>
</el-tabs>
</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
}
}
}
//
const fetchNewsList = async (categoryId) => {
try {
const response = await queryEssayListApi(categoryId)
console.log(response.success,'daaaaaaa')
console.log(response.result.records,'ddddddd')
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) => {
router.push({
name: 'newsDetail',
params: { id: newsItem.id.toString() },
})
}
</script>
<style scoped>
.container{
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;
}
.news-image {
width: 100px;
height: 80px;
margin-right: 30px;
}
</style>

@ -1,12 +1,166 @@
<template>
<div class="container">
<router-view/>
<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>
<img class="news-image" :src="newsItem.imageUrl" alt="News Image" v-default-image>
</div>
<el-divider />
</li>
</ul>
</el-tab-pane>
</el-tabs>
</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
}
}
}
//
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) => {
router.push({
name: 'newsDetail',
params: { id: newsItem.id.toString() },
})
}
</script>
<style scoped>
.main{
margin-top: 100px;
}
.container{
margin-top:100px;
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;
}
.news-image {
width: 100px;
height: 80px;
margin-right: 30px;
}
</style>

@ -56,10 +56,10 @@
<div class="top">
<div class="left">
<el-image
src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg"
style="width: 300px"
:src="setImageUrl(raceInfo.compLogo)"
style="width: 1.5625rem"
:preview-src-list="[
'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg',
setImageUrl(raceInfo.compLogo),setImageUrl(raceInfo.compImg),
]"
></el-image>
</div>
@ -106,7 +106,7 @@
</div>
<div class="label">附件:</div>
<div class="file">
<el-tag type="primary">fhsuihfiaosdufasiu.pdf</el-tag>
<el-tag type="primary" @click="doLoadFile(raceInfo.compFile)">{{ raceInfo.compFile }}</el-tag>
</div>
</div>
</div>
@ -174,6 +174,11 @@ getraceInfoEvent()
const goToCompetition = (id:any) => {
Router.push({ path: '/competition', query: { id } })
}
const doLoadFile = (url:any) => {
// console.log( import.meta.env.VITE_APP_BASE_API + "/sys/common/static/" + url)
window.open( import.meta.env.VITE_APP_BASE_API + "/sys/common/static/" + url)
}
</script>
<style lang="scss" scoped>
@ -368,6 +373,7 @@ const goToCompetition = (id:any) => {
}
.file {
margin-top: 25px;
cursor: pointer;
}
}
}

@ -0,0 +1,165 @@
<template>
<!-- 比赛列表 -->
<div class="container-1420" v-if="isLoading">
<div class="nav-title">
<div class="top">竞赛导航</div>
<div class="bottom">30+项目登陆后报名</div>
</div>
<div class="race-list">
<div
class="item"
v-for="item in splietArr"
:key="item.id"
@click="toDetail(item.id)"
>
<div class="image">
<img :src="setImageUrl(item.compImg)" alt="" v-default-image />
</div>
<div class="reac-info">
<div class="reac-title">{{ item.compName }}</div>
<div class="reac-project"><div v-html="item.compName"></div></div>
<!-- <div class="time">
报名时间:{{ item.starttime }}-{{ item.endtime }}
</div> -->
</div>
</div>
</div>
<div class="page">
<el-pagination background layout="prev, pager, next" :total="total" @change="handleSizeChange"/>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { getRaceList } from '@/api/race'
import { useRouter } from 'vue-router'
import { ElLoading } from 'element-plus'
const router = useRouter()
const reacProjectList = ref<any>([])
const splietArr = ref<any>([])
const isLoading = ref(false)
const total = ref<any>(0)
const getRaceProjectListEvent = async () => {
let page = {
column: 'createTime',
order: 'desc',
pageNo: 1,
pageSize: 8,
}
const loading = ElLoading.service({
lock: true,
text: 'Loading',
background: 'rgba(255, 255, 255, 0.7)',
})
const res: any = await getRaceList(page)
console.log(res)
reacProjectList.value = res.result
splietArr.value = reacProjectList.value.slice(0, 8)
total.value = res.result.length
console.log(total.value, 'reacProjectList.value ')
isLoading.value = true
loading.close()
}
getRaceProjectListEvent()
const setImageUrl = (url: string) => {
return import.meta.env.VITE_APP_BASE_API + url
}
//
const toDetail = (id: number) => {
router.push({
path: '/race-info',
query: {
id,
},
})
}
//
const handleSizeChange = (e:any) => {
console.log(e);
splietArr.value = reacProjectList.value.slice((e-1) * 8 ,(e-1) * 8 + 8)
}
</script>
<style lang="scss" scoped>
.race-list {
position: relative;
width: 100%;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, 1fr);
// gap: 10px;
margin-top: 20px;
.item {
width: 340px;
height: 360px;
// background-color: pink;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.06);
cursor: pointer;
border-radius: 10px;
transition: all 0.2s;
.image {
width: 100%;
height: 194px;
img {
width: 100%;
height: 100%;
}
}
.reac-info {
padding: 0 8px;
.reac-title {
margin-top: 19px;
color: #c9c9c9;
font-size: 12px;
}
.reac-project {
font-size: 16px;
font-weight: 600;
color: #333333;
margin-top: 10px;
}
.time {
font-size: 14px;
color: #8c8b8b;
margin-top: 40px;
}
}
}
.item:hover {
transform: translateY(-5px);
}
.item:nth-child(n) {
margin-top: 20px;
}
.more {
position: absolute;
right: 20px;
top: -20px;
color: #0bd7c6;
cursor: pointer;
font-size: 14px;
}
}
.nav-title {
margin-top: 100px;
color: #1e2033;
.top {
font-size: 40px;
font-weight: 600;
text-align: center;
}
.bottom {
font-size: 16px;
text-align: center;
margin-top: 10px;
}
}
.page{
display: flex;
justify-content: center;
margin-top: 25px;
}
</style>

@ -0,0 +1,171 @@
<template>
<el-card style="margin-top: 0.1302rem">
<template #header>
<div style="font-size: 16px; font-weight: 600">我的奖项</div>
</template>
<el-table :data="tableData" border style="width: 100%">
<el-table-column
align="center"
prop="annualid_dictText"
label="年度"
width="70"
/>
<el-table-column
align="center"
prop="annalComp_dictText"
label="年度比赛"
/>
<el-table-column
align="center"
prop="annualCompP_dictText"
label="年度比赛项目"
/>
<el-table-column align="center" prop="enrollCode" label="报名编号" />
<el-table-column
align="center"
prop="awardname"
label="奖项名称"
width="90"
/>
<el-table-column align="center" prop="studentcode" label="学生学号" />
<el-table-column
align="center"
prop="studentname"
label="学生姓名"
width="100"
/>
<el-table-column align="center" prop="sczs" label="证书">
<template #default="{ row }">
<el-image
:src="setImageUrl(row.sczs)"
style="width: 0.2604rem; height: 0.2604rem"
:preview-src-list="[setImageUrl(row.sczs)]"
:z-index="100"
></el-image>
<!-- <img :src="setImageUrl(row.sczs)" alt=""> -->
</template>
</el-table-column>
<el-table-column
align="center"
prop="tj_dictText"
label="是否推荐"
width="90"
/>
<el-table-column align="center" label="操作">
<template #default="{ row }">
<el-button
link
type="primary"
size="small"
@click="uploadZs(row.id)"
>
上传证书
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog
v-model="dialogVisible"
v-if="dialogVisible"
title="上传证书"
width="25%"
:before-close="handleClose"
>
<el-form label-width="80" style="padding-right: 30px">
<el-form-item label="证书">
<el-upload
v-model:file-list="fileList"
action="#"
list-type="picture-card"
:auto-upload="false"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submit">确认</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
import { getAwardslist, uploadFileZs,saveSz } from '@/api/race'
const dialogVisible = ref(false)
const tableData = ref<any>([])
const getAwardListApi = async () => {
const data = {
column: 'createTime',
order: 'desc',
pageNo: 1,
pageSize: 10,
}
const res: any = await getAwardslist(data)
tableData.value = res.result.records
console.log(tableData.value, 'tableData.value')
}
getAwardListApi()
const setImageUrl = (url: string) => {
return import.meta.env.VITE_APP_BASE_API + '/sys/common/staticzs/' + url
}
const fileList = ref<any>([])
const zsUrl = ref('')
const zsId = ref(0)
const uploadZs = (id:any) => {
zsId.value = id
dialogVisible.value = true
}
const uploadFileEvent = async () => {
const fromData = new FormData()
fromData.append('file', fileList.value[0].raw)
const res: any = await uploadFileZs(fromData)
zsUrl.value = res.message
}
const submit = async () => {
await uploadFileEvent()
let data = {
id:zsId.value,
sczs:zsUrl.value
}
await saveSz(data)
getAwardListApi()
dialogVisible.value = false
fileList.value = []
}
const handleClose = () => {
dialogVisible.value = false
fileList.value = []
}
watch(
() => fileList.value,
(newVal, oldVal) => {
console.log(newVal, oldVal)
if (newVal.length === 1) {
;(document.querySelector('.el-upload') as HTMLElement).style.display =
'none'
} else {
setTimeout(() => {
;(document.querySelector('.el-upload') as HTMLElement).style.display =
'flex'
}, 0)
}
},
)
</script>
<style lang="scss" scoped>
:deep(.el-image-viewer__close) {
top: 160px;
}
:deep(.el-table__cell) {
position: static !important; // el-image el-table
}
</style>

@ -80,9 +80,9 @@
<!-- <img style="width: 75px; height:75px ;" src="../../assets/images/item.png" alt="" srcset=""> -->
<el-image
style="width: 100px; height: 100px"
:src="setImageUrl(userInfo.avatar)"
:src="setImageUrl(useUserStore.userInfo.avatar)"
:preview-src-list="[
setImageUrl(userInfo.avatar),
setImageUrl(useUserStore.userInfo.avatar),
]"
/>
</div>
@ -90,32 +90,35 @@
<div class="info-box">
<div class="label">姓名</div>
<div class="text">{{ userInfo.realname }}</div>
<div class="text">{{ useUserStore.userInfo.realname}}</div>
</div>
<div class="info-box">
<div class="label">姓别</div>
<div class="text">{{ userInfo.sex === 1 ? '男' : '女' }}</div>
<div class="text">{{ useUserStore.userInfo.sex === 1 ? '男' : '女' }}</div>
</div>
<div class="info-box">
<div class="label">生日</div>
<div class="text">{{ useUserStore.userInfo.birthday }}</div>
</div>
<div class="info-box">
<div class="label">学号</div>
<div class="text">{{ userInfo.workNo }}</div>
<div class="text">{{ useUserStore.userInfo.workNo }}</div>
</div>
<div class="info-box">
<div class="label">手机号</div>
<div class="text">{{ userInfo.phone }}</div>
<div class="text">{{ useUserStore.userInfo.phone }}</div>
</div>
<div class="info-box">
<!-- <div class="info-box">
<div class="label">院系</div>
<div class="text">国际教育学院</div>
</div>
</div> -->
<div class="info-box">
<div class="label">邮箱</div>
<div class="text">{{ userInfo.email }}</div>
<div class="text">{{ useUserStore.userInfo.email }}</div>
</div>
</div>
</div>
@ -141,6 +144,7 @@
</div>
</div>
</el-card>
<awardeList />
</div>
<el-dialog
v-model="dialogVisible"
@ -163,13 +167,13 @@
<el-form-item label="姓名">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="部门">
<!-- <el-form-item label="部门">
<el-cascader
:props="props"
style="width: 100%"
v-model="form.facultiesId"
/>
</el-form-item>
</el-form-item> -->
<el-form-item label="生日">
<el-date-picker
v-model="form.birthday"
@ -205,7 +209,7 @@ import { nextTick, onMounted, reactive, ref, toRefs, watch } from 'vue'
import { useRouter } from 'vue-router'
import userStore from '@/store/module/user'
import { getFaculties, uploadFile, editUserInfoApi } from '@/api/race'
import { id } from 'element-plus/es/locale/index.mjs'
import awardeList from './components/awardeList.vue'
const useUserStore = userStore()
const userInfo = ref<any>({})
console.log(useUserStore.userInfo, 'useUserStore')
@ -214,17 +218,17 @@ const Router = useRouter()
const dialogVisible = ref(false)
//
const editUserInfo = () => {
form.name = userInfo.value.realname
form.birthday = userInfo.value.birthday
form.sex = userInfo.value.sex
form.email = userInfo.value.email
// form.facultiesId = userInfo.value.facultiesId
form.phone = userInfo.value.phone
form.name = useUserStore.userInfo.realname
form.birthday = useUserStore.userInfo.birthday
form.sex = useUserStore.userInfo.sex
form.email = useUserStore.userInfo.email
// form.facultiesId = useUserStore.userInfo.facultiesId
form.phone = useUserStore.userInfo.phone
dialogVisible.value = true
nextTick(() => {
fileList.value = [
{
url: setImageUrl(userInfo.value.avatar),
url: setImageUrl(useUserStore.userInfo.avatar),
},
]
})
@ -273,6 +277,8 @@ const submit = async () => {
}
await editUserInfoApi(data)
useUserStore.getUserInfo()
userInfo.value = useUserStore.userInfo
dialogVisible.value = false
}
onMounted(() => {})

Loading…
Cancel
Save