pptist 基础功能

This commit is contained in:
zdg 2024-11-27 13:45:48 +08:00
parent 01dc5dc643
commit c1bba6e443
12 changed files with 647 additions and 212 deletions

View File

@ -23,7 +23,9 @@ const defaultData = {
curNode: null, // 当前选中的节点 curNode: null, // 当前选中的节点
defaultExpandedKeys: [], //展开的节点 defaultExpandedKeys: [], //展开的节点
subjectTree: [] // "树结构" 章节 subjectTree: [] // "树结构" 章节
} },
env: {}, // 不走同步 Pinia - 变量
curr: {} // 不走同步 Pinia - 当前信息
}, },
local: { // 本地(永久localStorage) local: { // 本地(永久localStorage)
}, },

View File

@ -1,15 +1,20 @@
<template> <template>
<template v-if="loading">
加载中...
</template>
<template v-else>
<Screen v-if="screening" /> <Screen v-if="screening" />
<Editor v-else-if="_isPC" /> <Editor v-else-if="_isPC" />
<Mobile v-else /> <Mobile v-else />
</template>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted } from 'vue' import { ref, onMounted, watch, onBeforeMount } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useScreenStore, useMainStore, useSnapshotStore } from './store' import { useScreenStore, useMainStore, useSnapshotStore, useSlidesStore } from './store'
import { LOCALSTORAGE_KEY_DISCARDED_DB } from './configs/storage' import { LOCALSTORAGE_KEY_DISCARDED_DB } from './configs/storage'
import { deleteDiscardedDB } from './utils/database' import { deleteDiscardedDB } from './utils/database'
import { isPC } from './utils/common' import { isPC } from './utils/common'
@ -17,10 +22,17 @@ import Editor from './views/Editor/index.vue'
import Screen from './views/Screen/index.vue' import Screen from './views/Screen/index.vue'
import Mobile from './views/Mobile/index.vue' import Mobile from './views/Mobile/index.vue'
// zdg
import msgUtils from '@/plugins/modal' //
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api
import { PPTApi } from './api'
const loading = ref(true)
const _isPC = isPC() const _isPC = isPC()
const mainStore = useMainStore() const mainStore = useMainStore()
const snapshotStore = useSnapshotStore() const snapshotStore = useSnapshotStore()
const slidesStore = useSlidesStore()
const { databaseId } = storeToRefs(mainStore) const { databaseId } = storeToRefs(mainStore)
const { screening } = storeToRefs(useScreenStore()) const { screening } = storeToRefs(useScreenStore())
@ -29,9 +41,11 @@ if (import.meta.env.MODE !== 'development') {
} }
onMounted(async () => { onMounted(async () => {
await initLoad()
await deleteDiscardedDB() await deleteDiscardedDB()
snapshotStore.initSnapshotDatabase() snapshotStore.initSnapshotDatabase()
mainStore.setAvailableFonts() mainStore.setAvailableFonts()
loading.value = false //
}) })
// localStorage indexedDB ID // localStorage indexedDB ID
@ -44,6 +58,29 @@ window.addEventListener('unload', () => {
const newDiscardedDB = JSON.stringify(discardedDBList) const newDiscardedDB = JSON.stringify(discardedDBList)
localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB) localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB)
}) })
/** 接口类型 */
interface Result {
code?: number,
msg?: string,
data?: any
rows?: Array<any>,
total?: number
}
//
const initLoad: Function = () => {
const urlSearch = location.href.split('?')[1]
const query = Object.fromEntries(new URLSearchParams(urlSearch))
const id: String = query.id
// pptx
if (!!id) return PPTApi.getSlideList(id)
return Promise.resolve()
}
//
watch(() => slidesStore.slides, (newVal, oldVal) => {
//
PPTApi.updateSlides(newVal, oldVal)
},{ deep: true })
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -0,0 +1,171 @@
/**
* @description ppt幻灯片相关的请求接口-
* @author zdg
* @date 2024-11-26
*/
import { toRaw } from 'vue'
import msgUtils from '@/plugins/modal' // 消息工具
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
import * as useStore from '../store' // pptist-状态管理
import { sessionStore } from '@/utils/store' // electron-store 状态管理
import useUserStore from '@/store/modules/user' // 外部-用户信息
const slidesStore = useStore.useSlidesStore()
const userStore = useUserStore()
/** 工具类 */
export class Utils {
static mxData: any = {
throTime: 0, // 节流时间
}
/**
* -
* @param {*} func
* @param {*} delay
* @param {*} type 1- 2-
* mxThrottle(() => {xxxx}, 200)
*/
static mxThrottle(func, delay = 200, type = 1) {
if (type == 1) { // 节流(第一次触发后面的事件不触发)
const cur = Date.now()
const lastExecuted = this.mxData.throTime
if (cur - lastExecuted > delay) {
this.mxData.throTime = cur
return func.apply(this)
}
} else { // 防抖(只触发最后一次事件)
const timer = this.mxData.throTime
!!timer && clearTimeout(timer)
this.mxData.throTime = setTimeout(() => {
return func.apply(this)
}, delay)
}
}
}
/** ppt相关后端接口处理 */
export class PPTApi {
// 变量
static isUpdate = true // 是否更新数据
// 获取所有幻灯片列表
static getSlideList(parentid: (Number | String)): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
const params: object = { parentid }
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
if (res.code === 200) {
const slides = (res.rows || []).map(o => {
if (!!o.datacontent) {
const json = JSON.parse(o.datacontent)
!!json && (json.id = o.id)
return json
}
// 如果没有数据,默认空白页
return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}}
})
slidesStore.updateSlideIndex(0) // 下标0 为第一页
slidesStore.setSlides(slides) // 写入数据
resolve(true)
} else msgUtils.msgError(res.msg || '获取数据失败');resolve(false)
})
}
// 新增幻灯片
static addSlide(data: object): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
const enpt = sessionStore.get('curr.entp')||{}
const resource = sessionStore.get('curr.resource')||{}
const {id, ...content} = data
const params = {
parentid: resource.id,
entpid: userStore.user.deptId,
entpcourseid: enpt.id,
ppttype: 'file',
title: '',
fileurl: '',
filetype: 'slide',
datacontent: JSON.stringify(content),
filekey: '',
filetag: '',
fileidx: 0,
dflag: 0,
status: '',
edituserid: userStore.id
}
const rid = await API_entpcoursefile.addEntpcoursefileReturnId(params)
if (!!rid) {
data.id = rid
slidesStore.updateSlide(data)
// msgUtils.msgSuccess('新增成功')
this.isUpdate = false // 新增后会触发监听,不再更新数据
resolve(true)
} else msgUtils.msgError('新增失败');resolve(false)
})
}
/**
* @description
* @param newVal
* @param oldVal
* @returns
*/
static async updateSlides(newVal: object, oldVal: object) {
const newData = toRaw(newVal)
const oldData = toRaw(oldVal)
console.log('监听幻灯片数据变化', newData, oldData)
if (!(newData&&newData.length)) return // 新数据为空,不需要更新数据
else if (!oldData.length) return // 初始加载,旧数据空不需要更新数据
const currentSlide = toRaw(slidesStore.currentSlide)
const isAdd = !/^\d+$/.test(currentSlide.id) // 是否新增
if (isAdd) { // 新增的幻灯片(id 为非数字,说明是新增的幻灯片)
const bool = await this.addSlide(currentSlide)
bool && this.batchUpdateSlides(newData, true) // 批量更新-排序
} else { // 防抖-更新
if (!this.isUpdate) return this.isUpdate = true // 下次更新数据
const params = {
id: currentSlide.id,
datacontent: JSON.stringify(currentSlide),
}
Utils.mxThrottle(() => {this.updateSlide(params)}, 1000, 2)
}
}
// 更新幻灯片
static updateSlide(data: object): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
if (res.code === 200) {
resolve(true)
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
})
}
/**
* @description |
* @param list
* @param sort
* @returns
*/
static batchUpdateSlides(list: Slide[], sort: boolean): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
const data: object[] = list.map((o, index) => ({
id: o.id,
fileidx: index,
datacontent: sort?null:JSON.stringify(o),
}))
const res: Result = await API_entpcoursefile.batchUpdateNew(data)
if (res.code === 200) {
resolve(true)
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
})
}
// 删除幻灯片
static delSlide(id: string): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
const res: Result = await API_entpcoursefile.delEntpcoursefile(id)
if (res.code === 200) {
resolve(true)
} else msgUtils.msgError(res.msg || '删除失败');resolve(false)
})
}
}
export default PPTApi

View File

@ -0,0 +1,19 @@
/**
* @description api store循环引用
* @author zdg
*/
import msgUtils from '@/plugins/modal' // 消息工具
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
export default class {
// 删除幻灯片
static delSlide(id: string): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
console.log('delSlide', id)
const res: Result = await API_entpcoursefile.delEntpcoursefile(id)
if (res.code === 200) {
resolve(true)
} else msgUtils.msgError(res.msg || '删除失败');resolve(false)
})
}
}

View File

@ -1,186 +1,187 @@
import type { Slide } from '../types/slides' import type { Slide } from '../types/slides'
export const slides: Slide[] = [ export const slides: Slide[] = [
{ // {
id: 'test-slide-1', // id: 'test-slide-1',
elements: [ // elements: [
{ // {
type: 'shape', // type: 'shape',
id: '4cbRxp', // id: '4cbRxp',
left: 0, // left: 0,
top: 200, // top: 200,
width: 546, // width: 546,
height: 362.5, // height: 362.5,
viewBox: [200, 200], // viewBox: [200, 200],
path: 'M 0 0 L 0 200 L 200 200 Z', // path: 'M 0 0 L 0 200 L 200 200 Z',
fill: '#5b9bd5', // fill: '#5b9bd5',
fixedRatio: false, // fixedRatio: false,
opacity: 0.7, // opacity: 0.7,
rotate: 0 // rotate: 0
}, // },
{ // {
type: 'shape', // type: 'shape',
id: 'ookHrf', // id: 'ookHrf',
left: 0, // left: 0,
top: 0, // top: 0,
width: 300, // width: 300,
height: 320, // height: 320,
viewBox: [200, 200], // viewBox: [200, 200],
path: 'M 0 0 L 0 200 L 200 200 Z', // path: 'M 0 0 L 0 200 L 200 200 Z',
fill: '#5b9bd5', // fill: '#5b9bd5',
fixedRatio: false, // fixedRatio: false,
flipV: true, // flipV: true,
rotate: 0 // rotate: 0
}, // },
{ // {
type: 'text', // type: 'text',
id: 'idn7Mx', // id: 'idn7Mx',
left: 355, // left: 355,
top: 65.25, // top: 65.25,
width: 450, // width: 450,
height: 188, // height: 188,
lineHeight: 1.2, // lineHeight: 1.2,
content: '<p><strong><span style=\"font-size: 112px;\">PPTist</span></strong></p>', // content: '<p><strong><span style=\"font-size: 112px;\">PPTist</span></strong></p>',
rotate: 0, // rotate: 0,
defaultFontName: 'Microsoft Yahei', // defaultFontName: 'Microsoft Yahei',
defaultColor: '#333' // defaultColor: '#333'
}, // },
{ // {
type: 'text', // type: 'text',
id: '7stmVP', // id: '7stmVP',
left: 355, // left: 355,
top: 253.25, // top: 253.25,
width: 585, // width: 585,
height: 56, // height: 56,
content: '<p><span style=\"font-size: 24px;\">基于 Vue 3.x + TypeScript 的在线演示文稿应用</span></p>', // content: '<p><span style=\"font-size: 24px;\">基于 Vue 3.x + TypeScript 的在线演示文稿应用</span></p>',
rotate: 0, // rotate: 0,
defaultFontName: 'Microsoft Yahei', // defaultFontName: 'Microsoft Yahei',
defaultColor: '#333' // defaultColor: '#333'
}, // },
{ // {
type: 'line', // type: 'line',
id: 'FnpZs4', // id: 'FnpZs4',
left: 361, // left: 361,
top: 238, // top: 238,
start: [0, 0], // start: [0, 0],
end: [549, 0], // end: [549, 0],
points: ['', ''], // points: ['', ''],
color: '#5b9bd5', // color: '#5b9bd5',
style: 'solid', // style: 'solid',
width: 2, // width: 2,
}, // },
], // ],
background: { // background: {
type: 'solid', // type: 'solid',
color: '#ffffff', // color: '#ffffff',
}, // },
}, // },
{ // {
id: 'test-slide-2', // id: 'test-slide-2',
elements: [ // elements: [
{ // {
type: 'text', // type: 'text',
id: 'ptNnUJ', // id: 'ptNnUJ',
left: 145, // left: 145,
top: 148, // top: 148,
width: 711, // width: 711,
height: 77, // height: 77,
lineHeight: 1.2, // lineHeight: 1.2,
content: '<p style=\"text-align: center;\"><strong><span style=\"font-size: 48px;\">在此处添加标题</span></strong></p>', // content: '<p style=\"text-align: center;\"><strong><span style=\"font-size: 48px;\">在此处添加标题</span></strong></p>',
rotate: 0, // rotate: 0,
defaultFontName: 'Microsoft Yahei', // defaultFontName: 'Microsoft Yahei',
defaultColor: '#333', // defaultColor: '#333',
}, // },
{ // {
type: 'text', // type: 'text',
id: 'mRHvQN', // id: 'mRHvQN',
left: 207.50000000000003, // left: 207.50000000000003,
top: 249.84259259259264, // top: 249.84259259259264,
width: 585, // width: 585,
height: 56, // height: 56,
content: '<p style=\"text-align: center;\"><span style=\"font-size: 24px;\">在此处添加副标题</span></p>', // content: '<p style=\"text-align: center;\"><span style=\"font-size: 24px;\">在此处添加副标题</span></p>',
rotate: 0, // rotate: 0,
defaultFontName: 'Microsoft Yahei', // defaultFontName: 'Microsoft Yahei',
defaultColor: '#333', // defaultColor: '#333',
}, // },
{ // {
type: 'line', // type: 'line',
id: '7CQDwc', // id: '7CQDwc',
left: 323.09259259259267, // left: 323.09259259259267,
top: 238.33333333333334, // top: 238.33333333333334,
start: [0, 0], // start: [0, 0],
end: [354.8148148148148, 0], // end: [354.8148148148148, 0],
points: ['', ''], // points: ['', ''],
color: '#5b9bd5', // color: '#5b9bd5',
style: 'solid', // style: 'solid',
width: 4 // width: 4
}, // },
{ // {
type: 'shape', // type: 'shape',
id: '09wqWw', // id: '09wqWw',
left: -27.648148148148138, // left: -27.648148148148138,
top: 432.73148148148147, // top: 432.73148148148147,
width: 1056.2962962962963, // width: 1056.2962962962963,
height: 162.96296296296296, // height: 162.96296296296296,
viewBox: [200, 200], // viewBox: [200, 200],
path: 'M 0 20 C 40 -40 60 60 100 20 C 140 -40 160 60 200 20 L 200 180 C 140 240 160 140 100 180 C 40 240 60 140 0 180 L 0 20 Z', // path: 'M 0 20 C 40 -40 60 60 100 20 C 140 -40 160 60 200 20 L 200 180 C 140 240 160 140 100 180 C 40 240 60 140 0 180 L 0 20 Z',
fill: '#5b9bd5', // fill: '#5b9bd5',
fixedRatio: false, // fixedRatio: false,
rotate: 0 // rotate: 0
} // }
], // ],
background: { // background: {
type: 'solid', // type: 'solid',
color: '#fff', // color: '#fff',
}, // },
}, // },
{ // {
id: 'test-slide-3', // id: 'test-slide-3',
elements: [ // elements: [
{ // {
type: 'shape', // type: 'shape',
id: 'vSheCJ', // id: 'vSheCJ',
left: 183.5185185185185, // left: 183.5185185185185,
top: 175.5092592592593, // top: 175.5092592592593,
width: 605.1851851851851, // width: 605.1851851851851,
height: 185.18518518518516, // height: 185.18518518518516,
viewBox: [200, 200], // viewBox: [200, 200],
path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z', // path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z',
fill: '#5b9bd5', // fill: '#5b9bd5',
fixedRatio: false, // fixedRatio: false,
rotate: 0 // rotate: 0
}, // },
{ // {
type: 'shape', // type: 'shape',
id: 'Mpwv7x', // id: 'Mpwv7x',
left: 211.29629629629628, // left: 211.29629629629628,
top: 201.80555555555557, // top: 201.80555555555557,
width: 605.1851851851851, // width: 605.1851851851851,
height: 185.18518518518516, // height: 185.18518518518516,
viewBox: [200, 200], // viewBox: [200, 200],
path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z', // path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z',
fill: '#5b9bd5', // fill: '#5b9bd5',
fixedRatio: false, // fixedRatio: false,
rotate: 0, // rotate: 0,
opacity: 0.7 // opacity: 0.7
}, // },
{ // {
type: 'text', // type: 'text',
id: 'WQOTAp', // id: 'WQOTAp',
left: 304.9074074074074, // left: 304.9074074074074,
top: 198.10185185185182, // top: 198.10185185185182,
width: 417.9629629629629, // width: 417.9629629629629,
height: 140, // height: 140,
content: '<p style=\"text-align: center;\"><strong><span style=\"font-size: 80px;\"><span style=\"color: rgb(255, 255, 255);\">感谢观看</span></span></strong></p>', // content: '<p style=\"text-align: center;\"><strong><span style=\"font-size: 80px;\"><span style=\"color: rgb(255, 255, 255);\">感谢观看</span></span></strong></p>',
rotate: 0, // rotate: 0,
defaultFontName: 'Microsoft Yahei', // defaultFontName: 'Microsoft Yahei',
defaultColor: '#333', // defaultColor: '#333',
wordSpace: 5 // wordSpace: 5
} // }
], // ],
background: { // background: {
type: 'solid', // type: 'solid',
color: '#fff', // color: '#fff',
}, // },
}, // },
// {"id":"-3hMiOtk8M","elements":[],"background":{"type":"solid","color":"#fff"}},
] ]

View File

@ -6,6 +6,8 @@ import { slides } from '../mocks/slides'
import { theme } from '../mocks/theme' import { theme } from '../mocks/theme'
import { layouts } from '../mocks/layout' import { layouts } from '../mocks/layout'
import PPTApi from '../api/store'
interface RemovePropData { interface RemovePropData {
id: string id: string
propName: string | string[] propName: string | string[]
@ -155,14 +157,13 @@ export const useSlidesStore = defineStore('slides', {
this.slides = slides this.slides = slides
}, },
deleteSlide(slideId: string | string[]) { async deleteSlide(slideId: string | string[]) {
const slidesId = Array.isArray(slideId) ? slideId : [slideId] const slidesId = Array.isArray(slideId) ? slideId : [slideId]
const slides: Slide[] = JSON.parse(JSON.stringify(this.slides)) const slides: Slide[] = JSON.parse(JSON.stringify(this.slides))
const deleteSlidesIndex = [] const deleteSlidesIndex = []
for (const deletedId of slidesId) { for (const deletedId of slidesId) {
const index = slides.findIndex(item => item.id === deletedId) const index = slides.findIndex(item => item.id === deletedId)
deleteSlidesIndex.push(index)
const deletedSlideSection = slides[index].sectionTag const deletedSlideSection = slides[index].sectionTag
if (deletedSlideSection) { if (deletedSlideSection) {
@ -172,9 +173,14 @@ export const useSlidesStore = defineStore('slides', {
slides[index + 1].sectionTag = deletedSlideSection slides[index + 1].sectionTag = deletedSlideSection
} }
} }
// 后端先删除,再更新页面数据
const isDel = await PPTApi.delSlide(deletedId)
if (isDel) {
// 后端删除成功,更新页面数据
deleteSlidesIndex.push(index)
slides.splice(index, 1) slides.splice(index, 1)
} }
}
let newIndex = Math.min(...deleteSlidesIndex) let newIndex = Math.min(...deleteSlidesIndex)
const maxIndex = slides.length - 1 const maxIndex = slides.length - 1

View File

@ -0,0 +1,54 @@
import request from '@/utils/request'
// 查询entpcourse列表
export function listEntpcourse(query) {
return request({
url: '/education/entpcourse/list',
method: 'get',
params: query
})
}
// 查询entpcourse详细
export function getEntpcourse(id) {
return request({
url: '/education/entpcourse/' + id,
method: 'get'
})
}
// 新增entpcourse
export function addEntpcourse(data) {
return request({
url: '/education/entpcourse',
method: 'post',
data: data
})
}
// 修改entpcourse
export function updateEntpcourse(data) {
return request({
url: '/education/entpcourse',
method: 'put',
data: data
})
}
// 删除entpcourse
export function delEntpcourse(id) {
return request({
url: '/education/entpcourse/' + id,
method: 'delete'
})
}
export function lpmChat(query) {
return request({
url: '/llm/chatToSD',
method: 'POST',
params: query
})
}

View File

@ -85,6 +85,14 @@ export function updateFileByArray(data) {
data: data data: data
}) })
} }
// zdg: 批量更新pptist - 新
export function batchUpdateNew(data) {
return request({
url: '/education/entpcoursefile/batch/update',
method: 'post',
data: data
})
}
// 修改entpcoursefile // 修改entpcoursefile
export function updateFile2Redis(data) { export function updateFile2Redis(data) {

View File

@ -10,7 +10,7 @@ import _ from 'lodash'
// import { diff } from 'jsondiffpatch' // import { diff } from 'jsondiffpatch'
// const Remote = isNode?require('@electron/remote'):{} // 远程模块 // const Remote = isNode?require('@electron/remote'):{} // 远程模块
const exArrs = ['subject'] // 不需要同步key-排除 const exArrs = ['subject','env','curr'] // 不需要同步key-排除
export function shareStorePlugin({store}) { export function shareStorePlugin({store}) {
store.$subscribe((mutation, state) => { // 自动同步 store.$subscribe((mutation, state) => { // 自动同步

View File

@ -6,7 +6,7 @@ import { sessionStore } from '@/utils/store'
// 默认数据 // 默认数据
const defData = sessionStore.store || {} const defData = sessionStore.store || {}
const exArrs = ['subject'] const exArrs = ['subject','env','curr']
exArrs.forEach(k => Object.keys(defData).includes(k) && (delete defData[k])) exArrs.forEach(k => Object.keys(defData).includes(k) && (delete defData[k]))
// 延时 // 延时

View File

@ -24,13 +24,21 @@
<div class="flex justify-between pb-2"> <div class="flex justify-between pb-2">
<h3>教师资源</h3> <h3>教师资源</h3>
<span class="c-btns"> <span class="c-btns">
<el-button size="small" text :icon="Refresh" @click="handleAll('refresh')">刷新</el-button> <template v-for="item in resourBtns">
<el-button size="small" text :icon="Files" @click="handleAll('resource')">资源库</el-button> <el-button :size="item.size" text :icon="item.icon" @click="handleAll(item.prop)">{{ item.name }}</el-button>
<el-button size="small" text :icon="UploadFilled" @click="handleAll('upload')">上传</el-button> </template>
<el-button size="small" text :icon="Plus" @click="handleAll('add')">添加</el-button>
</span> </span>
</div> </div>
<c-table ref="resourRef" v-bind="sourceOpt" t-class="rounded"></c-table> <c-table ref="resourRef" v-bind="sourceOpt" t-class="rounded">
<template #title="{row,value}">
<el-link :underline="false" @click="handleAll('open', row)">
<svg class="icon svg-icon" aria-hidden="true">
<use :xlink:href="`#icon-${getIcon(row)}`"></use>
</svg>
<b class="ml-1">{{ value }}</b>
</el-link>
</template>
</c-table>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -40,12 +48,16 @@
import { onMounted, ref, watch, reactive } from 'vue' import { onMounted, ref, watch, reactive } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { Plus, Refresh, Upload, Files, UploadFilled } from '@element-plus/icons-vue' import { Plus, Refresh, Upload, Files, UploadFilled } from '@element-plus/icons-vue'
import { createWindow } from '@/utils/tool' // import useUserStore from '@/store/modules/user' //
import * as entpcoursefile from '@/api/education/entpcoursefile' // api import msgUtils from '@/plugins/modal' //
import { createWindow, sessionStore } from '@/utils/tool' //
import * as API_entpcourse from '@/api/education/entpcourse' // api
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api
// //
import ChooseTextbook from '@/components/choose-textbook/index.vue' import ChooseTextbook from '@/components/choose-textbook/index.vue'
const router = useRouter() const router = useRouter()
const userStore = useUserStore() //
const courseObj = reactive({ const courseObj = reactive({
// : id,id,id, // : id,id,id,
@ -54,19 +66,27 @@ const courseObj = reactive({
levelSecondId: '', levelSecondId: '',
coursetitle: '', coursetitle: '',
node: null, // node: null, //
entp: null, //
}) })
const dt = reactive({ const dt = reactive({
curRow: null, // curRow: null, //
}) })
// ref // ref
const resourRef = ref() // ref const resourRef = ref() // ref
//
const resourBtns = [
{ name: '刷新', prop: 'refresh', size: 'small', icon: Refresh },
{ name: '资源库', prop:'resource', size:'small', icon: Files },
{ name: '上传', prop:'upload', size:'small', icon: UploadFilled },
{ name: '添加', prop:'add', size:'small', icon: Plus },
]
// -cTable // -cTable
const sourceOpt = reactive({ const sourceOpt = reactive({
data: [], // data: [], //
option: [ // option: [ //
{ label: '名称', prop: 'title', align: 'left' }, { label: '名称', prop: 'title', align: 'left' },
{ label: '类型', prop: 'type' }, { label: '类型', prop: 'filetype', width: 80, },
{ label: '时间', prop: 'createTime', width: 160, sortable: true }, { label: '时间', prop: 'timestamp', width: 160, sortable: true },
], ],
noPage: true, // noPage: true, //
isMain: false, // isMain: false, //
@ -78,15 +98,15 @@ const sourceOpt = reactive({
} else dt.curRow = r } else dt.curRow = r
} }
}) })
sourceOpt.data = [
{ title: '测试学校' }, //
{ title: '测试学校2' }, onMounted(() => {
{ title: '测试学校3' }, })
]
// -methods // -methods
// //
const changeBook = (data) => { const changeBook = async(data) => {
// console.log(data)
const { textBook, node } = data const { textBook, node } = data
let textbookId = textBook.curBookId let textbookId = textBook.curBookId
let levelSecondId = node.id let levelSecondId = node.id
@ -106,6 +126,13 @@ const changeBook = (data) => {
// ID // ID
localStorage.setItem('unitId', JSON.stringify({ levelFirstId, levelSecondId })) localStorage.setItem('unitId', JSON.stringify({ levelFirstId, levelSecondId }))
//
const params = { evalid: node.id, edituserid: userStore.id, pageSize: 1 }
const res = await HTTP_SERVER_API('getCourseList', params)
courseObj.entp = res?.rows?.[0] || null
sessionStore.set('curr.entp', courseObj.entp) //
// -
getResourceList()
} }
const openPPTist = () => { const openPPTist = () => {
@ -120,21 +147,131 @@ const onchange = (path) => {
router.push(path) router.push(path)
} }
} }
//
const getResourceList = async () => {
const entpcourseidarray = courseObj?.entp?.id
if (!entpcourseidarray) return msgUtils.msgWarning('请选择章节?')
const params = {
pageSize: 100, parentid: 0, entpcourseidarray,
orderByColumn: 'timestamp', isAsc: 'desc',
}
const res = await HTTP_SERVER_API('getCourseFileList', params)
if (res?.code == 200) {
sourceOpt.data = res?.rows || []
} else {
msgUtils.msgWarning('获取资源列表, 请重试')
}
}
// HTTP
const HTTP_SERVER_API = (type, params = {}) => {
switch (type) {
case 'addEntpcourse': { //
const node = courseObj.node || {}
if (!node) return msgUtils.msgWarning('请选择章节?')
const def = { //
entpid: userStore.user.deptId, // id
level: 1, //
parentid: 0, // id
dictid: 0, // id
evalid: node.id, // id
evalparentid: node.parentid, // id(id)
edusubject: node.edusubject, //
edudegree: node.edudegree, //
edustage: node.edustage, //
coursetype: '课标学科', //
coursetitle: node.itemtitle, //
coursedesc: '', //
status: '', //
dflag: 0, //
edituserid: userStore.id, // id
createblankfile: 'no', //
}
courseObj.entp = def
return API_entpcourse.addEntpcourse(def)
}
case 'addEntpcoursefile': { //
const enpt = courseObj.entp
const def = {
parentid: 0,
entpid: userStore.user.deptId,
entpcourseid: enpt.id,
ppttype: 'file',
title: enpt.coursetitle,
fileurl: '',
filetype: 'aptist',
datacontent: '',
filekey: '',
filetag: '',
fileidx: 0,
dflag: 0,
status: '',
edituserid: userStore.id
}
// return Promise.resolve(1)
return API_entpcoursefile.addEntpcoursefileReturnId({...def,...params})
}
case 'getCourseList': { //
return API_entpcourse.listEntpcourse(params)
}
case 'getCourseFileList':{ //
return API_entpcoursefile.listEntpcoursefileNew(params)
}
}
}
// //
const handleAll = (type) =>{ const handleAll = async(type, row) =>{
console.log(type) console.log(type)
switch (type) { switch (type) {
case 'refresh': // case 'refresh': //
getResourceList()
break; break;
case 'resource': // case 'resource': //
break; break;
case 'upload': // case 'upload': //
break; break;
case 'add':{ // case 'add':{ // PPT-list -
const enpt = courseObj.entp //
if (!enpt) { //
const resid = await HTTP_SERVER_API('addEntpcourse')
courseObj.entp.id = resid
}
// ppt-
const p_params = {parentContent: '{"width":1000,"ratio":0.5625}'}
const id = await HTTP_SERVER_API('addEntpcoursefile', p_params)
if (!!id??null) { //
const params = {
parentid: id,
title: '第一页',
filetype: 'slide',
datacontent: '{"elements":[],"background":{"type":"solid","color":"#fff"}}' // json
}
// ppt-(slide)
await HTTP_SERVER_API('addEntpcoursefile', params)
//
await getResourceList()
} else {
msgUtils.msgWarning('添加失败!')
}
break; break;
} }
case 'open': { // -pptist
// console.log(row)
if (row.filetype != 'aptist') return msgUtils.msgWarning('暂不支持该类型文件!')
sessionStore.set('curr.resource', row) //
const query = { id: row.id }
const queryUrl = new URLSearchParams(query).toString()
console.log('打开资源 ', queryUrl)
createWindow('open-win', { url: `/pptist?${queryUrl}` })
}
} }
} }
// icons
const getIcon = o => {
let icon = o.filetype
if (['aptist','PPTX','pptList'].includes(o.filetype)) icon = 'pptx'
return icon
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>