代码提交

This commit is contained in:
jiangzhe 2024-06-24 15:20:12 +08:00
parent eed984f0fd
commit 6df1a23984
25 changed files with 2455 additions and 1923 deletions

View File

@ -10,14 +10,19 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.8",
"@vue-office/pdf": "^2.0.2",
"@vueuse/core": "^9.12.0", "@vueuse/core": "^9.12.0",
"axios": "^1.2.6", "axios": "^1.2.6",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"element-plus": "^2.2.28", "element-plus": "^2.6.1",
"pinia": "^2.0.28", "file-saver": "^2.0.5",
"pinia-plugin-persistedstate": "^3.0.2", "pinia": "^2.1.7",
"vue": "^3.2.45", "pinia-plugin-persistedstate": "^3.2.1",
"vue-router": "^4.1.6" "vue": "^3.4.21",
"vue-demi": "^0.14.8",
"vue-router": "^4.3.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.0.0",

File diff suppressed because it is too large Load Diff

View File

@ -13,4 +13,48 @@ export const getResourceList = (params = {}) => {
url: '/portal/resource/list', url: '/portal/resource/list',
params params
}) })
}
export const getTreeList = (params = {}) => {
return httpInstance({
url: '/portal/resource/catalog/tree',
params
})
}
export const getResourceInfo = (id) => {
return httpInstance({
url: `/portal/resource/${id}`,
})
}
export function resourcePreview(id) {
return httpInstance({
url: `/portal/resource/preview/${id}`,
method: 'post',
responseType: 'blob'
});
}
export function resourcePreviewTxt(id) {
return httpInstance({
url: `/portal/resource/preview/${id}`,
method: 'post',
responseType: 'blob',
transformResponse: [
async function (data) {
return await transformData(data)
}
]
});
}
const transformData = (data) => {
return new Promise((resolve) => {
let reader = new FileReader()
reader.readAsText(data)
reader.onload = function () {
resolve(reader.result)
}
})
} }

View File

@ -19,6 +19,12 @@ export const getTrendAPI = (params = {}) => {
}) })
} }
export const getTrendInfoAPI = (trendId) => {
return httpInstance({
url: `/portal/trend/${trendId}`
})
}
/** /**
*查询学校名师列表 *查询学校名师列表
*/ */

View File

@ -21,4 +21,41 @@ export const getTextbookList = (params = {}) => {
url: '/portal/textbook/list', url: '/portal/textbook/list',
params params
}) })
}
export const getTextbookInfoAPI = (id) => {
return httpInstance({
url: `/portal/textbook/${id}`
})
}
export function textbookPreview(id) {
return httpInstance({
url: `/portal/textbook/preview/${id}`,
method: 'post',
responseType: 'blob'
});
}
export function textbookPreviewTxt(id) {
return httpInstance({
url: `/portal/textbook/preview/${id}`,
method: 'post',
responseType: 'blob',
transformResponse: [
async function (data) {
return await transformData(data)
}
]
});
}
const transformData = (data) => {
return new Promise((resolve) => {
let reader = new FileReader()
reader.readAsText(data)
reader.onload = function () {
resolve(reader.result)
}
})
} }

BIN
src/assets/images/trend.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

View File

@ -6,8 +6,8 @@
<span>{{ label }}</span> <span>{{ label }}</span>
<!-- 排序图标 --> <!-- 排序图标 -->
<div class="isIconList"> <div class="isIconList">
<img :src="getSortIcon(key, 'asc')" class="up" /> <img :src="getSortIcon(key, 'ascending')" class="up" />
<img :src="getSortIcon(key, 'desc')" /> <img :src="getSortIcon(key, 'descending')" />
</div> </div>
</div> </div>
</div> </div>
@ -36,11 +36,11 @@ const getSortIcon = (key, order) => {
const handleSortChange = (keyName) => { const handleSortChange = (keyName) => {
// //
const sortMap = new Map([ const sortMap = new Map([
[1, 'desc'], [1, 'descending'],
[2, 'asc'], [2, 'ascending'],
[3, ''], [3, ''],
['desc', 1], ['descending', 1],
['asc', 2], ['ascending', 2],
['', 3], ['', 3],
[undefined, 3] [undefined, 3]
]); ]);
@ -75,6 +75,7 @@ const handleSortChange = (keyName) => {
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
margin-left: 6px; margin-left: 6px;
img { img {
width: 10px; width: 10px;
height: auto; height: auto;
@ -85,13 +86,13 @@ const handleSortChange = (keyName) => {
} }
} }
img + img { img+img {
margin-top: 2px; margin-top: 2px;
} }
} }
} }
.jsItem + .jsItem { .jsItem+.jsItem {
margin-left: 60px; margin-left: 60px;
} }
} }

View File

@ -0,0 +1,104 @@
<template>
<vue-office-docx v-loading="fileLoading" element-loading-text="加载中..."
v-if="fileSuffix == '.doc' || fileSuffix == '.docx'" :src="file" />
<vue-office-excel v-loading="fileLoading" element-loading-text="加载中..." :options="options"
style="height: 100vh;width: 100vh;" v-if="fileSuffix == '.xls' || fileSuffix == '.xlsx'" :src="file" />
<vue-office-pdf v-loading="fileLoading" element-loading-text="加载中..." v-if="fileSuffix == '.pdf'" :src="file" />
<div v-loading="fileLoading" element-loading-text="加载中..." v-if="fileSuffix == '.txt'" style="white-space: pre-wrap;">
{{ txt }}
</div>
<img v-if="imgSuffixArr.includes(fileSuffix)" :src="imgUrl" alt="" v-loading="fileLoading"
element-loading-text="加载中..." style="width: 100%; text-align: center;">
</template>
<script setup>
import { ref, watchEffect } from 'vue'
import { textbookPreview, textbookPreviewTxt } from '@/apis/textbook'
import { resourcePreview, resourcePreviewTxt } from '@/apis/catalogResource'
//VueOfficeDocx
import VueOfficeDocx from '@vue-office/docx'
//
import '@vue-office/docx/lib/index.css'
//VueOfficeExcel
import VueOfficeExcel from '@vue-office/excel'
//
import '@vue-office/excel/lib/index.css'
//VueOfficePdf
import VueOfficePdf from '@vue-office/pdf'
const props = defineProps({
id: Number,
type: String,
fileSuffix: String
})
const options = ref({
xls: false, //xlsxfalsexlstrue
minColLength: 0, // excelxlsx0.
minRowLength: 0, // excelxlsx0.
widthOffset: 10, // Npx
heightOffset: 10, // Npx
beforeTransformData: (workbookData) => { return workbookData }, //exceljsexcelexcelvalue
transformData: (workbookData) => { return workbookData }, //exceltransformDatatext
})
const fileSuffixArr = ['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf']
const imgSuffixArr = ['.jpg', '.png', '.jpeg', '.gif', '.bmp']
const file = ref('')
const fileLoading = ref(false)
const txt = ref('')
const imgUrl = ref('')
const previewFile = async () => {
fileLoading.value = true
if (props.fileSuffix == '.txt') {
let fileRes
if (props.type == 'textbook') {
fileRes = await textbookPreviewTxt(props.id)
}
if (props.type == 'resource') {
fileRes = await resourcePreviewTxt(props.id)
}
txt.value = fileRes
} else if (imgSuffixArr.includes(props.fileSuffix)) {
let fileRes
if (props.type == 'textbook') {
fileRes = await textbookPreview(props.id)
}
if (props.type == 'resource') {
fileRes = await resourcePreview(props.id)
}
let blob = new Blob([fileRes], { type: `image/${row.fileSuffix.substring(1)}` })
imgUrl.value = URL.createObjectURL(blob)
} else if (fileSuffixArr.includes(props.fileSuffix)) {
let fileRes
if (props.type == 'textbook') {
fileRes = await textbookPreview(props.id)
}
if (props.type == 'resource') {
fileRes = await resourcePreview(props.id)
}
fileRes.arrayBuffer().then(res => file.value = res)
}
fileLoading.value = false
}
watchEffect(() => {
previewFile()
})
</script>
<style lang="scss" scoped>
:deep(.docx-wrapper) {
background-color: #E2F1F8;
padding: 0;
}
</style>

View File

@ -22,7 +22,3 @@ app.use(router)
app.use(lazyPlugin) app.use(lazyPlugin)
app.use(componentPlugin) app.use(componentPlugin)
app.mount('#app') app.mount('#app')

View File

@ -1,7 +1,7 @@
// createRouter创建router实例对象 // createRouter创建router实例对象
// createWebHistory创建history模式的路由 // createWebHistory创建history模式的路由
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHashHistory } from 'vue-router'
import Login from '@/views/Login/index.vue' import Login from '@/views/Login/index.vue'
import Layout from '@/views/Layout/index.vue' import Layout from '@/views/Layout/index.vue'
import Home from '@/views/Home/index.vue' import Home from '@/views/Home/index.vue'
@ -17,7 +17,7 @@ import UserInfo from '@/views/Member/components/UserInfo.vue'
import UserOrder from '@/views/Member/components/UserOrder.vue' import UserOrder from '@/views/Member/components/UserOrder.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHashHistory(import.meta.env.BASE_URL),
// path和component对应关系的位置 // path和component对应关系的位置
routes: [ routes: [
{ {
@ -32,6 +32,10 @@ const router = createRouter({
path: 'news', path: 'news',
component: () => import('@/views/News/index.vue') component: () => import('@/views/News/index.vue')
}, },
{
path: 'news/:id',
component: () => import('@/views/NewsDetail/index.vue')
},
{ {
path: 'newDetail/:id', path: 'newDetail/:id',
component: () => import('@/views/NewsDetail/index.vue') component: () => import('@/views/NewsDetail/index.vue')
@ -40,14 +44,26 @@ const router = createRouter({
path: 'textBook', path: 'textBook',
component: () => import('@/views/TextBook/index.vue') component: () => import('@/views/TextBook/index.vue')
}, },
{
path: 'textBookDetail',
component: () => import('@/views/TextBookDetail/index.vue')
},
{ {
path: 'subject', path: 'subject',
component: () => import('@/views/CatalogResource/index.vue') component: () => import('@/views/CatalogResource/index.vue')
}, },
{ {
path: 'subSubject/:id', path: 'subSubject',
component: () => import('@/views/SubCatalogResource/index.vue') component: () => import('@/views/SubCatalogResource/index.vue')
}, },
{
path: 'subjectDetail',
component: () => import('@/views/CatalogResourceDetail/index.vue')
},
{
path: 'teacher',
component: () => import('@/views/Teacher/index.vue')
},
{ {
path: 'category/:id', path: 'category/:id',
component: Category component: Category

View File

@ -50,7 +50,6 @@ img {
max-width: 100%; max-width: 100%;
max-height: 100%; max-height: 100%;
vertical-align: middle; vertical-align: middle;
background: #ebebeb url('@/assets/images/200.png') no-repeat center / contain;
} }
ul { ul {
list-style: none; list-style: none;

View File

@ -3,7 +3,7 @@ import axios from 'axios'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { useUserStore } from '@/stores/userStore' import { useUserStore } from '@/stores/userStore'
const httpInstance = axios.create({ const httpInstance = axios.create({
baseURL: '/api', baseURL: '/api-school',
timeout: 50000 timeout: 50000
}) })
@ -32,4 +32,4 @@ httpInstance.interceptors.response.use(res => res.data, e => {
}) })
export default httpInstance export default httpInstance

View File

@ -1,3 +1,6 @@
import request from '@/utils/http'
import FileSaver from 'file-saver'
// 日期格式化 // 日期格式化
export function parseTime(time, pattern) { export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) { if (arguments.length === 0 || !time) {
@ -41,4 +44,60 @@ export function parseTime(time, pattern) {
} }
return value || 0; return value || 0;
}); });
} }
let downloadLoadingInstance
export function download(url, params, fileName) {
downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
return request.post(url, params, {
transformRequest: [
(params) => {
return tansParams(params);
}
],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob'
}).then(async (resp) => {
const isBlod = blobValidate(resp);
if (isBlod) {
const blob = new Blob([resp]);
FileSaver.saveAs(blob, fileName);
} else {
const resText = await resp.data.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r);
ElMessage.error('下载文件出现错误,请联系管理员!');
downloadLoadingInstance.close();
});
}
export const tansParams = (params) => {
let result = '';
for (const propName of Object.keys(params)) {
const value = params[propName];
const part = encodeURIComponent(propName) + '=';
if (value !== null && value !== '' && typeof value !== 'undefined') {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
const params = propName + '[' + key + ']';
const subPart = encodeURIComponent(params) + '=';
result += subPart + encodeURIComponent(value[key]) + '&';
}
}
} else {
result += part + encodeURIComponent(value) + '&';
}
}
}
return result;
};
export const blobValidate = (data) => {
return data.type !== 'application/json';
};

View File

@ -24,24 +24,27 @@
</div> </div>
<div class="subject-content"> <div class="subject-content">
<div class="subject-card" v-for="item in resourceList"> <div class="subject-card" v-for="item in resourceList" @click="goTo(item)">
<RouterLink :to="`subSubject/${item.catalogId}`"> <el-card>
<el-card> <img :src="item.coverUrl" />
<img :src="item.coverUrl" /> <p class="subject-title">{{ item.catalogName }}</p>
</el-card> </el-card>
<div class="subject-top">1790个资源</div> <div class="subject-top">{{ item.resourceNum }}个资源</div>
</RouterLink>
</div> </div>
</div> </div>
<el-pagination class="book-page" background layout="prev, pager, next, sizes,jumper" :total="1000" /> <el-pagination class="book-page" background layout="prev, pager, next, sizes,jumper" :total="total"
@current-change="handleCurrentChange" @size-change="handleSizeChange" />
</el-card> </el-card>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { getResourceCatalogList } from '@/apis/catalogResource' import { getResourceCatalogList } from '@/apis/catalogResource'
const router = useRouter()
const queryParams = ref({ const queryParams = ref({
pageNum: 1, pageNum: 1,
pageSize: 12 pageSize: 12
@ -54,10 +57,23 @@ const getResourceListData = async () => {
total.value = res.total total.value = res.total
} }
const goTo = (item) => {
router.push({ path: `subSubject`, query: { catalogId: item.catalogId, catalogName: item.catalogName, createTime: item.createTime, resourceNum: item.resourceNum } })
}
onMounted(() => { onMounted(() => {
getResourceListData() getResourceListData()
}) })
const handleCurrentChange = (val) => {
queryParams.value.pageNum = val
getResourceListData()
}
const handleSizeChange = (val) => {
queryParams.value.pageSize = val
getResourceListData()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -108,6 +124,18 @@ onMounted(() => {
.subject-card { .subject-card {
position: relative; position: relative;
img {
border-radius: 10px;
width: 100%;
height: 240px;
}
.subject-title {
text-align: center;
margin-top: 5px;
font-size: 16px;
}
.subject-top { .subject-top {
position: absolute; position: absolute;
top: 0; top: 0;

View File

@ -0,0 +1,107 @@
<template>
<div class="container">
<div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: 'subject' }">专题资源</el-breadcrumb-item>
<el-breadcrumb-item>{{ info.fileName }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="textbook-card">
<div class="textbook-top">
<div class="left">
<h1>{{ info.fileName }}</h1>
<p class="textbook-info">
<span>上传者{{ info.createBy }}</span>
<span>上传时间{{ info.createTime }}</span>
</p>
</div>
<div class="right">
<el-button :icon="Download" type="primary" @click="downloadFile">下载</el-button>
</div>
</div>
<div class="textbook-content">
<PreviewFile :id="id" type="resource" :fileSuffix="fileSuffix"></PreviewFile>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { getResourceInfo } from '@/apis/catalogResource'
import { Download } from '@element-plus/icons-vue'
import PreviewFile from '@/components/PreviewFile/index.vue'
import { download } from '@/utils/utils'
const route = useRoute()
const id = route.query.id
const fileSuffix = ref('')
console.log(id);
const info = ref({})
const getResourceInfoData = async () => {
const res = await getResourceInfo(id)
info.value = res.data
fileSuffix.value = res.data.fileSuffix
}
const downloadFile = () => {
download(`/portal/resource/preview/${id}`, {}, info.value.fileName)
}
onMounted(() => {
getResourceInfoData()
})
</script>
<style lang="scss" scoped>
.container {
.bread-container {
padding: 25px 0;
:deep(.el-breadcrumb__inner) {
color: #fff;
font-size: 16px;
}
:deep(.el-breadcrumb__separator) {
color: #fff;
}
}
.textbook-card {
margin-top: 20px;
padding: 20px;
min-height: 600px;
background-color: #E2F1F8;
border-radius: 10px;
.textbook-top {
display: flex;
justify-content: space-between;
align-items: center;
.textbook-info {
line-height: 60px;
color: #A9A19B;
span:nth-child(1) {
margin-right: 20px;
}
}
}
.textbook-content {
margin: 0 50px;
}
}
}
</style>

View File

@ -4,6 +4,11 @@ import { onMounted, ref } from 'vue'
const bannerList = ref([]) const bannerList = ref([])
const goTarget = (url) => {
window.open(url, '__blank');
}
const getBanner = async () => { const getBanner = async () => {
const res = await getBannerAPI({ const res = await getBannerAPI({
pageNum: 1, pageNum: 1,
@ -12,6 +17,11 @@ const getBanner = async () => {
bannerList.value = res.rows bannerList.value = res.rows
} }
const handleChange = (val) => {
console.log(val.url);
goTarget(val.url)
}
onMounted(() => getBanner()) onMounted(() => getBanner())
</script> </script>
@ -21,7 +31,7 @@ onMounted(() => getBanner())
<div class="home-banner"> <div class="home-banner">
<el-carousel height="500px" arrow="always"> <el-carousel height="500px" arrow="always">
<el-carousel-item v-for="item in bannerList" :key="item.bannerId"> <el-carousel-item v-for="item in bannerList" :key="item.bannerId">
<img :src="item.coverUrl" :alt="item.title"> <img :src="item.coverUrl" :alt="item.title" @click="handleChange(item)">
</el-carousel-item> </el-carousel-item>
</el-carousel> </el-carousel>
</div> </div>

View File

@ -19,8 +19,10 @@
<ul class="card-left-list"> <ul class="card-left-list">
<li v-for="item in trendList"> <li v-for="item in trendList">
<span>{{ item.title }}</span> <RouterLink :to="`news/${item.trendId}`">
<span>{{ parseTime(item.createTime, '{y}-{m}-{d}') }}</span> <span>{{ item.title }}</span>
<span>{{ parseTime(item.createTime, '{y}-{m}-{d}') }}</span>
</RouterLink>
</li> </li>
</ul> </ul>
</el-card> </el-card>
@ -33,7 +35,9 @@
<div class="card-right-header"> <div class="card-right-header">
<span>数字化教材云平台</span> <span>数字化教材云平台</span>
<span class="more">查看更多></span> <span class="more">
<RouterLink to="textBook">查看更多></RouterLink>
</span>
</div> </div>
</template> </template>
@ -60,7 +64,9 @@
<div class="title">专题资源</div> <div class="title">专题资源</div>
<div class="card-subject-header"> <div class="card-subject-header">
<span>助力加强理论学习</span> <span>助力加强理论学习</span>
<span class="more">查看更多>></span> <span class="more">
<RouterLink to="subject">查看更多></RouterLink>
</span>
</div> </div>
</template> </template>
<div class="subject-content"> <div class="subject-content">
@ -68,7 +74,7 @@
<img :src="item.coverUrl" alt=""> <img :src="item.coverUrl" alt="">
<template #footer> <template #footer>
<div class="subject-title">{{ item.catalogName }}</div> <div class="subject-title">{{ item.catalogName }}</div>
<div class="subject-date">2024-04-12</div> <div class="subject-date">{{ parseTime(item.createTime, '{y}-{m}-{d}') }}</div>
</template> </template>
</el-card> </el-card>
</div> </div>
@ -81,7 +87,7 @@
<div class="title">校园名师</div> <div class="title">校园名师</div>
<div class="card-teacher-header"> <div class="card-teacher-header">
<span>教育大计老师为本</span> <span>教育大计老师为本</span>
<span class="more">查看更多>></span> <RouterLink to="teacher">查看更多></RouterLink>
</div> </div>
</template> </template>
@ -252,6 +258,8 @@ const gotoInfo = (id) => {
img { img {
border-radius: 5px; border-radius: 5px;
height: 240px;
width: 100%;
} }
.subject-title { .subject-title {
@ -275,13 +283,20 @@ const gotoInfo = (id) => {
} }
.card-teacher-list { .card-teacher-list {
display: flex; display: grid;
justify-content: space-between; grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(1, 1fr);
gap: 10px;
.item { .item {
flex: 0 1 24%;
text-align: center; text-align: center;
img {
border-radius: 10px;
width: 100%;
height: 300px;
}
.teacher-name { .teacher-name {
line-height: 45px; line-height: 45px;
font-size: 18px; font-size: 18px;

View File

@ -22,7 +22,7 @@
<style scoped lang='scss'> <style scoped lang='scss'>
.app_footer { .app_footer {
overflow: hidden; overflow: hidden;
background-color: #f5f5f5; background-color: #fff;
padding-top: 20px; padding-top: 20px;

View File

@ -19,8 +19,14 @@
</div> </div>
</template> </template>
<el-table :data="tableData" class="table" stripe :show-header="false"> <el-table @row-click="handleRowClick" :data="tableData" class="table" stripe :show-header="false">
<el-table-column prop="title" label="title" /> <el-table-column prop="title" label="title">
<template #default="{ row }">
<img src="@/assets/images/trend.png" alt="">
&nbsp;
<span>{{ row.title }}</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="date" width="200" /> <el-table-column prop="createTime" label="date" width="200" />
</el-table> </el-table>
@ -34,9 +40,12 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { Search } from '@element-plus/icons-vue' import { Search } from '@element-plus/icons-vue'
import { getTrendAPI } from '@/apis/home' import { getTrendAPI } from '@/apis/home'
const router = useRouter()
const queryParams = ref({ const queryParams = ref({
title: '', title: '',
pageNum: 1, pageNum: 1,
@ -55,11 +64,25 @@ onMounted(() => {
}) })
const handleCurrentChange = (val) => { const handleCurrentChange = (val) => {
queryParams.pageNum = val queryParams.value.pageNum = val
getTrendData()
} }
const handleSizeChange = (val) => { const handleSizeChange = (val) => {
queryParams.pageSize = val queryParams.value.pageSize = val
getTrendData()
}
const goTarget = (url) => {
window.open(url, '__blank');
}
const handleRowClick = (row) => {
if (row.type == 1) {
goTarget(row.url)
} else {
router.push(`news/${row.trendId}`)
}
} }
</script> </script>
@ -80,6 +103,7 @@ const handleSizeChange = (val) => {
.news-card { .news-card {
margin-top: 20px; margin-top: 20px;
// box-shadow: 10px 10px 10px 90px #FAEADF;
.card-header { .card-header {
display: flex; display: flex;

View File

@ -1,13 +1,91 @@
<template> <template>
<div class="container"> <div class="container">
动态详情 <div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: '/news' }">学校动态</el-breadcrumb-item>
<el-breadcrumb-item>{{ info.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="news-card">
<div class="news-top">
<h1>{{ info.title }}</h1>
<p class="news-info">
<span>上传者{{ info.createBy }}</span>
<span>上传时间{{ info.createTime }}</span>
</p>
</div>
<div class="news-content" v-html="info.content"> </div>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { getTrendInfoAPI } from '@/apis/home'
const route = useRoute()
const id = route.params.id
const info = ref({})
const getTrendInfoData = async () => {
const res = await getTrendInfoAPI(id)
info.value = res.data
}
onMounted(() => {
getTrendInfoData()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.container {} .container {
.bread-container {
padding: 25px 0;
:deep(.el-breadcrumb__inner) {
color: #fff;
font-size: 16px;
}
:deep(.el-breadcrumb__separator) {
color: #fff;
}
}
.news-card {
margin-top: 20px;
padding: 20px;
min-height: 600px;
background-color: #FAEADF;
border-radius: 10px;
.news-top {
text-align: center;
.news-info {
line-height: 60px;
color: #A9A19B;
span:nth-child(1) {
margin-right: 20px;
}
}
}
.news-content {
margin: 0 20px;
:deep(p) {
text-indent: 2em;
line-height: 30px;
}
}
}
}
</style> </style>

View File

@ -3,17 +3,17 @@
<div class="bread-container"> <div class="bread-container">
<el-breadcrumb separator=">"> <el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>专题资源</el-breadcrumb-item> <el-breadcrumb-item :to="{ path: 'subject' }">专题资源</el-breadcrumb-item>
<el-breadcrumb-item>课后服务</el-breadcrumb-item> <el-breadcrumb-item>{{ catalogName }}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</div> </div>
<div class="sub-subject-top"> <div class="sub-subject-top">
<img src="@/assets/images/subject.png" /> <img src="@/assets/images/subject.png" />
<div class="sub-subject-top-right"> <div class="sub-subject-top-right">
<div class="title">课后服务</div> <div class="title">{{ catalogName }}</div>
<div class="more">创建时间2024-01-01</div> <div class="more">创建时间{{ createTime }}</div>
<div class="more">资源数据1790</div> <div class="more">资源数据{{ resourceNum }}</div>
</div> </div>
</div> </div>
@ -26,28 +26,29 @@
</div> </div>
</template> </template>
<el-table :data="tableData" row-key="id" border default-expand-all :show-header="false"> <el-table @row-click="handleRowClick" :data="tableData" row-key="id" border default-expand-all
<el-table-column prop="name" label="Name" /> :show-header="false">
<el-table-column prop="label" label="label" />
</el-table> </el-table>
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="18"> <el-col :span="18">
<el-card> <el-card>
<div class="card-right-header"> <template #header>
<el-table :data="tableSortData" :default-sort="{ prop: 'date', order: 'descending' }"> <div class="card-right-header">
<el-table-column prop="date" label="上传时间" sortable width="180" /> <!-- 排序组件 -->
<el-table-column prop="name" label="浏览量" sortable width="180" /> <JzSort v-model="sortResult" :sortData="sortData" />
<el-table-column prop="address" label="下载量" sortable width="180" /> <div class="header-search">
</el-table> <el-input v-model="input" style="width: 300px" placeholder="请输入关键词" />
<div class="header-search"> <el-button type="primary" :icon="Search" />
<el-input v-model="input" style="width: 300px" placeholder="请输入关键词" /> </div>
<el-button type="primary" :icon="Search" />
</div> </div>
</div> </template>
<div class="book-grid"> <div class="book-grid">
<el-card v-for="item in resourceList"> <el-card v-for="item in resourceList" @click="goto(item)">
<div class="book-content"> <div class="book-content">
<img class="file-type" src="@/assets/images/word.png" alt=""> <img class="file-type" src="@/assets/images/word.png" alt="">
<img src="@/assets/images/book.png" alt=""> <img src="@/assets/images/book.png" alt="">
@ -71,7 +72,8 @@
</template> </template>
</el-card> </el-card>
</div> </div>
<el-pagination class="book-page" background layout="prev, pager, next, sizes,jumper" :total="total" /> <el-pagination class="book-page" background layout="prev, pager, next, sizes,jumper" :total="total"
@current-change="handleCurrentChange" @size-change="handleSizeChange" />
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
@ -79,50 +81,43 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted, watchEffect } from 'vue'
import { useRoute } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { View, Search } from '@element-plus/icons-vue' import { View, Search } from '@element-plus/icons-vue'
import { getResourceList } from '@/apis/catalogResource' import { getTreeList, getResourceList } from '@/apis/catalogResource'
import JzSort from '@/components/JzSort/index.vue'
const router = useRouter()
const route = useRoute() const route = useRoute()
const id = route.params const catalogId = route.query.catalogId
const catalogName = route.query.catalogName
const createTime = route.query.createTime
const resourceNum = route.query.resourceNum || 0
const queryParams = ref({ const queryParams = ref({
catalogId: catalogId,
title: '', title: '',
pageNum: 1, pageNum: 1,
pageSize: 6 pageSize: 6,
orderByColumn: '',
isAsc: ''
}) })
const tableData = [ //
{ const sortData = [
id: 1, { label: '上传时间', key: 'createTime' },
name: '全部', { label: '浏览量', key: 'previewNum' },
}, { label: '下载量', key: 'downloadNum' }
{ ];
id: 2, const sortResult = ref({}); //
name: '我上学了',
},
{
id: 3,
name: '识字',
children: [
{
id: 31,
name: '1 天地人',
},
{
id: 32,
name: '2金木水火土',
},
],
},
{
id: 4,
name: '汉语拼音',
},
]
const tableSortData = [] const tableData = ref([])
const getTreeListData = async () => {
const res = await getTreeList({ catalogId })
tableData.value = res.data
console.log(tableData.value);
}
const resourceList = ref([]) const resourceList = ref([])
const total = ref(0) const total = ref(0)
@ -132,9 +127,38 @@ const getResourceListData = async () => {
total.value = res.total total.value = res.total
} }
const handleRowClick = (val) => {
queryParams.value.catalogId = val.id
}
onMounted(() => { onMounted(() => {
getTreeListData()
getResourceListData() getResourceListData()
}) })
const handleCurrentChange = (val) => {
queryParams.value.pageNum = val
getResourceListData()
}
const handleSizeChange = (val) => {
queryParams.value.pageSize = val
getResourceListData()
}
//
watchEffect(() => {
queryParams.value.orderByColumn = sortResult.value.key
queryParams.value.isAsc = sortResult.value.order
getResourceListData()
})
const goto = (item) => {
router.push({ path: 'subjectDetail', query: { id: item.id } })
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -185,17 +209,8 @@ onMounted(() => {
} }
.card-right-header { .card-right-header {
position: relative; display: flex;
justify-content: space-between;
:deep(.el-table__body-wrapper) {
display: none;
}
.header-search {
position: absolute;
top: 0;
right: 0;
}
} }
.book-grid { .book-grid {

144
src/views/Teacher/index.vue Normal file
View File

@ -0,0 +1,144 @@
<template>
<div class="container">
<div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>校园名师</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-card class="teacher-card">
<template #header>
<div class="card-header">
<div>
<div class="title">校园名师</div>
<div>教育大计老师为本</div>
</div>
<el-input v-model="queryParams.title" style="width: 240px;" size="large" placeholder="请输入关键字"
:suffix-icon="Search" />
</div>
</template>
<ul class="card-teacher-list">
<li class="item" v-for="item in tableData">
<el-card>
<img :src="item.avatarUrl" alt="">
<p class="teacher-name">{{ item.teacherName }}</p>
<p class="teacher-class">{{ item.gradeName }}</p>
<p class="teacher-desc" v-html="item.content"></p>
</el-card>
</li>
</ul>
<template #footer>
<el-pagination class="footer" background layout="prev, pager, next, sizes,jumper" :total="total"
@current-change="handleCurrentChange" @size-change="handleSizeChange" />
</template>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { Search } from '@element-plus/icons-vue'
import { getShowAPI } from '@/apis/home'
const queryParams = ref({
title: '',
pageNum: 1,
pageSize: 10
})
const tableData = ref([])
const total = ref(0)
const getShowData = async () => {
const res = await getShowAPI(queryParams.value)
tableData.value = res.rows
total.value = res.total
}
onMounted(() => {
getShowData()
})
const handleCurrentChange = (val) => {
queryParams.value.pageNum = val
getShowData()
}
const handleSizeChange = (val) => {
queryParams.value.pageSize = val
getShowData()
}
</script>
<style lang="scss" scoped>
.container {
.bread-container {
padding: 25px 0;
:deep(.el-breadcrumb__inner) {
color: #fff;
font-size: 16px;
}
:deep(.el-breadcrumb__separator) {
color: #fff;
}
}
.teacher-card {
margin-top: 20px;
.card-header {
display: flex;
justify-content: space-between;
.title {
font-size: 20px;
font-weight: bold;
margin-bottom: 5px;
}
}
.card-teacher-list {
display: flex;
justify-content: space-between;
.item {
flex: 0 1 24%;
text-align: center;
.teacher-name {
line-height: 45px;
font-size: 18px;
font-weight: bold;
}
.teacher-class {
line-height: 40px;
font-size: 17px;
}
.teacher-desc {
font-size: 16px;
color: #7F7F7F;
text-align: left;
}
}
}
:deep(.el-table__row .cell) {
font-size: 17px;
padding: 7px;
}
.footer {
display: flex;
justify-content: end;
}
}
}
</style>

View File

@ -45,25 +45,25 @@
</el-form-item> </el-form-item>
<el-form-item label="类型"> <el-form-item label="类型">
<el-radio-group> <el-radio-group v-model="queryParams.type">
<el-radio-button>全部</el-radio-button> <el-radio-button label="全部" :value="0"></el-radio-button>
<el-radio-button>课件</el-radio-button> <el-radio-button label="课件" :value="1"></el-radio-button>
<el-radio-button>精品课堂</el-radio-button> <el-radio-button label="精品课堂" :value="2"></el-radio-button>
<el-radio-button>作业</el-radio-button> <el-radio-button label="作业" :value="3"></el-radio-button>
<el-radio-button>试卷</el-radio-button> <el-radio-button label="试卷" :value="4"></el-radio-button>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="格式"> <el-form-item label="格式">
<el-radio-group> <el-radio-group v-model="queryParams.fileSuffix">
<el-radio-button>全部</el-radio-button> <el-radio-button label="全部" value="0"></el-radio-button>
<el-radio-button>PPT</el-radio-button> <el-radio-button label="PPT" value="0"></el-radio-button>
<el-radio-button>WORD</el-radio-button> <el-radio-button label="WORD" value="0"></el-radio-button>
<el-radio-button>PDF</el-radio-button> <el-radio-button label="PDF" value="0"></el-radio-button>
<el-radio-button>图片</el-radio-button> <el-radio-button label="图片" value="0"></el-radio-button>
<el-radio-button>音频</el-radio-button> <el-radio-button label="音频" value="0"></el-radio-button>
<el-radio-button>视频</el-radio-button> <el-radio-button label="视频" value="0"></el-radio-button>
<el-radio-button>其它</el-radio-button> <el-radio-button label="其它" value="0"></el-radio-button>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -93,10 +93,10 @@
</div> </div>
<div class="book-grid"> <div class="book-grid">
<el-card v-for="item in tableData" :key="item"> <el-card v-for="item in tableData" :key="item" @click="goto(item)">
<div class="book-content"> <div class="book-content">
<img class="file-type" src="@/assets/images/word.png" alt="" /> <img class="file-type" src="@/assets/images/word.png" alt="" />
<img src="@/assets/images/book.png" alt="" /> <img class="book" src="@/assets/images/book.png" alt="" />
</div> </div>
<template #footer> <template #footer>
@ -105,7 +105,7 @@
<div class="book-teacher"><span>{{ item.createBy }}</span>&nbsp;|&nbsp;<span>{{ item.createDept <div class="book-teacher"><span>{{ item.createBy }}</span>&nbsp;|&nbsp;<span>{{ item.createDept
}}</span></div> }}</span></div>
<div class="book-view"> <div class="book-view">
<span> <span style="margin-right: 5px;">
<el-icon> <el-icon>
<View /> <View />
</el-icon> </el-icon>
@ -126,14 +126,20 @@
<script setup> <script setup>
import { ref, onMounted, watchEffect, watch } from 'vue'; import { ref, onMounted, watchEffect, watch } from 'vue';
import { useRouter } from 'vue-router'
import { View } from '@element-plus/icons-vue' import { View } from '@element-plus/icons-vue'
import { getTextbookAPI, getTextbookTreeAPI, getTextbookList } from '@/apis/textbook' import { getTextbookAPI, getTextbookTreeAPI, getTextbookList } from '@/apis/textbook'
import JzSort from '@/components/JzSort/index.vue' import JzSort from '@/components/JzSort/index.vue'
const router = useRouter()
const queryParams = ref({ const queryParams = ref({
catalogId: undefined, catalogId: undefined,
type: undefined,
fileSuffix: undefined,
pageNum: 1, pageNum: 1,
pageSize: 6 pageSize: 6,
orderByColumn: '',
isAsc: ''
}) })
const tableData = ref([]) const tableData = ref([])
const total = ref(0) const total = ref(0)
@ -207,19 +213,12 @@ const filterListByParentId = (parentId) => {
// //
const sortData = [ const sortData = [
{ label: '上传时间', key: 'date' }, { label: '上传时间', key: 'createTime' },
{ label: '浏览量', key: 'num1' }, { label: '浏览量', key: 'previewNum' },
{ label: '下载量', key: 'num2' } { label: '下载量', key: 'downloadNum' }
]; ];
const sortResult = ref({}); // const sortResult = ref({}); //
//
watchEffect(() => {
console.log('===排序 改变了===', sortResult.value);
// TODO:
})
const getTextbookListData = async () => { const getTextbookListData = async () => {
const res = await getTextbookList(queryParams.value) const res = await getTextbookList(queryParams.value)
tableData.value = res.rows tableData.value = res.rows
@ -227,11 +226,13 @@ const getTextbookListData = async () => {
} }
const handleCurrentChange = (val) => { const handleCurrentChange = (val) => {
queryParams.pageNum = val queryParams.value.pageNum = val
getTextbookListData()
} }
const handleSizeChange = (val) => { const handleSizeChange = (val) => {
queryParams.pageSize = val queryParams.value.pageSize = val
getTextbookListData()
} }
const handleRowClick = (val) => { const handleRowClick = (val) => {
@ -242,6 +243,18 @@ watch(() => queryParams.value.catalogId, (oldVal, newVal) => {
getTextbookListData() getTextbookListData()
}) })
//
watchEffect(() => {
queryParams.value.orderByColumn = sortResult.value.key
queryParams.value.isAsc = sortResult.value.order
getTextbookListData()
})
const goto = (item) => {
router.push({ path: 'textBookDetail', query: { id: item.id } })
}
onMounted(() => { onMounted(() => {
getTextbookData() getTextbookData()
getTextbookListData() getTextbookListData()
@ -289,8 +302,10 @@ onMounted(() => {
.book-content { .book-content {
position: relative; position: relative;
img { .book {
width: 250px; border-radius: 10px;
width: 100%;
height: 220px;
} }
.file-type { .file-type {

View File

@ -0,0 +1,105 @@
<template>
<div class="container">
<div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: 'textbook' }">同步教材</el-breadcrumb-item>
<el-breadcrumb-item>{{ info.fileName }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="textbook-card">
<div class="textbook-top">
<div class="left">
<h1>{{ info.fileName }}</h1>
<p class="textbook-info">
<span>上传者{{ info.createBy }}</span>
<span>上传时间{{ info.createTime }}</span>
</p>
</div>
<div class="right">
<el-button :icon="Download" type="primary" @click="downloadFile">下载</el-button>
</div>
</div>
<div class="textbook-content">
<PreviewFile :id="id" type="textbook" :fileSuffix="fileSuffix"></PreviewFile>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { getTextbookInfoAPI } from '@/apis/textbook'
import { Download } from '@element-plus/icons-vue'
import PreviewFile from '@/components/PreviewFile/index.vue'
import { download } from '@/utils/utils'
const route = useRoute()
const id = route.query.id
const fileSuffix = ref('')
const info = ref({})
const getTextbookInfoData = async () => {
const res = await getTextbookInfoAPI(id)
info.value = res.data
fileSuffix.value = res.data.fileSuffix
}
const downloadFile = () => {
download(`/portal/textbook/preview/${id}`, {}, info.value.fileName)
}
onMounted(() => {
getTextbookInfoData()
})
</script>
<style lang="scss" scoped>
.container {
.bread-container {
padding: 25px 0;
:deep(.el-breadcrumb__inner) {
color: #fff;
font-size: 16px;
}
:deep(.el-breadcrumb__separator) {
color: #fff;
}
}
.textbook-card {
margin-top: 20px;
padding: 20px;
min-height: 600px;
background-color: #E2F1F8;
border-radius: 10px;
.textbook-top {
display: flex;
justify-content: space-between;
align-items: center;
.textbook-info {
line-height: 60px;
color: #A9A19B;
span:nth-child(1) {
margin-right: 20px;
}
}
}
.textbook-content {
margin: 0 50px;
}
}
}
</style>

View File

@ -10,6 +10,11 @@ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
build: {
outDir: 'portal',
chunkSizeWarningLimit: 1600
},
base: '/portal',
plugins: [ plugins: [
vue(), vue(),
// ... // ...
@ -42,10 +47,10 @@ export default defineConfig({
}, },
server: { server: {
proxy: { proxy: {
'/api': { '/api-school': {
target: 'http://localhost:8090/', target: 'http://localhost:8090/',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') rewrite: (path) => path.replace(/^\/api-school/, '')
} }
} }
} }