提交 2f6edac6 authored 作者: lihuihui's avatar lihuihui

update

上级 3f1b3100
......@@ -35,7 +35,13 @@ function genNavClassName(data: IMenuItem) {
<h1 class="app-name">统一资源管理平台</h1>
</div>
<div class="app-header-nav">
<div class="app-header-nav-item" v-for="(item, index) in menus" :key="index" :class="genNavClassName(item)" v-permission="item.tag">
<div
class="app-header-nav-item"
v-for="(item, index) in menus"
:key="index"
:class="genNavClassName(item)"
v-permission="item.tag"
>
<router-link :to="item.path">{{ item.name }}</router-link>
</div>
</div>
......
import type { RouteRecordRaw } from 'vue-router'
export const routes: Array<RouteRecordRaw> = [
{
path: '/course',
redirect: '/course/my'
}
]
import httpRequest from '@/utils/axios'
// 获取视频列表
export function getVideoList(params: { tab: string; status?: string; authorized?: string; classification?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/resource/v1/resource/video/list', { params })
}
// 创建视频
export function createVideo(data: { name: string; source: string; classification: string; knowledge_points: string; cover: string; source_id: string }) {
return httpRequest.post('/api/resource/v1/resource/video/create', data)
}
// 获取封面列表
export function getCoverList() {
return httpRequest.get('/api/resource/v1/util/get-cover-list')
}
// 获取视频详情
export function getVideoDetails(params: { id: string }) {
return httpRequest.get('/api/resource/v1/resource/video/view', { params })
}
// 更新视频
export function updateVideo(data: { id: string; name: string; classification: string; knowledge_points?: string; cover?: string }) {
return httpRequest.post('/api/resource/v1/resource/video/update', data)
}
// 部门共享
export function setDepartment(data: { id: string }) {
return httpRequest.post('/api/resource/v1/resource/video/set-department', data)
}
// 平台共享
export function setPlatform(data: { id: string }) {
return httpRequest.post('/api/resource/v1/resource/video/set-platform', data)
}
// 上下线
export function setStatus(data: { id: string }) {
return httpRequest.post('/api/resource/v1/resource/video/set-status', data)
}
// 更改负责人
export function setBelong(data: { id: string; belong_operator: string }) {
return httpRequest.post('/api/resource/v1/resource/video/set-belong', data)
}
// 获取视频详情
export function getVideoPpt(params: { id: string }) {
return httpRequest.get('/api/resource/v1/resource/video/get-ppt', { params })
}
// 创建课件
export function createPpt(data: { id: string; ppts: string }) {
return httpRequest.post('/api/resource/v1/resource/video/create-ppt', data)
}
// 编辑课件
export function updatePpt(data: { id: string; ppt_id: string, name: string, point: string, url: string }) {
return httpRequest.post('/api/resource/v1/resource/video/update-ppt', data)
}
// 编辑课件
export function deletePpt(data: { id: string; ppt_id: string }) {
return httpRequest.post('/api/resource/v1/resource/video/delete-ppt', data)
}
<script setup lang="ts">
const props:any = defineProps<{ data: object, tabIndex: string }>()
</script>
<template>
<!-- <div>{{ props.data }}</div> -->
<div class="card-item">
<div class="card-item-top">
<div class="title">{{ props.data.name }}</div>
<!-- <img :src="props.data.cover" /> -->
<div class="cover-img" :style="`background-image:url(${props.data.cover})`"></div>
<div class="tool-pop-btn">
<div style="min-width:100%">
<router-link v-if="props.data.auth_edit" :to="`/resource/video/update?id=${props.data.id}`">
<div class="edit-btn">编辑</div>
</router-link>
</div>
<div style="min-width:100%">
<router-link v-if="props.data.auth_view" :to="`/resource/video/view?id=${props.data.id}`">
<div class="view-btn">查看</div>
</router-link>
</div>
</div>
</div>
<div class="card-item-bottom">
<div class="item-t">
<div class="text">{{ props.data.created_operator_name }}/{{ props.data.organ_id_name }}</div>
<div :class="props.data.status == 1 ? 'tag green' : 'tag'">{{ props.data.status_name }}</div>
</div>
<div class="item-b">
<div class="time">{{ props.data.updated_time }}</div>
<div class="tag" v-if="tabIndex === '2'">{{ props.data.department_public === '0' ? '未共享' : '已共享' }}</div>
<div class="tag" v-if="tabIndex === '3'">{{ props.data.platform_public === '0' ? '未共享' : '已共享' }}</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.card-item {
width: 265px;
border-radius: 6px;
overflow: hidden;
margin-right: 20px;
margin-bottom: 20px;
.card-item-top {
height: 170px;
position: relative;
&:hover {
.tool-pop-btn {
opacity: 1;
}
}
.cover-img {
width: 100%;
height: 100%;
background-size: cover;
}
.title {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
line-height: 37px;
background: rgba(0, 0, 0, 0.4);
font-size: 18px;
color: #ffffff;
padding-left: 16px;
box-sizing: border-box;
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
}
.tool-pop-btn {
transition: all .5s;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
opacity: 0;
padding-top: 52px;
box-sizing: border-box;
.edit-btn{
width: 113px;
line-height: 32px;
border: 1px solid #D3D3D3;
border-radius: 18px;
text-align: center;
font-size: 14px;
color: #FFFFFF;
margin: 0 auto 12px;
cursor: pointer;
}
.view-btn{
width: 113px;
line-height: 32px;
background: #AA1941;
border-radius: 18px;
text-align: center;
font-size: 14px;
color: #FFFFFF;
margin: 0 auto;
cursor: pointer;
}
}
}
}
.card-item-bottom{
background: #fff;
padding: 20px 16px 30px;
.item-t{
display: flex;
align-items: center;
justify-content: space-between;
.text{
width: 150px;
font-size: 16px;
line-height: 100%;
color: #666666;
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
}
.tag{
width: 48px;
line-height: 22px;
background: #AA1941;
border-radius: 11px;
font-size: 14px;
color: #fff;
text-align: center;
&.green{
background: #1AB226;
}
}
}
.item-b{
margin-top: 18px;
display: flex;
align-items: center;
justify-content: space-between;
.time{
font-size: 14px;
line-height: 100%;
color: #999999;
}
.tag{
font-size: 16px;
line-height: 100%;
color: #999999;
}
}
}
</style>
\ No newline at end of file
<script setup lang="ts">
const prop = defineProps(['data'])
const bytesToSize = (bytes: number) => {
if (bytes === 0) return { number: 0, unit: 'B' }
const k = 1000, // or 1024
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k))
return { number: (bytes / Math.pow(k, i)).toPrecision(3), unit: sizes[i] }
}
</script>
<template>
<div class="statistics-list">
<div class="item" v-for="(item, index) in prop.data" :key="index">
<template v-if="item.key === 'memory_size'">
<div class="icon"></div>
<div class="num">
{{ bytesToSize(item.number).number }}<span>{{ bytesToSize(item.number).unit }}</span>
</div>
<div class="text">{{ item.text }}</div>
</template>
<template v-else-if="item.key === 'learn_time_length' || item.key === 'length'">
<div class="icon"></div>
<div class="num">
{{ Number((item.number / 60 / 60).toString().match(/^\d+(?:\.\d{0,2})?/)) }}<span>{{ item.unit }}</span>
</div>
<div class="text">{{ item.text }}</div>
</template>
<template v-else>
<div class="icon"></div>
<div class="num">
{{ item.number }}<span>{{ item.unit }}</span>
</div>
<div class="text">{{ item.text }}</div>
</template>
</div>
</div>
</template>
<style lang="scss">
.statistics-list {
display: flex;
margin-top: -20px;
justify-content: space-around;
.item {
padding-top: 15px;
min-width: 110px;
height: 140px;
border: 1px solid #e5e5e5;
border-radius: 6px;
box-sizing: border-box;
margin-right: 20px;
margin-top: 20px;
// &:nth-child(1) {
// .icon {
// background-image: url(https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/home-icon1.png);
// }
// }
&:nth-child(1) {
.icon {
background-image: url(https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/home-icon2.png);
}
}
&:nth-child(2) {
.icon {
background-image: url(https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/home-icon3.png);
}
}
&:nth-child(3) {
.icon {
background-image: url(https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/home-icon4.png);
}
}
&:nth-child(4) {
.icon {
background-image: url(https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/home-icon8.png);
}
}
&:nth-child(5) {
.icon {
background-image: url(https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/home-icon9.png);
}
}
.icon {
width: 40px;
height: 40px;
background-size: 100% 100%;
margin: 0 auto;
}
.num {
font-size: 26px;
line-height: 100%;
color: #bf9d6b;
text-align: center;
padding: 10px;
span {
font-size: 12px;
}
}
.text {
font-size: 14px;
line-height: 100%;
color: #8e8e8e;
text-align: center;
}
}
}
</style>
import type { RouteRecordRaw } from 'vue-router'
import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [
{
path: '/course/my',
component: AppLayout,
children: [
{ path: '', component: () => import('./views/List.vue') }
]
}
]
<script setup lang="ts">
import { getVideoList } from '../api'
import CardListItem from '../components/CardListItem.vue'
import { Expand, PictureFilled } from '@element-plus/icons-vue'
import { useGetCategoryList } from '@/composables/useGetCategoryList'
import { useProjectList } from '@/composables/useGetProjectList'
import { useMapStore } from '@/stores/map'
import { useUserStore } from '@/stores/user'
// 统计资源数据整合
import Statistics from '../components/Statistics.vue'
// 判断当前用户是不是超级管理员
const user = useUserStore().roles
const isAdmin = !!user.find((item: any) => item.name === '超级管理员')
const store = useMapStore()
// 筛选部门列表
const departmentList: any = useProjectList('', '79806610719731712').departmentList
// 筛选下拉选择tree 视频分类
let { list: selectTree } = useGetCategoryList()
const defaultProps = {
children: 'children',
label: 'category_name',
value: 'id'
}
// 资源出处 tab触发
const tabValue = ref('1')
const appList = ref()
const tabChange = () => {
appList.value.refetch()
}
// 列表切换
let isCard = $ref(true)
// table 数据
const listOptions = $computed(() => {
const columns = [
{
label: '视频标题',
prop: 'name',
align: 'center',
computed({ row }: any) {
return row.name?.length > 10 ? `${row.name.slice(0, 10)}...` : row.name
}
},
{ label: '视频分类', prop: 'classification_name', align: 'center' },
{ label: '知识点', prop: 'knowledge_points', align: 'center' },
{ label: '封面', slots: 'table-cover', width: 150, align: 'center' },
{ label: '资源状态', prop: 'status_name', align: 'center' },
{ label: '审核状态', prop: 'audit_status_name', align: 'center' },
{ label: '更新人', prop: 'updated_operator_name', align: 'center' },
{ label: '更新人部门', prop: 'organ_id_name', align: 'center' },
{ label: '更新日期', prop: 'updated_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', width: 200 }
]
if (tabValue.value === '2') {
columns.splice(2, 0, { label: '部门共享', prop: 'department_public_name', align: 'center' })
}
if (tabValue.value === '3') {
columns.splice(2, 0, { label: '平台共享', prop: 'platform_public_name', align: 'center' })
}
return {
remote: {
httpRequest: getVideoList,
params: { tab: tabValue, status: '', authorized: '', name: '' }
},
filters: [
{
type: 'select',
prop: 'status',
label: '状态',
options: store.getMapValuesByKey('system_status')
},
{ prop: 'classification', label: '类别', slots: 'filter-type' },
{ type: 'input', prop: 'name', label: '标题' },
{
prop: 'authorized',
slots: 'filter-department'
}
],
columns
}
})
const typeFilter = () => {
appList.value.refetch()
}
const changeCard = () => {
isCard = !isCard
}
const statisticsData = [
{ key: 'courseware_count', unit: '门', number: 0, text: '平台课程总数' },
{ key: 'other_information_count', unit: '门', number: 0, text: '部门课程总数' },
{ key: 'question_count', unit: '门', number: 0, text: '我的课程总数' },
{ key: 'learn_times', unit: '万人次', number: 0, text: '总学习人次' },
{ key: 'learn_time_length', unit: '小时', number: 0, text: '总学习时长' }
]
</script>
<template>
<AppCard title="资源统计">
<Statistics :data="statisticsData"></Statistics>
</AppCard>
<AppCard>
<div class="video-head">
<el-tabs @tab-change="tabChange" v-model="tabValue">
<el-tab-pane label="我的资源" name="1"></el-tab-pane>
<el-tab-pane label="部门资源" name="2"></el-tab-pane>
<el-tab-pane label="公开资源" name="3"></el-tab-pane>
</el-tabs>
<el-icon class="video-head-icon" @click="changeCard"><Expand /></el-icon>
</div>
<div class="video-tool-btn">
<router-link
v-if="tabValue === '1'"
to="/resource/video/update"
target="_blank"
v-permission="'v1-resource-video-create'"
>
<el-button type="primary" round>新建视频资源</el-button>
</router-link>
</div>
<AppList v-bind="listOptions" ref="appList">
<template #header-aside></template>
<template #table-cover="{ row }">
<div style="background: #ccc">
<el-icon :size="50" color="#fff" v-if="row.cover == ''">
<PictureFilled></PictureFilled>
</el-icon>
<div
v-else
:style="`width: 150px;
display: block;
height: 83px;
background-size: cover;
background-image: url(${row.cover});`"
></div>
</div>
</template>
<template #filter-type="{ params }">
<el-tree-select
@change="typeFilter"
clearable
:props="defaultProps"
v-model="params.classification"
:data="selectTree"
/>
</template>
<template v-if="tabValue == '3' && isAdmin" #filter-department="{ params }">
<div class="name" style="font-size: 14px; color: #606266; padding-right: 12px">部门</div>
<el-select @change="typeFilter" clearable v-model="params.authorized">
<el-option v-for="item in departmentList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</template>
<template #table-operate="{ row }">
<el-space>
<router-link v-if="row.auth_edit" :to="`/resource/video/update?id=${row.id}`">
<el-button plain>编辑</el-button>
</router-link>
<router-link v-permission="'v1-resource-video-view'" :to="`/resource/video/view?id=${row.id}`">
<el-button type="primary" plain>查看</el-button>
</router-link>
</el-space>
</template>
<!-- 卡片 -->
<template #body="{ data }" v-if="isCard">
<div class="card-list" v-if="data.length">
<CardListItem :tabIndex="tabValue" v-for="(item, index) in data" :data="item" :key="index"></CardListItem>
</div>
<el-empty v-else description="暂无数据" />
</template>
</AppList>
</AppCard>
</template>
<style lang="scss">
.card-list {
background: #fafafa;
padding: 20px;
display: flex;
flex-wrap: wrap;
}
.video-head {
position: relative;
.video-head-icon {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
color: #666;
cursor: pointer;
}
}
.video-tool-btn {
padding: 10px 0 30px 0;
}
</style>
......@@ -98,38 +98,42 @@ const submitForm = async (formEl: FormInstance | undefined) => {
// 更新
const updateResources = () => {
const params = Object.assign({ id: id }, form.data)
updateVideo(params).then((res: any) => {
if (res.code === 0) {
ElMessage({ message: '更新成功', type: 'success' })
setTimeout(() => {
router.push({
path: '/resource/video'
})
}, 1000)
} else {
updateVideo(params)
.then((res: any) => {
if (res.code === 0) {
ElMessage({ message: '更新成功', type: 'success' })
setTimeout(() => {
router.push({
path: '/resource/video'
})
}, 1000)
} else {
submitFlag = true
}
})
.catch(() => {
submitFlag = true
}
}).catch(() => {
submitFlag = true
})
})
}
// 新建
const createResources = () => {
createVideo(form.data).then((res: any) => {
if (res.code === 0) {
ElMessage({ message: '创建成功', type: 'success' })
setTimeout(() => {
router.push({
path: '/resource/video'
})
}, 1000)
} else {
createVideo(form.data)
.then((res: any) => {
if (res.code === 0) {
ElMessage({ message: '创建成功', type: 'success' })
setTimeout(() => {
router.push({
path: '/resource/video'
})
}, 1000)
} else {
submitFlag = true
}
})
.catch(() => {
submitFlag = true
}
}).catch(() => {
submitFlag = true
})
})
}
// 协议勾选
......@@ -147,11 +151,11 @@ const watchSwiper = (index: number) => {
if (!index) {
isSwiperBtn = 0
} else {
swiperCovers.length === index + 1 ? isSwiperBtn = 1 : isSwiperBtn = 2
swiperCovers.length === index + 1 ? (isSwiperBtn = 1) : (isSwiperBtn = 2)
}
}
const changeProtocol = (data:any) => {
const changeProtocol = (data: any) => {
protocol.value = data.value
}
</script>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论