Merge branch 'zouyf_dev' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl
This commit is contained in:
commit
eb428eaddf
|
@ -23,7 +23,9 @@ const defaultData = {
|
||||||
curNode: null, // 当前选中的节点
|
curNode: null, // 当前选中的节点
|
||||||
defaultExpandedKeys: [], //展开的节点
|
defaultExpandedKeys: [], //展开的节点
|
||||||
subjectTree: [] // "树结构" 章节
|
subjectTree: [] // "树结构" 章节
|
||||||
}
|
},
|
||||||
|
env: {}, // 不走同步 Pinia - 变量
|
||||||
|
curr: {} // 不走同步 Pinia - 当前信息
|
||||||
},
|
},
|
||||||
local: { // 本地(永久localStorage)
|
local: { // 本地(永久localStorage)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<Screen v-if="screening" />
|
<template v-if="loading">
|
||||||
<Editor v-else-if="_isPC" />
|
加载中...
|
||||||
<Mobile v-else />
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<Screen v-if="screening" />
|
||||||
|
<Editor v-else-if="_isPC" />
|
||||||
|
<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">
|
||||||
|
|
|
@ -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
|
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"}},
|
||||||
]
|
]
|
|
@ -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,8 +173,13 @@ export const useSlidesStore = defineStore('slides', {
|
||||||
slides[index + 1].sectionTag = deletedSlideSection
|
slides[index + 1].sectionTag = deletedSlideSection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 后端先删除,再更新页面数据
|
||||||
slides.splice(index, 1)
|
const isDel = await PPTApi.delSlide(deletedId)
|
||||||
|
if (isDel) {
|
||||||
|
// 后端删除成功,更新页面数据
|
||||||
|
deleteSlidesIndex.push(index)
|
||||||
|
slides.splice(index, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let newIndex = Math.min(...deleteSlidesIndex)
|
let newIndex = Math.min(...deleteSlidesIndex)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,16 @@ export function listEntpcoursework(query) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 查询entpcoursework列表
|
||||||
|
export function listEntpcourseworkLocal(query) {
|
||||||
|
return request({
|
||||||
|
url: '/education/entpcoursework/local/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 查询entpcoursework详细
|
// 查询entpcoursework详细
|
||||||
export function getEntpcoursework(id) {
|
export function getEntpcoursework(id) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
@ -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
|
||||||
|
})
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted, watch } from 'vue'
|
||||||
import { conversation, completion } from '@/api/mode/index'
|
import { completion } from '@/api/mode/index'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { dataSetJson } from '@/utils/comm.js'
|
import { dataSetJson } from '@/utils/comm.js'
|
||||||
|
@ -58,7 +58,7 @@ const props = defineProps({
|
||||||
return { name: '11' }
|
return { name: '11' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modeType: {
|
type: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1
|
default: 1
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ const send = () =>{
|
||||||
msg: textarea.value
|
msg: textarea.value
|
||||||
})
|
})
|
||||||
loaded.value = true
|
loaded.value = true
|
||||||
getConversation(textarea.value)
|
getCompletion(textarea.value)
|
||||||
textarea.value = ''
|
textarea.value = ''
|
||||||
}
|
}
|
||||||
const curNode = reactive({})
|
const curNode = reactive({})
|
||||||
|
@ -87,16 +87,11 @@ const params = reactive(
|
||||||
dataset_id: ''
|
dataset_id: ''
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// 获取会话ID
|
|
||||||
const getConversation = (val) => {
|
|
||||||
|
|
||||||
getCompletion(val)
|
|
||||||
}
|
|
||||||
// 大模型对话
|
// 大模型对话
|
||||||
const getCompletion = async (val) => {
|
const getCompletion = async (val) => {
|
||||||
try {
|
try {
|
||||||
|
params.prompt = `按照${val}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
||||||
params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标${props.item.name},${val}`
|
|
||||||
const { data } = await completion(params)
|
const { data } = await completion(params)
|
||||||
let answer = data.answer
|
let answer = data.answer
|
||||||
msgList.value.push({
|
msgList.value.push({
|
||||||
|
@ -117,13 +112,26 @@ const saveAdjust = (item) =>{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modeType = ref('课标')
|
||||||
|
watch(() => props.type, (newVal) => {
|
||||||
|
if (newVal == 1){
|
||||||
|
modeType.value = '课标'
|
||||||
|
}
|
||||||
|
if (newVal == 2){
|
||||||
|
modeType.value = '教材'
|
||||||
|
}
|
||||||
|
if (newVal == 2){
|
||||||
|
modeType.value = '考试'
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { immediate: false })
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let data = sessionStore.get('subject.curNode')
|
let data = sessionStore.get('subject.curNode')
|
||||||
|
|
||||||
Object.assign(curNode, data);
|
Object.assign(curNode, data);
|
||||||
let text = props.modeType == 1||props.modeType == 2 ? '课标' : '考试'
|
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
|
||||||
let jsonKey = `${text}-${data.edustage}-${data.edusubject}`
|
|
||||||
console.log(jsonKey)
|
|
||||||
params.dataset_id = dataSetJson[jsonKey]
|
params.dataset_id = dataSetJson[jsonKey]
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -52,7 +52,7 @@ watch(() => props.item.answer, (newVal) => {
|
||||||
|
|
||||||
|
|
||||||
const onSave = () =>{
|
const onSave = () =>{
|
||||||
editTempResult({id: props.item.reultId, content: textarea.value}).then( res =>{
|
editTempResult({id: props.item.resultId, content: textarea.value}).then( res =>{
|
||||||
isDialog.value = false
|
isDialog.value = false
|
||||||
ElMessage.success('操作成功')
|
ElMessage.success('操作成功')
|
||||||
emitter.emit('onGetChild', textarea.value)
|
emitter.emit('onGetChild', textarea.value)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, nextTick } from 'vue'
|
import { ref, onMounted, nextTick } from 'vue'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
import PDF from '@/components/PdfJs/index.vue'
|
import PDF from '@/components/PdfJs/index.vue'
|
||||||
import LeftDialog from './left-dialog.vue'
|
import LeftDialog from './left-dialog.vue'
|
||||||
|
|
||||||
|
@ -31,7 +32,11 @@ const onClick = () => {
|
||||||
const pdfUrl = ref('')
|
const pdfUrl = ref('')
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const { fileurl } = props.curNode
|
let data = sessionStore.get('subject.curBook')
|
||||||
|
let fileurl = data.fileurl
|
||||||
|
if(props.type == 1){
|
||||||
|
fileurl = `${data.edustage}-${data.edusubject}-课标.txt`
|
||||||
|
}
|
||||||
pdfUrl.value = import.meta.env.VITE_APP_RES_FILE_PATH + fileurl.replace('.txt', '.pdf')
|
pdfUrl.value = import.meta.env.VITE_APP_RES_FILE_PATH + fileurl.replace('.txt', '.pdf')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -76,15 +76,16 @@
|
||||||
<!--编辑结果-->
|
<!--编辑结果-->
|
||||||
<EditDialog v-model="isEdit" :item="editItem" />
|
<EditDialog v-model="isEdit" :item="editItem" />
|
||||||
<!--AI 对话调整-->
|
<!--AI 对话调整-->
|
||||||
<AdjustDialog v-model="isAdjust" :modeType="type" :item="editItem" />
|
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" />
|
||||||
<!--添加、编辑提示词-->
|
<!--添加、编辑提示词-->
|
||||||
<keywordDialog v-model="isWordDialog" :isAdd="isAdd" :item="editItem" />
|
<keywordDialog v-model="isWordDialog" :isAdd="isAdd" :item="editItem" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, computed, onUnmounted } from 'vue'
|
import { ref, reactive, onMounted, watch, onUnmounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { tempSave, completion, modelList, removeChildTemp, tempResult } from '@/api/mode/index'
|
import { tempSave, completion, modelList, removeChildTemp, tempResult, editTempResult } from '@/api/mode/index'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
import keywordDialog from './keyword-dialog.vue';
|
import keywordDialog from './keyword-dialog.vue';
|
||||||
import AdjustDialog from './adjust-dialog.vue'
|
import AdjustDialog from './adjust-dialog.vue'
|
||||||
import EditDialog from './edit-dialog.vue'
|
import EditDialog from './edit-dialog.vue'
|
||||||
|
@ -154,13 +155,13 @@ const getChildTemplate = () => {
|
||||||
|
|
||||||
// 查询模板结果
|
// 查询模板结果
|
||||||
const getTempResult = () => {
|
const getTempResult = () => {
|
||||||
tempResult({ mainModelId: curTemplate.id }).then(res => {
|
tempResult({ mainModelId: curTemplate.id, pageNum: 1, pageSize: 10000 }).then(res => {
|
||||||
let rows = res.rows
|
let rows = res.rows
|
||||||
childTempList.value.forEach(item => {
|
childTempList.value.forEach(item => {
|
||||||
rows.forEach(el => {
|
rows.forEach(el => {
|
||||||
if (item.id == el.modelId) {
|
if (item.id == el.modelId) {
|
||||||
item.answer = el.content
|
item.answer = el.content
|
||||||
item.reultId = el.id
|
item.resultId = el.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -187,7 +188,7 @@ const changeTemplate = (val) => {
|
||||||
const removeItem = async (item, isChild) => {
|
const removeItem = async (item, isChild) => {
|
||||||
/**
|
/**
|
||||||
* item: 当前操作的模板
|
* item: 当前操作的模板
|
||||||
* isChild: 子模板中的移除为 true 否则为false
|
* isChild: 子模板中的移除为 true
|
||||||
*/
|
*/
|
||||||
if (item.ex3 != '1') {
|
if (item.ex3 != '1') {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
|
@ -213,15 +214,11 @@ const removeItem = async (item, isChild) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
|
||||||
editKeyWord(item,!isChild)
|
editKeyWord(item,!isChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Ai对话调整
|
// Ai对话调整
|
||||||
const curIndex = ref(-1)
|
const curIndex = ref(-1)
|
||||||
const isAdjust = ref(false)
|
const isAdjust = ref(false)
|
||||||
|
@ -240,11 +237,21 @@ const onEdit = (index, item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const modeType = computed(() => {
|
const modeType = ref('课标')
|
||||||
if (props.type == 1) return '课标';
|
watch(() => props.type, (newVal) => {
|
||||||
if (props.type == 2) return '教材';
|
if (newVal == 1){
|
||||||
if (props.type == 3) return '考试';
|
modeType.value = '课标'
|
||||||
})
|
}
|
||||||
|
if (newVal == 2){
|
||||||
|
modeType.value = '教材'
|
||||||
|
}
|
||||||
|
if (newVal == 2){
|
||||||
|
modeType.value = '考试'
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { immediate: false })
|
||||||
|
|
||||||
|
|
||||||
// 重新研读
|
// 重新研读
|
||||||
const params = reactive(
|
const params = reactive(
|
||||||
{
|
{
|
||||||
|
@ -256,12 +263,12 @@ const params = reactive(
|
||||||
const againResult = async (index, item) => {
|
const againResult = async (index, item) => {
|
||||||
try {
|
try {
|
||||||
childTempList.value[index].loading = true
|
childTempList.value[index].loading = true
|
||||||
params.prompt = `按照${item.name}的要求,针对${props.curNode.edustage}${props.curNode.edusubject}${modeType} 对${props.curNode.itemtitle}进行教学分析`
|
params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
||||||
const { data } = await completion(params)
|
const { data } = await completion(params)
|
||||||
let answer = data.answer
|
let answer = data.answer
|
||||||
childTempList.value[index].oldAnswer = answer
|
childTempList.value[index].oldAnswer = answer
|
||||||
childTempList.value[index].answer = getResult(answer);
|
childTempList.value[index].answer = getResult(answer);
|
||||||
onSaveTemp(item)
|
onEditSave(item)
|
||||||
} finally {
|
} finally {
|
||||||
childTempList.value[index].loading = false
|
childTempList.value[index].loading = false
|
||||||
}
|
}
|
||||||
|
@ -271,7 +278,7 @@ const getCompletion = async () => {
|
||||||
for (let item of childTempList.value) {
|
for (let item of childTempList.value) {
|
||||||
try {
|
try {
|
||||||
item.loading = true
|
item.loading = true
|
||||||
params.prompt = `按照${item.name}的要求,针对${props.curNode.edustage}${props.curNode.edusubject}${modeType} 对${props.curNode.itemtitle}进行教学分析`
|
params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
||||||
const { data } = await completion(params)
|
const { data } = await completion(params)
|
||||||
let answer = data.answer
|
let answer = data.answer
|
||||||
item.oldAnswer = answer
|
item.oldAnswer = answer
|
||||||
|
@ -283,10 +290,19 @@ const getCompletion = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存 重新研读后的结果
|
||||||
|
const onEditSave = async (item) =>{
|
||||||
|
const { res } = await editTempResult({id: item.resultId, content: item.oldAnswer})
|
||||||
|
ElMessage.success(res)
|
||||||
|
getChildTemplate()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
const onSaveTemp = (item) => {
|
const onSaveTemp = (item) => {
|
||||||
const data = {
|
const data = {
|
||||||
mainModelId: props.tempId,
|
mainModelId: curTemplate.id,
|
||||||
modelId: item.id,
|
modelId: item.id,
|
||||||
examDocld: '',
|
examDocld: '',
|
||||||
content: item.oldAnswer
|
content: item.oldAnswer
|
||||||
|
@ -324,10 +340,12 @@ emitter.on('onGetMain', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const curNode = reactive({})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTemplateList()
|
getTemplateList()
|
||||||
let jsonKey = `${modeType}-${props.curNode.edustage}-${props.curNode.edusubject}`
|
let data = sessionStore.get('subject.curNode')
|
||||||
|
Object.assign(curNode, data);
|
||||||
|
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
|
||||||
params.dataset_id = dataSetJson[jsonKey]
|
params.dataset_id = dataSetJson[jsonKey]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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) => { // 自动同步
|
||||||
|
|
|
@ -16,14 +16,11 @@ const useClassTaskStore = defineStore('classTask',{
|
||||||
{value: 6, label: "复合题"},
|
{value: 6, label: "复合题"},
|
||||||
], // 习题查询条件 - 题型
|
], // 习题查询条件 - 题型
|
||||||
entpCourseWorkGroupList: [{
|
entpCourseWorkGroupList: [{
|
||||||
Key: -1,
|
Key: 0,
|
||||||
Value: '不限',
|
Value: '不限',
|
||||||
}, {
|
}, {
|
||||||
Key: 1,
|
Key: 1,
|
||||||
Value: '真题',
|
Value: '真题',
|
||||||
}, {
|
|
||||||
Key: 0,
|
|
||||||
Value: '非真题',
|
|
||||||
}
|
}
|
||||||
], // 习题查询条件 - 题源
|
], // 习题查询条件 - 题源
|
||||||
entpCourseWorkYearList: [
|
entpCourseWorkYearList: [
|
||||||
|
|
|
@ -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]))
|
||||||
|
|
||||||
// 延时
|
// 延时
|
||||||
|
|
|
@ -97,4 +97,34 @@ const getProgress = async (id) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { createOutline, getBackGround, createPPT, getProgress, createByOutline };
|
const getBackGroundV2 = async () => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aipptV2/themeListV2", "GET");
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const createPPTV2 = async (data) => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aipptV2/createV2", "POST", data);
|
||||||
|
console.log("createOutline response:", response);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getProgressV2 = async (id) => {
|
||||||
|
try {
|
||||||
|
const response = await req(`/api/aipptV2/progressV2?sid=${id}`, "GET");
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { createOutline, getBackGround, createPPT, getProgress, getBackGroundV2, createPPTV2, getProgressV2, createByOutline };
|
||||||
|
|
|
@ -118,7 +118,7 @@ import { Search } from '@element-plus/icons-vue'
|
||||||
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
import { listEntpcoursework } from '@/api/education/entpCourseWork'
|
import { listEntpcoursework, listEntpcourseworkLocal } from '@/api/education/entpCourseWork'
|
||||||
import { listEvaluationclue } from '@/api/classTask'
|
import { listEvaluationclue } from '@/api/classTask'
|
||||||
import { delEntpcoursework, updateEntpcoursework } from "@/api/education/entpCourseWork";
|
import { delEntpcoursework, updateEntpcoursework } from "@/api/education/entpCourseWork";
|
||||||
|
|
||||||
|
@ -247,31 +247,32 @@ function Apis(key) {
|
||||||
const client = new Apis('/paht');
|
const client = new Apis('/paht');
|
||||||
const t = function(name, time) {
|
const t = function(name, time) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const queryForm = {
|
const queryForm = {
|
||||||
// 题类
|
// 题类
|
||||||
worktype: entpCourseWorkQueryParams.worktype.label == '不限' ? '' : entpCourseWorkQueryParams.worktype.label,
|
worktype: entpCourseWorkQueryParams.worktype.label,
|
||||||
// 题源 TODO 估计后端没做相应的查询处理 web端也没有返回
|
// 题源 TODO 估计后端没做相应的查询处理 web端也没有返回
|
||||||
// workgroup: entpCourseWorkQueryParams.workgroup,
|
workgroup: entpCourseWorkQueryParams.workgroup,
|
||||||
// 年份 TODO 估计后端没做相应的查询处理 web端也没有返回
|
// 年份 TODO 估计后端没做相应的查询处理 web端也没有返回
|
||||||
// yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
|
yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
|
||||||
// 关键字
|
// 关键字
|
||||||
title: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
|
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
|
||||||
|
// 课程相关参数
|
||||||
|
edustage: userStore.edustage, // this.userStore.edustage,
|
||||||
|
edusubject: userStore.edusubject, // this.userStore.edusubject,
|
||||||
|
eid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
|
||||||
|
status: "1",
|
||||||
|
editUserId: userStore.userId,
|
||||||
|
//orderby: 'concat(worktype,timestamp) DESC',
|
||||||
|
|
||||||
// 分页参数
|
// 分页参数
|
||||||
pageNum: paginationParams.pageNum,
|
pageNum: paginationParams.pageNum,
|
||||||
pageSize: paginationParams.pageSize,
|
pageSize: paginationParams.pageSize,
|
||||||
// 课程相关参数
|
}
|
||||||
edustage: userStore.edustage, // this.userStore.edustage,
|
//const entpcourseworkres = listEntpcoursework(queryForm);
|
||||||
edusubject: userStore.edusubject, // this.userStore.edusubject,
|
const entpcourseworkres = listEntpcourseworkLocal(queryForm);
|
||||||
evalid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
|
|
||||||
status: "1",
|
|
||||||
edituserid: userStore.userId,
|
|
||||||
orderby: 'concat(worktype,timestamp) DESC',
|
|
||||||
|
|
||||||
}
|
|
||||||
const entpcourseworkres = listEntpcoursework(queryForm);
|
|
||||||
|
|
||||||
resolve(entpcourseworkres);
|
resolve(entpcourseworkres);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handleQueryFromEntpCourseWork= async (queryType) => {
|
const handleQueryFromEntpCourseWork= async (queryType) => {
|
||||||
|
|
|
@ -143,7 +143,8 @@ const getCompletion = async () => {
|
||||||
for (let item of childTempList.value) {
|
for (let item of childTempList.value) {
|
||||||
try {
|
try {
|
||||||
item.loading = true
|
item.loading = true
|
||||||
params.prompt = `根据${curNode.edustage}${curNode.edusubject},提炼出${item.prompt}`
|
// params.prompt = `根据${curNode.edustage}${curNode.edusubject},提炼出${item.prompt}`
|
||||||
|
params.prompt = `按照${item.prompt}的要求,针对${curNode.edustage}${curNode.edusubject}考试 对${curNode.itemtitle}进行教学分析`
|
||||||
const { data } = await completion(params)
|
const { data } = await completion(params)
|
||||||
let answer = data.answer
|
let answer = data.answer
|
||||||
item.oldAnswer = answer
|
item.oldAnswer = answer
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -0,0 +1,380 @@
|
||||||
|
<template>
|
||||||
|
<div class="ai-container">
|
||||||
|
<el-steps style="max-width:100% " :active="activeStep" align-center>
|
||||||
|
<el-step title="生成大纲" />
|
||||||
|
<el-step title="选择模板" />
|
||||||
|
<el-step title="制作PPT" />
|
||||||
|
</el-steps>
|
||||||
|
<div class="card-box">
|
||||||
|
<el-card class="card2" v-if="activeStep === 0">
|
||||||
|
<div class="paragraphs">
|
||||||
|
{{ outputText }}
|
||||||
|
</div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 1">
|
||||||
|
<div style="padding-bottom: 10px">ppt模板选择</div>
|
||||||
|
<div class="themes">
|
||||||
|
<div v-for="item in backGroundList" :key="item.key" :style="{
|
||||||
|
padding: '20px',
|
||||||
|
paddingRight: '30px',
|
||||||
|
paddingLeft: '30px',
|
||||||
|
margin: '10px',
|
||||||
|
backgroundColor: getBackgroundColor(item.key),
|
||||||
|
borderRadius: '10px',
|
||||||
|
borderBlock: '10px solid #e6e6e6'
|
||||||
|
}" @click="chooseBackground(item.key)" @mouseenter="changeCursor('pointer')" @mouseleave="changeCursor('default')">
|
||||||
|
{{ item.name }}
|
||||||
|
<br />
|
||||||
|
<img style="width: 150px; height: auto" :src="item.thumbnail" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row class="el-row">
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>自动配图</div>
|
||||||
|
<el-switch v-model="outlineData.is_figure" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>PPT作者名:</div>
|
||||||
|
<el-input v-model="outlineData.author" style="width: 50%" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="outlineCreatePPT()">生成PPT</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 2">
|
||||||
|
<el-progress :percentage="percentage" type="circle" ></el-progress>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { creatAIPPT } from '@/utils/talkFile'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getBackGround,
|
||||||
|
createPPT,
|
||||||
|
getProgress,
|
||||||
|
} from "@/utils/ppt-request.js";
|
||||||
|
import CryptoJS from "crypto-js"
|
||||||
|
|
||||||
|
import { getSignature } from "@/utils/index.js";
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let apikey = "39d05b269fa229f431a56c21794a8ea5"
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
|
||||||
|
const outputText = ref(""); // 用于展示的大纲数据
|
||||||
|
const stagingData = ref([]); //储存的对话数据,用于多轮对话
|
||||||
|
const stagOutputText = ref(""); // 暂存大纲用于拆分
|
||||||
|
let extractedParts = ref([]) // 初步拆分
|
||||||
|
|
||||||
|
let firstArray = ref([]); //大纲的大纲等级数字部分
|
||||||
|
let secondArray = ref([]); //大纲的文字部分
|
||||||
|
|
||||||
|
|
||||||
|
const backGroundList = ref([]);
|
||||||
|
|
||||||
|
const inputTheme = ref("高中语文《沁园春雪》的授课课件"); // 输入的主题
|
||||||
|
const inputRequire = ref("") // 输入的需求
|
||||||
|
const activeStep = ref(0); // 上方进度条
|
||||||
|
const combined = ref('') // 修改完毕的大纲数据,准备传入ppt生成模型
|
||||||
|
|
||||||
|
const treeData = ref([]);
|
||||||
|
const status = ref("init");
|
||||||
|
|
||||||
|
const percentage = ref(0);
|
||||||
|
|
||||||
|
const getBackground = () => {
|
||||||
|
treeData.value = [];
|
||||||
|
getBackGround().then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
backGroundList.value = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBackgroundColor = (key) => {
|
||||||
|
return outlineData.value.theme === key ? '#83e2b6' : '#f5f5f5';
|
||||||
|
};
|
||||||
|
|
||||||
|
const outlineData = ref({
|
||||||
|
query: '', // 用户要求(最多8000字)
|
||||||
|
theme: 'auto', // ppt生成主题
|
||||||
|
author: 'AIX平台',
|
||||||
|
is_card_note: false, // 是否自动生成ppt演讲备注
|
||||||
|
is_cover_img: false, // 是否自动生成封面
|
||||||
|
is_figure: false, // 是否自动配图
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 将输入数据或返回数据存入记忆中
|
||||||
|
function updateStagingData(role, newData) {
|
||||||
|
stagingData.value.push({ role: role, content: newData });
|
||||||
|
}
|
||||||
|
//大纲直接生成ppt
|
||||||
|
const outlineCreatePPT = () => {
|
||||||
|
const newOutlineData = { ...outlineData.value, };
|
||||||
|
newOutlineData.query = outputText.value;
|
||||||
|
|
||||||
|
createPPT(newOutlineData).then((res) => {
|
||||||
|
console.log(res, "正在生成中");
|
||||||
|
activeStep.value = 2
|
||||||
|
|
||||||
|
const checkProgress = () => {
|
||||||
|
getProgress(res.sid).then((response) => {
|
||||||
|
percentage.value = response.process;
|
||||||
|
if (response && response.pptUrl && response.pptUrl.length > 4) {
|
||||||
|
// window.location.href = response.data.pptUrl;
|
||||||
|
//发消息到主进程,携带名称和URL,将URL下载下来后复制到文件列表并上传到服务
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
|
||||||
|
emit('addSuccess',res)
|
||||||
|
ElMessage.success("生成成功");
|
||||||
|
} else {
|
||||||
|
const sleepTime = 2000;
|
||||||
|
let remainingTime = sleepTime;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
remainingTime -= 100;
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
checkProgress();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProgress();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//初次对话
|
||||||
|
const addMessage = () => {
|
||||||
|
const themeValue = inputTheme.value;
|
||||||
|
const requireValue = inputRequire.value;
|
||||||
|
firstArray.value = []
|
||||||
|
secondArray.value = []
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
const combinedString = `请帮我生成一个ppt大纲,主题为:${themeValue}。具体内容要求为:${requireValue}。注意,用三个等级大纲展示,如1. 1.1 1.1.2 2. 2.1这种类型,且按照这种顺序,不要有完全相同数字等级的大纲,不要有目录`
|
||||||
|
updateStagingData("user", combinedString);
|
||||||
|
connectWebSocket(stagingData.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
let ttsWS
|
||||||
|
function connectWebSocket(data) {
|
||||||
|
outputText.value = ""; //清楚展示部分内容
|
||||||
|
status.value = "ttsing";
|
||||||
|
return getWebsocketUrl().then((url) => {
|
||||||
|
ttsWS = new WebSocket(url);
|
||||||
|
ttsWS.onopen = () => {
|
||||||
|
webSocketSend(ttsWS, data);
|
||||||
|
};
|
||||||
|
ttsWS.onmessage = (e) => {
|
||||||
|
result1(e.data);
|
||||||
|
};
|
||||||
|
ttsWS.onerror = (e) => {
|
||||||
|
status.value = "error";
|
||||||
|
console.log("WebSocket error:", e);
|
||||||
|
};
|
||||||
|
ttsWS.onclose = () => {
|
||||||
|
status.value = "init";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWebsocketUrl() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var apiKey = apikey;
|
||||||
|
var apiSecret = secret;
|
||||||
|
var url = "wss://spark-api.xf-yun.com/v4.0/chat";
|
||||||
|
|
||||||
|
var host = "spark-api.xf-yun.com";
|
||||||
|
var date = new Date().toGMTString();
|
||||||
|
var algorithm = "hmac-sha256";
|
||||||
|
var headers = "host date request-line";
|
||||||
|
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v4.0/chat HTTP/1.1`;
|
||||||
|
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
|
||||||
|
var signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||||||
|
|
||||||
|
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
|
||||||
|
var authorization = CryptoJS.enc.Base64.stringify(
|
||||||
|
CryptoJS.enc.Utf8.parse(authorizationOrigin)
|
||||||
|
);
|
||||||
|
|
||||||
|
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
|
||||||
|
console.log(url);
|
||||||
|
resolve(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function webSocketSend(ws, data) {
|
||||||
|
const params = {
|
||||||
|
header: {
|
||||||
|
app_id: appId,
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
chat: {
|
||||||
|
domain: "4.0Ultra",
|
||||||
|
temperature: 0.5,
|
||||||
|
max_tokens: 1024,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
message: {
|
||||||
|
text: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ws.send(JSON.stringify(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
function result1(resultData) {
|
||||||
|
let jsonData = JSON.parse(resultData);
|
||||||
|
outputText.value += jsonData.payload.choices.text[0].content;
|
||||||
|
const div = document.querySelector('.paragraphs');
|
||||||
|
if (div) {
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
if (jsonData.payload && jsonData.payload.usage) {
|
||||||
|
startExtraction() // 返回完毕后开始拆分大纲
|
||||||
|
console.log(firstArray.value, secondArray.value)
|
||||||
|
activeStep.value = 2
|
||||||
|
updateStagingData("assistant", outputText.value) //返回数据存入记忆池
|
||||||
|
}
|
||||||
|
if (jsonData.header.code !== 0) {
|
||||||
|
alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chooseBackground = (data) => {
|
||||||
|
outlineData.value.theme = data
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeCursor = (cursorStyle) => {
|
||||||
|
document.documentElement.style.cursor = cursorStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx"
|
||||||
|
// creatAIPPT(props.currentNode.itemtitle + '.pptx',url, props.uploadData).then((res) => {
|
||||||
|
// emit('addSuccess',res)
|
||||||
|
// })
|
||||||
|
// connectWebSocket("");
|
||||||
|
let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFilea2e0342f406e4f89b7524bf421d3fef26331634651754729404/%E9%AB%98%E4%B8%AD%E8%AF%AD%E6%96%87%E3%80%8A%E6%B2%81%E5%9B%AD%E6%98%A5%C2%B7%E9%9B%AA%E3%80%8B%E6%8E%88%E8%AF%BE%E8%A7%A3%E6%9E%90.pptx";
|
||||||
|
emit('addSuccess',{url})
|
||||||
|
props.dataList.filter(item => {
|
||||||
|
inputRequire.value += item.answer
|
||||||
|
})
|
||||||
|
getBackground();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-container {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f7f6;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card1 {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraphs {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.themes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 250px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
outline-style: none;
|
||||||
|
/* margin: 5px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col>div,
|
||||||
|
.outline-row>.el-col>div>.el-input {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash {
|
||||||
|
margin-left: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash::after {
|
||||||
|
content: "";
|
||||||
|
border-bottom: 1px dashed #000;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-1 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #c2dbf3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-2 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row {
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
:deep(.el-card__body){
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,391 @@
|
||||||
|
<template>
|
||||||
|
<div class="ai-container">
|
||||||
|
<el-steps style="max-width:100% " :active="activeStep" align-center>
|
||||||
|
<el-step title="生成大纲" />
|
||||||
|
<el-step title="选择模板" />
|
||||||
|
<el-step title="制作PPT" />
|
||||||
|
</el-steps>
|
||||||
|
<div class="card-box">
|
||||||
|
<el-card class="card2" v-if="activeStep === 0">
|
||||||
|
<div class="paragraphs">
|
||||||
|
{{ outputText }}
|
||||||
|
</div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 1">
|
||||||
|
<div style="padding-bottom: 10px">ppt模板选择</div>
|
||||||
|
<div class="themes">
|
||||||
|
<div v-for="item in backGroundList" :key="item.templateIndexId" :style="{
|
||||||
|
padding: '5px',
|
||||||
|
paddingRight: '5px',
|
||||||
|
paddingLeft: '5px',
|
||||||
|
margin: '5px',
|
||||||
|
backgroundColor: getBackgroundColor(item.templateIndexId),
|
||||||
|
borderRadius: '10px',
|
||||||
|
borderBlock: '10px solid #e6e6e6'
|
||||||
|
}" @click="chooseBackground(item.templateIndexId)" @mouseenter="changeCursor('pointer')" @mouseleave="changeCursor('default')">
|
||||||
|
{{ item.name }}
|
||||||
|
<img style="width: 150px; height: auto" :src="getBackGroundImg(item.detailImage)" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row class="el-row">
|
||||||
|
<!-- <el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>演讲备注</div>
|
||||||
|
<el-switch v-model="outlineData.is_card_note" />
|
||||||
|
</div>
|
||||||
|
</el-col>-->
|
||||||
|
<!-- <el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>生成封面</div>
|
||||||
|
<el-switch v-model="outlineData.is_cover_img" />
|
||||||
|
</div>
|
||||||
|
</el-col>-->
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>自动配图</div>
|
||||||
|
<el-switch v-model="outlineData.isFigure" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>PPT作者名:</div>
|
||||||
|
<el-input v-model="outlineData.author" style="width: 50%" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="outlineCreatePPT()">生成PPT</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 2">
|
||||||
|
<el-progress :percentage="30" type="circle" v-if="percentage === 30"></el-progress>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getBackGroundV2,
|
||||||
|
createPPTV2,
|
||||||
|
getProgressV2,
|
||||||
|
} from "@/utils/ppt-request.js";
|
||||||
|
import CryptoJS from "crypto-js"
|
||||||
|
|
||||||
|
import { getSignature } from "@/utils/index.js";
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let apikey = "39d05b269fa229f431a56c21794a8ea5"
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
|
||||||
|
const outputText = ref(""); // 用于展示的大纲数据
|
||||||
|
const stagingData = ref([]); //储存的对话数据,用于多轮对话
|
||||||
|
const stagOutputText = ref(""); // 暂存大纲用于拆分
|
||||||
|
let extractedParts = ref([]) // 初步拆分
|
||||||
|
|
||||||
|
let firstArray = ref([]); //大纲的大纲等级数字部分
|
||||||
|
let secondArray = ref([]); //大纲的文字部分
|
||||||
|
|
||||||
|
|
||||||
|
const backGroundList = ref([]);
|
||||||
|
|
||||||
|
const inputTheme = ref("高中语文《沁园春雪》的授课课件"); // 输入的主题
|
||||||
|
const inputRequire = ref("") // 输入的需求
|
||||||
|
const activeStep = ref(0); // 上方进度条
|
||||||
|
const combined = ref('') // 修改完毕的大纲数据,准备传入ppt生成模型
|
||||||
|
|
||||||
|
const treeData = ref([]);
|
||||||
|
const status = ref("init");
|
||||||
|
|
||||||
|
const percentage = ref(0);
|
||||||
|
|
||||||
|
const getBackgrounds = () => {
|
||||||
|
treeData.value = [];
|
||||||
|
getBackGroundV2().then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
backGroundList.value = res.records;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBackGroundImg = (imgUrlStr) => {
|
||||||
|
return JSON.parse(imgUrlStr).titleCoverImage
|
||||||
|
};
|
||||||
|
|
||||||
|
const outlineData = ref({
|
||||||
|
query: '', // 用户要求(最多8000字)
|
||||||
|
// templateId: 'auto', // ppt生成主题
|
||||||
|
author: 'AIX平台',
|
||||||
|
isFigure: false, // 是否自动配图
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 将输入数据或返回数据存入记忆中
|
||||||
|
function updateStagingData(role, newData) {
|
||||||
|
stagingData.value.push({ role: role, content: newData });
|
||||||
|
}
|
||||||
|
//大纲直接生成ppt
|
||||||
|
const outlineCreatePPT = () => {
|
||||||
|
const newOutlineData = { ...outlineData.value, };
|
||||||
|
newOutlineData.query = outputText.value;
|
||||||
|
|
||||||
|
createPPTV2(newOutlineData).then((res) => {
|
||||||
|
console.log(res, "正在生成中");
|
||||||
|
activeStep.value = 2
|
||||||
|
|
||||||
|
const checkProgress = () => {
|
||||||
|
getProgressV2(res.sid).then((response) => {
|
||||||
|
percentage.value = response.process;
|
||||||
|
if (response && response.pptUrl && response.pptUrl.length > 4) {
|
||||||
|
console.log('PPT',response)
|
||||||
|
// window.location.href = response.data.pptUrl;
|
||||||
|
//发消息到主进程,携带名称和URL,将URL下载下来后复制到文件列表并上传到服务
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
|
||||||
|
emit('addSuccess',res)
|
||||||
|
ElMessage.success("生成成功");
|
||||||
|
} else {
|
||||||
|
const sleepTime = 2000;
|
||||||
|
let remainingTime = sleepTime;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
remainingTime -= 100;
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
checkProgress();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProgress();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//初次对话
|
||||||
|
const addMessage = () => {
|
||||||
|
const themeValue = inputTheme.value;
|
||||||
|
const requireValue = inputRequire.value;
|
||||||
|
firstArray.value = []
|
||||||
|
secondArray.value = []
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
const combinedString = `请帮我生成一个ppt大纲,主题为:${themeValue}。具体内容要求为:${requireValue}。注意,用三个等级大纲展示,如1. 1.1 1.1.2 2. 2.1这种类型,且按照这种顺序,不要有完全相同数字等级的大纲,不要有目录`
|
||||||
|
updateStagingData("user", combinedString);
|
||||||
|
connectWebSocket(stagingData.value);
|
||||||
|
// activeStep.value = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
let ttsWS
|
||||||
|
function connectWebSocket(data) {
|
||||||
|
outputText.value = ""; //清楚展示部分内容
|
||||||
|
status.value = "ttsing";
|
||||||
|
return getWebsocketUrl().then((url) => {
|
||||||
|
ttsWS = new WebSocket(url);
|
||||||
|
ttsWS.onopen = () => {
|
||||||
|
webSocketSend(ttsWS, data);
|
||||||
|
};
|
||||||
|
ttsWS.onmessage = (e) => {
|
||||||
|
result1(e.data);
|
||||||
|
};
|
||||||
|
ttsWS.onerror = (e) => {
|
||||||
|
status.value = "error";
|
||||||
|
console.log("WebSocket error:", e);
|
||||||
|
};
|
||||||
|
ttsWS.onclose = () => {
|
||||||
|
status.value = "init";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBackgroundColor = (key) => {
|
||||||
|
return outlineData.value.templateId === key ? '#83e2b6' : '#f5f5f5';
|
||||||
|
};
|
||||||
|
|
||||||
|
function getWebsocketUrl() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var apiKey = apikey;
|
||||||
|
var apiSecret = secret;
|
||||||
|
var url = "wss://spark-api.xf-yun.com/v4.0/chat";
|
||||||
|
|
||||||
|
var host = "spark-api.xf-yun.com";
|
||||||
|
var date = new Date().toGMTString();
|
||||||
|
var algorithm = "hmac-sha256";
|
||||||
|
var headers = "host date request-line";
|
||||||
|
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v4.0/chat HTTP/1.1`;
|
||||||
|
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
|
||||||
|
var signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||||||
|
|
||||||
|
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
|
||||||
|
var authorization = CryptoJS.enc.Base64.stringify(
|
||||||
|
CryptoJS.enc.Utf8.parse(authorizationOrigin)
|
||||||
|
);
|
||||||
|
|
||||||
|
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
|
||||||
|
console.log(url);
|
||||||
|
resolve(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function webSocketSend(ws, data) {
|
||||||
|
const params = {
|
||||||
|
header: {
|
||||||
|
app_id: appId,
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
chat: {
|
||||||
|
domain: "4.0Ultra",
|
||||||
|
temperature: 0.5,
|
||||||
|
max_tokens: 1024,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
message: {
|
||||||
|
text: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ws.send(JSON.stringify(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
function result1(resultData) {
|
||||||
|
let jsonData = JSON.parse(resultData);
|
||||||
|
console.log(jsonData)
|
||||||
|
outputText.value += jsonData.payload.choices.text[0].content;
|
||||||
|
const div = document.querySelector('.paragraphs');
|
||||||
|
if (div) {
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
if (jsonData.payload && jsonData.payload.usage) {
|
||||||
|
updateStagingData("assistant", outputText.value) //返回数据存入记忆池
|
||||||
|
}
|
||||||
|
if (jsonData.header.code !== 0) {
|
||||||
|
alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chooseBackground = (data) => {
|
||||||
|
outlineData.value.templateId = data
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeCursor = (cursorStyle) => {
|
||||||
|
document.documentElement.style.cursor = cursorStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx"
|
||||||
|
// creatAIPPT(props.currentNode.itemtitle + '.pptx',url, props.uploadData).then((res) => {
|
||||||
|
// emit('addSuccess',res)
|
||||||
|
// })
|
||||||
|
// connectWebSocket("init");
|
||||||
|
props.dataList.filter(item => {
|
||||||
|
inputRequire.value += item.answer
|
||||||
|
})
|
||||||
|
getBackgrounds();
|
||||||
|
// addMessage()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-container {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f7f6;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card1 {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraphs {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.themes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 250px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
outline-style: none;
|
||||||
|
/* margin: 5px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col>div,
|
||||||
|
.outline-row>.el-col>div>.el-input {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash {
|
||||||
|
margin-left: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash::after {
|
||||||
|
content: "";
|
||||||
|
border-bottom: 1px dashed #000;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-1 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #c2dbf3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-2 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row {
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
:deep(.el-card__body){
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog class="ppt-dialog" v-model="model" :show-close="false" width="800" destroy-on-close :top="'3vh'">
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h4 :id="titleId" :class="titleClass">生成PPT(试验版)</h4>
|
||||||
|
<i class="iconfont icon-guanbi" @click="close"></i>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<AiPptist @add-success="addAiPPT" :dataList="dataList"/>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import AiPptist from './ai-pptist.vue';
|
||||||
|
const model = defineModel()
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const addAiPPT = (data) => {
|
||||||
|
emit('addSuccess', data)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.ppt-dialog){
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
.dialog-header{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.icon-guanbi {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -59,24 +59,27 @@ const getSubject = () => {
|
||||||
// 选择学段
|
// 选择学段
|
||||||
const handleUserEduStage = (item) => {
|
const handleUserEduStage = (item) => {
|
||||||
userStore.edustage = item
|
userStore.edustage = item
|
||||||
sessionStore.set('edustage',item)
|
sessionStore.set('edustageSelf',item)
|
||||||
if(item === '幼儿园'){
|
if(item === '幼儿园'){
|
||||||
// 默认语文
|
// 默认语文
|
||||||
userStore.edusubject = '语文'
|
userStore.edusubject = '语文'
|
||||||
|
sessionStore.set('edusubjectSelf','语文')
|
||||||
}
|
}
|
||||||
else if(item === '高中' && userStore.edusubject === "道德与法治"){
|
else if(item === '高中' && userStore.edusubject === "道德与法治"){
|
||||||
// 默认语文
|
// 默认语文
|
||||||
userStore.edusubject = '政治'
|
userStore.edusubject = '政治'
|
||||||
|
sessionStore.set('edusubjectSelf','政治')
|
||||||
}
|
}
|
||||||
else if(item != '高中' && userStore.edusubject === "政治"){
|
else if(item != '高中' && userStore.edusubject === "政治"){
|
||||||
// 默认语文
|
// 默认语文
|
||||||
userStore.edusubject = '道德与法治'
|
userStore.edusubject = '道德与法治'
|
||||||
|
sessionStore.set('edusubjectSelf','道德与法治')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 选择学科
|
// 选择学科
|
||||||
const handleUserEduSubject = (item) => {
|
const handleUserEduSubject = (item) => {
|
||||||
userStore.edusubject = item;
|
userStore.edusubject = item;
|
||||||
sessionStore.set('edusubject',item)
|
sessionStore.set('edusubjectSelf',item)
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSubject()
|
getSubject()
|
||||||
|
|
|
@ -165,8 +165,8 @@ setTimeout(() => {
|
||||||
function submit() {
|
function submit() {
|
||||||
proxy.$refs.userRef.validate((valid) => {
|
proxy.$refs.userRef.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
userStore.user.edusubject = sessionStore.get('edusubject') ? sessionStore.get('edusubject') : userStore.user.edusubject
|
userStore.user.edusubject = sessionStore.get('edusubjectSelf') ? sessionStore.get('edusubjectSelf') : userStore.user.edusubject
|
||||||
userStore.user.edustage = sessionStore.get('edustage') ? sessionStore.get('edustage') : userStore.user.edustage
|
userStore.user.edustage = sessionStore.get('edustageSelf') ? sessionStore.get('edustageSelf') : userStore.user.edustage
|
||||||
updateUserInfo(userStore.user).then((response) => {
|
updateUserInfo(userStore.user).then((response) => {
|
||||||
if(response.code == 200){
|
if(response.code == 200){
|
||||||
userStore.login({username:userStore.user.userName,password:userStore.user.plainpwd}).then(() => {
|
userStore.login({username:userStore.user.userName,password:userStore.user.plainpwd}).then(() => {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<el-button type="primary">生成大纲</el-button>
|
<el-button type="primary">生成大纲</el-button>
|
||||||
<el-button type="danger">生成PPT</el-button>
|
<el-button type="danger" @click="pptDialog = true">生成PPT</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-con flex">
|
<div class="right-con flex">
|
||||||
|
@ -49,6 +49,7 @@
|
||||||
</div>
|
</div>
|
||||||
<EditDialog v-model="isEdit" :item="curItem" />
|
<EditDialog v-model="isEdit" :item="curItem" />
|
||||||
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
||||||
|
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -59,8 +60,9 @@ import EditDialog from './edit-dialog.vue'
|
||||||
import AdjustDialog from './adjust-dialog.vue'
|
import AdjustDialog from './adjust-dialog.vue'
|
||||||
import { completion, tempResult } from '@/api/mode/index.js'
|
import { completion, tempResult } from '@/api/mode/index.js'
|
||||||
import { dataSetJson } from '@/utils/comm.js'
|
import { dataSetJson } from '@/utils/comm.js'
|
||||||
|
import PptDialog from '@/views/prepare/container/pptist-dialog.vue'
|
||||||
|
|
||||||
|
const pptDialog = ref(false)
|
||||||
const resultList = ref([])
|
const resultList = ref([])
|
||||||
emitter.on('changeMode', (item) => {
|
emitter.on('changeMode', (item) => {
|
||||||
console.log(item, 'item')
|
console.log(item, 'item')
|
||||||
|
@ -95,6 +97,11 @@ const params = reactive(
|
||||||
dataset_id: ''
|
dataset_id: ''
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const addAiPPT = (res) => {
|
||||||
|
//TODO res中有PPT地址
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
const conversation = async () => {
|
const conversation = async () => {
|
||||||
for (let item of resultList.value) {
|
for (let item of resultList.value) {
|
||||||
item.loading = true
|
item.loading = true
|
||||||
|
|
Loading…
Reference in New Issue