baigl #261
|
@ -26,6 +26,14 @@
|
|||
"@electron/remote": "^2.1.2",
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
||||
"@antv/x6": "^2.18.1",
|
||||
"@antv/x6-plugin-clipboard": "^2.1.6",
|
||||
"@antv/x6-plugin-dnd": "^2.1.1",
|
||||
"@antv/x6-plugin-export": "^2.1.6",
|
||||
"@antv/x6-plugin-keyboard": "^2.2.3",
|
||||
"@antv/x6-plugin-selection": "^2.2.2",
|
||||
"@antv/x6-plugin-snapline": "^2.1.7",
|
||||
"@antv/x6-plugin-transform": "^2.1.8",
|
||||
"@vue-office/docx": "^1.6.2",
|
||||
"@vue-office/excel": "^1.7.11",
|
||||
"@vue-office/pdf": "^2.0.2",
|
||||
|
|
|
@ -71,3 +71,99 @@ export function updateClasswork(data) {
|
|||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 查询evaluationclue列表
|
||||
export function listEvaluationclue(query) {
|
||||
return request({
|
||||
url: '/education/evaluationclue/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询evaluationclue详细
|
||||
export function getEvaluationclue(id) {
|
||||
return request({
|
||||
url: '/education/evaluationclue/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增evaluationclue
|
||||
export function addEvaluationclueReturnId(data) {
|
||||
return request({
|
||||
url: '/education/evaluationclue/addReturnId',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 新增evaluationclue
|
||||
export function addEvaluationclue(data) {
|
||||
return request({
|
||||
url: '/education/evaluationclue',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改evaluationclue
|
||||
export function updateEvaluationclue(data) {
|
||||
return request({
|
||||
url: '/education/evaluationclue',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除evaluationclue
|
||||
export function delEvaluationclue(id) {
|
||||
return request({
|
||||
url: '/education/evaluationclue/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增evaluationclue,保存base64图片
|
||||
export function saveBase64File(data) {
|
||||
return request({
|
||||
url: '/education/evaluationclue/saveBase64File',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 新增evaluationclue,上传
|
||||
export function saveEvaluationClueUploadFile(data) {
|
||||
return request({
|
||||
url: '/education/evaluationclue/saveUploadFile',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
export function readFile(data) {
|
||||
return fetch(import.meta.env.VITE_APP_RES_FILE_PATH + data.cluelink, {
|
||||
method: "get",
|
||||
headers: {
|
||||
'Content-Type': 'text/plain', // 请求头设置为纯文本
|
||||
'Accept': 'text/plain' // 接受头设置为纯文本
|
||||
},
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
return Promise.resolve(text);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('读取文件出错:', error);
|
||||
return Promise.reject();
|
||||
});
|
||||
/*return request({
|
||||
url: '/education/evaluationclue/readFile',
|
||||
method: 'post',
|
||||
data: data
|
||||
})*/
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
<template>
|
||||
<el-card
|
||||
class="flow-contextmenu"
|
||||
ref="flowMenu"
|
||||
v-show="visible"
|
||||
:style="menuStyle"
|
||||
body-style="padding: 12px 0 12px 12px"
|
||||
>
|
||||
<el-cascader-panel
|
||||
:props="{ expandTrigger: 'hover' }"
|
||||
:options="options"
|
||||
:border="false"
|
||||
v-model="select"
|
||||
@change="handleMenuClick"
|
||||
>
|
||||
<template v-slot="{ node, data }">
|
||||
<span class="flow-contextmenu__node">{{ data.label }}</span>
|
||||
</template>
|
||||
</el-cascader-panel>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 隐藏/显示
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 位置
|
||||
position: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
menuStyle() {
|
||||
return {
|
||||
...this.position
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible: {
|
||||
handler() {
|
||||
this.select = []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
select: [],
|
||||
options: [
|
||||
{
|
||||
value: 'name',
|
||||
label: '随机name'
|
||||
},
|
||||
{
|
||||
value: 'color',
|
||||
label: '随机color'
|
||||
},
|
||||
{
|
||||
value: 'remove',
|
||||
label: '删除'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleMenuClick(action) {
|
||||
this.$emit('onMenuClick', action)
|
||||
this.$emit('update:visible', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flow-contextmenu {
|
||||
min-width: 150px;
|
||||
position: fixed;
|
||||
user-select: none;
|
||||
z-index: 99;
|
||||
:deep(.el-cascader-menu) {
|
||||
min-width: auto;
|
||||
.el-cascader-node {
|
||||
z-index: 10;
|
||||
margin-right: 10px;
|
||||
padding-right: 12px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
}
|
||||
.flow-contextmenu__node {
|
||||
display: inline-block;
|
||||
min-width: 60px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-drawer
|
||||
:model-value="drawer"
|
||||
:title="drawerTitle"
|
||||
:modal="false"
|
||||
:before-close="handleClose"
|
||||
direction="rtl">
|
||||
<el-form :model="form" size="large">
|
||||
<el-form-item label="节点名称">
|
||||
<el-input v-model="form.label" />
|
||||
</el-form-item>
|
||||
<el-form-item label="节点背景色">
|
||||
<el-color-picker v-model="form.bgcolor" />
|
||||
</el-form-item>
|
||||
<el-form-item label="节点边框颜色">
|
||||
<el-color-picker v-model="form.borderColor"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="节点文字颜色">
|
||||
<el-color-picker v-model="form.textColor"/>
|
||||
</el-form-item>
|
||||
<div class="save-row">
|
||||
<el-space :size="30">
|
||||
<el-button type="primary" @click="updateNode" size="default">保存</el-button>
|
||||
<el-button @click="closeDrawer" size="default">关闭</el-button>
|
||||
</el-space>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'flow-drawer',
|
||||
props: {
|
||||
drawerTitle: {
|
||||
type: String,
|
||||
default: '节点编辑'
|
||||
},
|
||||
drawer: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
default: ()=>{
|
||||
return {
|
||||
label: '',
|
||||
bgcolor: '',
|
||||
borderColor: '',
|
||||
textColor: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleClose(done){
|
||||
this.closeDrawer()
|
||||
done();
|
||||
},
|
||||
closeDrawer(){
|
||||
this.$emit('closeDrawer', false)
|
||||
},
|
||||
updateNode(){
|
||||
this.$emit('updateNode', this.form)
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-form-item__label) {
|
||||
font-weight: normal;
|
||||
}
|
||||
.save-row {
|
||||
margin-top: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,235 @@
|
|||
<template>
|
||||
<div class="flow-library">
|
||||
<div class="flow-library-title">节点库</div>
|
||||
<div class="flow-library-list">
|
||||
<div class="node-item" v-for="item in list" :key="item.name" :data-shape="item.shape"
|
||||
:data-name="item.name"
|
||||
@mousedown.stop="handleonAddNode"
|
||||
@touchstart.stop="handleonAddNode">
|
||||
<div
|
||||
:class="item.class"
|
||||
>
|
||||
<template v-if="item.class == 'parallelogram' || item.class == 'diamond'">
|
||||
<div :class="item.class + '-text'"> {{ item.name }} </div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ item.name }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <el-space wrap :size="30" class="ant-flow-save">
|
||||
<el-button type="success" @click="handleSave('img')">下载为图片</el-button>
|
||||
<el-button type="primary" @click="handleSave">保存</el-button>
|
||||
</el-space> -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'FlowLibrary',
|
||||
data() {
|
||||
return {
|
||||
// 过滤数据
|
||||
list: [
|
||||
{
|
||||
name: '开始',
|
||||
shape: 'custom-rect',
|
||||
class: 'elliptic'
|
||||
},
|
||||
{
|
||||
name: '过程',
|
||||
shape: 'custom-rect',
|
||||
class: 'rectangle'
|
||||
},
|
||||
{
|
||||
name: '可选过程',
|
||||
shape: 'custom-rect',
|
||||
class: 'quadrilateral'
|
||||
},
|
||||
{
|
||||
name: '决策',
|
||||
shape: 'custom-polygon',
|
||||
class: 'diamond'
|
||||
},
|
||||
{
|
||||
name: '数据',
|
||||
shape: 'custom-polygon',
|
||||
class: 'parallelogram'
|
||||
},
|
||||
{
|
||||
name: '连接',
|
||||
shape: 'custom-circle',
|
||||
class: 'round'
|
||||
},
|
||||
|
||||
],
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleonAddNode(e) {
|
||||
this.$emit('onAddNode', e)
|
||||
},
|
||||
// 保存
|
||||
handleSave(str){
|
||||
this.$emit('handleSave', str)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@mixin nodeColor {
|
||||
background: #EFF4FF;
|
||||
display: flex;
|
||||
border: solid 1px #5F95FF;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
}
|
||||
.flow-library {
|
||||
user-select: none;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
border-right: 1px solid #dcdfe6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
padding: 0 15px;
|
||||
&-title {
|
||||
line-height: 48px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 8px 0 8px 16px;
|
||||
}
|
||||
|
||||
&-item {
|
||||
width: 72px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
margin-right: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&__img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-top: 8px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
&--setting-shape {
|
||||
background-size: 32px;
|
||||
background-color: #5f95ff;
|
||||
background-position: 50% 15%;
|
||||
|
||||
.flow-library-item__name {
|
||||
position: absolute;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
bottom: 4px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
&-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-flow-save {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.node-item{
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.elliptic{
|
||||
width: 70px;
|
||||
height: 35px;
|
||||
border-radius: 20px;
|
||||
@include nodeColor;
|
||||
|
||||
}
|
||||
.quadrilateral{
|
||||
width: 60px;
|
||||
height: 35px;
|
||||
@include nodeColor;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.rectangle{
|
||||
width: 80px;
|
||||
height: 35px;
|
||||
@include nodeColor;
|
||||
}
|
||||
.round{
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border-radius: 50%;
|
||||
@include nodeColor;
|
||||
}
|
||||
.parallelogram{
|
||||
width: 55px;
|
||||
height: 35px;
|
||||
transform: skewX(-45deg);
|
||||
@include nodeColor;
|
||||
position: relative;
|
||||
line-height: 35px;
|
||||
.parallelogram-text{
|
||||
transform: skewX(45deg);
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.diamond {
|
||||
@include nodeColor;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
transform: rotateZ(45deg)skew(-12deg, -12deg);
|
||||
.diamond-text{
|
||||
transform: rotate(-45deg)skew(0deg,0deg);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,333 @@
|
|||
|
||||
import { Shape } from '@antv/x6'
|
||||
/**
|
||||
* @desc 初始化面板配置
|
||||
* @param check 查看模式
|
||||
*/
|
||||
export const graphOptions = (check = false) => {
|
||||
return {
|
||||
container: document.getElementById('flow-container'),
|
||||
// 定制节点和边的交互行为 ==> boolean 节点或边是否可交互
|
||||
interacting: check
|
||||
? {
|
||||
nodeMovable: false,
|
||||
edgeMovable: false,
|
||||
magnetConnectable: false,
|
||||
vertexDeletable: false
|
||||
}
|
||||
: true,
|
||||
// 对齐线
|
||||
snapline: true,
|
||||
// 显示网格 // 'dot' | 'fixedDot' | 'mesh'
|
||||
grid: {
|
||||
visible: true,
|
||||
size: 20, // 网格大小
|
||||
type: 'mesh',
|
||||
args: {
|
||||
color: '#e9e9e9',
|
||||
thickness: 2 // 网格线宽度/网格点大小
|
||||
}
|
||||
},
|
||||
// 平移
|
||||
panning: true,
|
||||
// 滚轮缩放 MouseWheel
|
||||
mousewheel: {
|
||||
enabled: true,
|
||||
zoomAtMousePosition: true,
|
||||
modifiers: ['ctrl', 'meta'],
|
||||
maxScale: 3,
|
||||
minScale: 0.3
|
||||
},
|
||||
// 连线规则
|
||||
connecting: {
|
||||
// 路由类型
|
||||
router: {
|
||||
// 连线类型在此修改
|
||||
// 曼哈顿路由 'manhattan' 路由是正交路由 'orth' 的智能版本,该路由由水平或垂直的正交线段组成,并自动避开路径上的其他节点(障碍)。
|
||||
name: 'manhattan',
|
||||
args: {
|
||||
padding: 1
|
||||
}
|
||||
},
|
||||
// 圆角连接器,将起点、路由点、终点通过直线按顺序连接,并在线段连接处通过圆弧连接(倒圆角)。
|
||||
connector: {
|
||||
name: 'rounded',
|
||||
args: {
|
||||
radius: 8
|
||||
}
|
||||
},
|
||||
anchor: 'center',
|
||||
connectionPoint: 'anchor',
|
||||
// 是否允许连接到画布空白位置的点,默认为 true。
|
||||
allowBlank: false,
|
||||
// 距离节点或者连接桩 20px 时会触发自动吸附
|
||||
snap: {
|
||||
radius: 20
|
||||
},
|
||||
// 拽出新的边
|
||||
createEdge() {
|
||||
return new Shape.Edge({
|
||||
// markup: [
|
||||
// {
|
||||
// tagName: 'path',
|
||||
// selector: 'stroke'
|
||||
// }
|
||||
// ],
|
||||
// connector: { name: 'rounded' },
|
||||
// attrs: {
|
||||
// stroke: {
|
||||
// fill: 'none',
|
||||
// connection: true,
|
||||
// strokeWidth: 4,
|
||||
// strokeLinecap: 'round',
|
||||
// stroke: '#666'
|
||||
// }
|
||||
// },
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#A2B1C3',
|
||||
strokeWidth: 3,
|
||||
targetMarker: {
|
||||
name: 'block',
|
||||
width: 12,
|
||||
height: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
zIndex: 0
|
||||
})
|
||||
},
|
||||
validateConnection({ targetMagnet }) {
|
||||
return !!targetMagnet
|
||||
}
|
||||
},
|
||||
// 连线高亮
|
||||
highlighting: {
|
||||
// 连线过程中,自动吸附到链接桩时被使用。
|
||||
magnetAdsorbed: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
attrs: {
|
||||
width: 12,
|
||||
r: 6,
|
||||
magnet: true,
|
||||
stroke: '#008CFF',
|
||||
strokeWidth: 2,
|
||||
fill: '#0F67FF'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
rotating: false, // 不能旋转
|
||||
keyboard: !check, // 按键操作
|
||||
clipboard: true, // 剪切板
|
||||
autoResize: true,
|
||||
onToolItemCreated({ tool }) {
|
||||
const options = tool.options
|
||||
if (options && options.index % 2 === 1) {
|
||||
tool.setAttrs({ fill: 'red' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 链接桩样式
|
||||
export const portStyle = {
|
||||
// width: 12,
|
||||
// r: 6, // 半径
|
||||
// // 当 magnet 属性为 true 时,表示该元素可以被链接,即在连线过程中可以被当做连线的起点或终点,与链接桩类似。
|
||||
// magnet: true,
|
||||
// stroke: '#008CFF',
|
||||
// strokeWidth: 2,
|
||||
// fill: '#fff',
|
||||
// zIndex: 1,
|
||||
// style: {
|
||||
// visibility: 'hidden',
|
||||
// },
|
||||
r: 6,
|
||||
magnet: true,
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 2,
|
||||
fill: '#fff',
|
||||
style: {
|
||||
visibility: 'hidden',
|
||||
},
|
||||
}
|
||||
|
||||
// 链接桩配置
|
||||
export const ports = {
|
||||
// 设置链接桩分组
|
||||
groups: {
|
||||
top: {
|
||||
// 定义连接柱的位置,如果不配置,将显示为默认样式
|
||||
position: 'top',
|
||||
// 定义连接柱的样式
|
||||
attrs: {
|
||||
circle: {
|
||||
...portStyle
|
||||
}
|
||||
}
|
||||
},
|
||||
right: {
|
||||
position: 'right',
|
||||
attrs: {
|
||||
circle: {
|
||||
...portStyle
|
||||
}
|
||||
}
|
||||
},
|
||||
bottom: {
|
||||
position: 'bottom',
|
||||
attrs: {
|
||||
circle: {
|
||||
...portStyle
|
||||
}
|
||||
}
|
||||
},
|
||||
left: {
|
||||
position: 'left',
|
||||
attrs: {
|
||||
circle: {
|
||||
...portStyle
|
||||
}
|
||||
}
|
||||
},
|
||||
absolute: {
|
||||
position: 'absolute',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 6,
|
||||
magnet: true,
|
||||
stroke: '#008CFF',
|
||||
strokeWidth: 2,
|
||||
fill: '#fff'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 链接桩
|
||||
items: [
|
||||
{
|
||||
group: 'top'
|
||||
},
|
||||
{
|
||||
group: 'right'
|
||||
},
|
||||
{
|
||||
group: 'bottom'
|
||||
},
|
||||
{
|
||||
group: 'left'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 动态计算宽高比
|
||||
export const transformToPercent = (target, sum, font) => {
|
||||
// https://x6.antv.vision/zh/docs/tutorial/intermediate/attrs
|
||||
// 相对节点的大小
|
||||
const percent = (target / sum).toFixed(2) * 100
|
||||
return `${percent}${font ? 'px' : '%'}`
|
||||
}
|
||||
|
||||
// 注册节点配置信息 注册以后就可以像使用内置节点那样使用该节点
|
||||
export const registerNodeOpeions = {
|
||||
'custom-rect': {
|
||||
inherit: 'rect',
|
||||
width: 70,
|
||||
height: 40,
|
||||
attrs: {
|
||||
body: {
|
||||
strokeWidth: 1,
|
||||
stroke: '#5F95FF',
|
||||
fill: '#EFF4FF',
|
||||
},
|
||||
text: {
|
||||
fontSize: 12,
|
||||
fill: '#262626',
|
||||
},
|
||||
},
|
||||
ports: { ...ports },
|
||||
},
|
||||
'custom-polygon' : {
|
||||
inherit: 'polygon',
|
||||
width: 70,
|
||||
height: 40,
|
||||
attrs: {
|
||||
body: {
|
||||
strokeWidth: 1,
|
||||
stroke: '#5F95FF',
|
||||
fill: '#EFF4FF',
|
||||
},
|
||||
text: {
|
||||
fontSize: 12,
|
||||
fill: '#262626',
|
||||
},
|
||||
},
|
||||
ports: {
|
||||
...ports,
|
||||
items: [
|
||||
{
|
||||
group: 'top',
|
||||
},
|
||||
{
|
||||
group: 'bottom',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
'custom-circle' : {
|
||||
inherit: 'circle',
|
||||
width: 50,
|
||||
height: 50,
|
||||
attrs: {
|
||||
body: {
|
||||
strokeWidth: 1,
|
||||
stroke: '#5F95FF',
|
||||
fill: '#EFF4FF',
|
||||
},
|
||||
text: {
|
||||
fontSize: 12,
|
||||
fill: '#262626',
|
||||
},
|
||||
},
|
||||
ports: { ...ports },
|
||||
},
|
||||
}
|
||||
|
||||
// 图形变换配置
|
||||
export const transFormOptions = {
|
||||
// 调整尺寸
|
||||
resizing: {
|
||||
enabled: true,
|
||||
minWidth: 1,
|
||||
maxWidth: 200,
|
||||
minHeight: 1,
|
||||
maxHeight: 150,
|
||||
restrict: false,
|
||||
preserveAspectRatio: false,
|
||||
},
|
||||
// 调整角度---旋转
|
||||
rotating: {
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
// 拖动添加节点样式配置
|
||||
export const addNodeAttrStyle = {
|
||||
'可选过程': {
|
||||
rx: 6,
|
||||
ry: 6,
|
||||
},
|
||||
'开始': {
|
||||
rx: 20,
|
||||
ry: 26,
|
||||
},
|
||||
'决策': {
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
},
|
||||
'数据': {
|
||||
refPoints: '10,0 40,0 30,20 0,20',
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,391 @@
|
|||
<template>
|
||||
<div v-loading="flowLoading" class="ant-flow" :style="{ height: 70 + 'vh' }">
|
||||
<!-- 左侧节点库 -->
|
||||
<flow-library @onAddNode="onAddNode" />
|
||||
<!--画布-->
|
||||
<div id="flow-container"></div>
|
||||
<!--右侧抽屉-->
|
||||
<FlowDrawer :drawer="drawer" :form="form" @closeDrawer="closeDrawer" @updateNode="updateNode" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Graph } from '@antv/x6'
|
||||
// 快捷键
|
||||
import { Keyboard } from '@antv/x6-plugin-keyboard'
|
||||
// 通过拖拽交互往画布中添加节点
|
||||
import { Dnd } from '@antv/x6-plugin-dnd'
|
||||
// 框选
|
||||
import { Selection } from '@antv/x6-plugin-selection'
|
||||
// 图形变换
|
||||
import { Transform } from '@antv/x6-plugin-transform'
|
||||
// 对齐线
|
||||
import { Snapline } from '@antv/x6-plugin-snapline'
|
||||
// 剪切板
|
||||
import { Clipboard } from '@antv/x6-plugin-clipboard'
|
||||
// 导出
|
||||
import { Export } from '@antv/x6-plugin-export'
|
||||
|
||||
import FlowLibrary from '@/components/Flowchart/FlowLibrary.vue'
|
||||
import FlowContentMenu from '@/components/Flowchart/FlowContentMenu.vue'
|
||||
import FlowDrawer from '@/components/Flowchart/FlowDrawer.vue'
|
||||
import { graphOptions, ports, registerNodeOpeions, transFormOptions, addNodeAttrStyle } from '@/components/Flowchart/config'
|
||||
|
||||
let graph = null
|
||||
let dnd = null
|
||||
let selector = null
|
||||
|
||||
export default {
|
||||
name: 'X6',
|
||||
components: { FlowContentMenu, FlowLibrary, FlowDrawer },
|
||||
title: 'Antv/X6流程图',
|
||||
props: {
|
||||
flowHeight: {
|
||||
type: Number,
|
||||
default: 800
|
||||
},
|
||||
dataSource: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawer: false,
|
||||
form: {
|
||||
label: '',
|
||||
bgcolor: '',
|
||||
borderColor: '',
|
||||
textColor: ''
|
||||
},
|
||||
currentNode: null,
|
||||
flowLoading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataSource(newVal){
|
||||
this.flowLoading = true
|
||||
this.updateConfigure(newVal)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.flowLoading = true
|
||||
this.$nextTick(()=>{
|
||||
if(graph){
|
||||
graph.clearCells()
|
||||
|
||||
}
|
||||
this.init()
|
||||
})
|
||||
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.destoryFlow()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 初始化画布
|
||||
*/
|
||||
init() {
|
||||
// 实例化
|
||||
graph = new Graph(graphOptions(false))
|
||||
|
||||
// 使用插件
|
||||
this.initPlugin()
|
||||
|
||||
// 注册自定义节点
|
||||
this.registerNode()
|
||||
|
||||
// 读取配置
|
||||
graph.fromJSON(this.dataSource)
|
||||
|
||||
// 居中展示
|
||||
graph.centerContent()
|
||||
|
||||
// 快捷键
|
||||
this.initEvent()
|
||||
|
||||
// 实例化拖动添加节点
|
||||
dnd = new Dnd({
|
||||
target: graph,
|
||||
scaled: false,
|
||||
})
|
||||
this.flowLoading = false
|
||||
},
|
||||
/**
|
||||
* 注册自定义节点
|
||||
*/
|
||||
registerNode() {
|
||||
Graph.registerNode('custom-rect',registerNodeOpeions['custom-rect'], true)
|
||||
Graph.registerNode('custom-polygon',registerNodeOpeions['custom-polygon'], true)
|
||||
Graph.registerNode('custom-circle',registerNodeOpeions['custom-circle'], true)
|
||||
},
|
||||
/**
|
||||
* 快捷键与事件
|
||||
*/
|
||||
initEvent() {
|
||||
// 点击...
|
||||
graph.on('cell:click', e => {
|
||||
this.showPorts(false)
|
||||
})
|
||||
|
||||
// 双击动态添加链接桩
|
||||
graph.on('node:dblclick', e => {
|
||||
const { node } = e
|
||||
|
||||
this.currentNode = node
|
||||
this.form.label = node.attr('text/text')
|
||||
this.form.bgcolor = node.attr('body/fill')
|
||||
this.form.borderColor = node.attr('body/stroke')
|
||||
this.form.textColor = node.attr('text/fill')
|
||||
this.drawer = true
|
||||
})
|
||||
|
||||
// Edge工具
|
||||
graph.on('cell:mouseenter', ({ cell }) => {
|
||||
if (cell.isEdge()) {
|
||||
// https://x6.antv.vision/zh/docs/tutorial/intermediate/tools
|
||||
// 1、vertices 路径点工具,在路径点位置渲染一个小圆点,
|
||||
// 2、segments 线段工具。在边的每条线段的中心渲染一个工具条,可以拖动工具条调整线段两端的路径点的位置。
|
||||
cell.addTools([
|
||||
'vertices',
|
||||
'segments',
|
||||
{
|
||||
name: 'button-remove',
|
||||
args: {
|
||||
x: '30%',
|
||||
y: '50%'
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
})
|
||||
graph.on('cell:mouseleave', ({ cell }) => {
|
||||
if (cell.isEdge()) {
|
||||
cell.removeTool('vertices')
|
||||
cell.removeTool('segments')
|
||||
cell.removeTool('button-remove')
|
||||
}
|
||||
})
|
||||
|
||||
// 链接桩控制
|
||||
graph.on('node:mouseenter', () => {
|
||||
this.showPorts(true)
|
||||
})
|
||||
graph.on('node:mouseleave', () => {
|
||||
this.showPorts(false)
|
||||
})
|
||||
|
||||
// 点击画布空白区域
|
||||
graph.on('blank:click', () => {
|
||||
graph.cleanSelection && graph.cleanSelection()
|
||||
})
|
||||
|
||||
/**
|
||||
* 基础操作S
|
||||
*/
|
||||
|
||||
|
||||
graph.bindKey(['meta+c', 'ctrl+c'], () => {
|
||||
const cells = graph.getSelectedCells()
|
||||
if (cells.length) {
|
||||
graph.copy(cells)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
graph.bindKey(['meta+x', 'ctrl+x'], () => {
|
||||
const cells = graph.getSelectedCells()
|
||||
if (cells.length) {
|
||||
graph.cut(cells)
|
||||
}
|
||||
return false
|
||||
})
|
||||
graph.bindKey(['meta+v', 'ctrl+v'], () => {
|
||||
if (!graph.isClipboardEmpty()) {
|
||||
const cells = graph.paste({ offset: 32 })
|
||||
graph.cleanSelection()
|
||||
graph.select(cells)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
//undo redo
|
||||
graph.bindKey(['meta+z', 'ctrl+z'], () => {
|
||||
if (graph.history.canUndo()) {
|
||||
graph.history.undo()
|
||||
}
|
||||
return false
|
||||
})
|
||||
graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
|
||||
if (graph.history.canRedo()) {
|
||||
graph.history.redo()
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// select all
|
||||
graph.bindKey(['meta+shift+a', 'ctrl+shift+a'], () => {
|
||||
const nodes = graph.getNodes()
|
||||
if (nodes) {
|
||||
graph.select(nodes)
|
||||
}
|
||||
})
|
||||
|
||||
// delete
|
||||
graph.bindKey(['backspace', 'delete'], () => {
|
||||
// 删除选中的元素
|
||||
const cells = graph.getSelectedCells()
|
||||
if (cells.length) {
|
||||
graph.removeCells(cells)
|
||||
}
|
||||
})
|
||||
|
||||
// zoom
|
||||
graph.bindKey(['ctrl+1', 'meta+1'], () => {
|
||||
const zoom = graph.zoom()
|
||||
if (zoom < 1.5) {
|
||||
graph.zoom(0.1)
|
||||
}
|
||||
})
|
||||
graph.bindKey(['ctrl+2', 'meta+2'], () => {
|
||||
const zoom = graph.zoom()
|
||||
if (zoom > 0.5) {
|
||||
graph.zoom(-0.1)
|
||||
}
|
||||
})
|
||||
/**
|
||||
* 基础操作E
|
||||
*/
|
||||
},
|
||||
// 连接桩显示/隐藏
|
||||
showPorts(show) {
|
||||
const container = document.getElementById('flow-container')
|
||||
const ports = container.querySelectorAll('.x6-port-body')
|
||||
for (let i = 0, len = ports.length; i < len; i = i + 1) {
|
||||
ports[i].style.visibility = show ? 'visible' : 'hidden'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 使用插件
|
||||
*/
|
||||
initPlugin(){
|
||||
graph.use(
|
||||
new Keyboard({
|
||||
enabled: true,
|
||||
global: true,
|
||||
}),
|
||||
).use(new Selection({
|
||||
multiple: true,
|
||||
showNodeSelectionBox: true,
|
||||
})).use(new Snapline({
|
||||
enabled: true,
|
||||
clean: false,
|
||||
})).use(new Transform(transFormOptions)).use(new Clipboard({
|
||||
enabled: true,
|
||||
})).use(new Export())
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加节点
|
||||
*/
|
||||
onAddNode(e) {
|
||||
const target = e && e.target.closest('.node-item')
|
||||
if (target) {
|
||||
const name = target.getAttribute('data-name')
|
||||
const shape = target.getAttribute('data-shape')
|
||||
|
||||
let nodeOptions = {
|
||||
shape,
|
||||
label: name,
|
||||
ports: { ...ports },
|
||||
}
|
||||
if(addNodeAttrStyle[name]){
|
||||
nodeOptions.attrs = {
|
||||
body: addNodeAttrStyle[name]
|
||||
}
|
||||
}
|
||||
const newNode = graph.createNode(nodeOptions)
|
||||
dnd.start(newNode, e)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 保存
|
||||
*/
|
||||
handleSave() {
|
||||
const res = graph.toJSON()
|
||||
return res
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭抽屉
|
||||
*/
|
||||
closeDrawer(data) {
|
||||
this.drawer = data
|
||||
},
|
||||
/**
|
||||
* 更新节点-节点名称/背景色/边框/节点颜色
|
||||
*/
|
||||
updateNode(form) {
|
||||
this.currentNode.attr('text/text', form.label)
|
||||
this.currentNode.attr('text/fill', form.textColor)
|
||||
this.currentNode.attr(`body/fill`, form.bgcolor)
|
||||
this.currentNode.attr(`body/stroke`, form.borderColor)
|
||||
this.drawer = false
|
||||
},
|
||||
updateConfigure(data) {
|
||||
graph.fromJSON(data)
|
||||
graph.centerContent()
|
||||
this.flowLoading = false
|
||||
},
|
||||
destoryFlow() {
|
||||
// 画布的销毁以及回收
|
||||
graph && graph.dispose()
|
||||
graph = null
|
||||
dnd = null
|
||||
selector = null
|
||||
},
|
||||
/**
|
||||
* 获取PNG
|
||||
*/
|
||||
getBase64Png(){
|
||||
return new Promise((resolve, reject)=>{
|
||||
graph.toPNG((dataUri)=>{
|
||||
resolve(dataUri)
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.ant-flow {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
#flow-container {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
}
|
||||
#stencil{
|
||||
user-select: none;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
border-right: 1px solid #dcdfe6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
|
@ -19,6 +19,7 @@
|
|||
<el-row class="middle">
|
||||
<el-col :span="24" style="height: 100%; overflow: hidden;">
|
||||
<el-form-item label="作业资源:" class="el-form-work-list">
|
||||
<!-- 左侧作业资源 -->
|
||||
<el-col :span="15" class="work-left">
|
||||
<!-- 习题训练 -->
|
||||
<div v-if="classWorkForm.worktype=='习题训练'" style="height: 100%; display: flex; flex-direction: column;">
|
||||
|
@ -114,37 +115,38 @@
|
|||
@pagination="getPaginationList" />
|
||||
</div> -->
|
||||
</div>
|
||||
<!-- <div v-if="classWorkForm.worktype!='习题训练'">
|
||||
<!-- 非习题训练:常规作业、 -->
|
||||
<div v-if="classWorkForm.worktype!='习题训练'">
|
||||
<div :style="{ 'overflow': 'auto'}">
|
||||
<template v-if="classWorkForm.worktype!='常规作业'">
|
||||
<template v-for="(item, index) in workResource.teachResourceList" :key="item">
|
||||
<div v-if="item.worktype==classWorkForm.worktype" style="border-bottom: 1px dotted;display: flex;justify-content: space-between;">
|
||||
<div style="margin-bottom: 5px; padding-left: 15px;display: flex;flex-direction: row;align-items: center;">
|
||||
<div style="font-size: 1.2em; font-weight: bold;margin-right: 5px">{{ item.worktype }}</div>
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<div style="color: silver; display: flex;align-items: center;">
|
||||
<el-image :src="item.userheadimgurl" style="height: 30px; width: 30px; border-radius: 50%;"></el-image>
|
||||
<div style="line-height: 18px">
|
||||
<div style="margin-top: 5px; margin-left: 5px">{{ item.username }} 来自{{ item.parententpname }} {{ item.userentpname }}</div>
|
||||
<div style="margin-top: 5px; margin-left: 5px">{{ item.timestamp }}</div>
|
||||
<template v-if="classWorkForm.worktype!='常规作业'">
|
||||
<template v-for="(item, index) in workResource.teachResourceList" :key="item">
|
||||
<div v-if="item.worktype==classWorkForm.worktype" style="border-bottom: 1px dotted;display: flex;justify-content: space-between;">
|
||||
<div style="margin-bottom: 5px; padding-left: 15px;display: flex;flex-direction: row;align-items: center;">
|
||||
<div style="font-size: 1.2em; font-weight: bold;margin-right: 5px">{{ item.worktype }}</div>
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<div style="color: silver; display: flex;align-items: center;">
|
||||
<el-image :src="item.userheadimgurl" style="height: 30px; width: 30px; border-radius: 50%;"></el-image>
|
||||
<div style="line-height: 18px">
|
||||
<div style="margin-top: 5px; margin-left: 5px">{{ item.username }} 来自{{ item.parententpname }} {{ item.userentpname }}</div>
|
||||
<div style="margin-top: 5px; margin-left: 5px">{{ item.timestamp }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex;align-items: center; justify-content: space-around; margin-left: 15px; margin-right: 15px;">
|
||||
<el-button icon="Search" @click="prevRead(item)">预览</el-button>
|
||||
<el-button icon="FolderAdd" @click="handleClassWorkAddOfResource(item)">添加到作业</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex;align-items: center; justify-content: space-around; margin-left: 15px; margin-right: 15px;">
|
||||
<el-button @click="prevRead(item)" icon="Search">预览</el-button>
|
||||
<el-button @click="handleClassWorkAddOfResource(item)" icon="FolderAdd">添加到作业</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="classWorkForm.worktype =='常规作业'">
|
||||
<div class="upload-homework" v-loading="fileLoading">
|
||||
<FileUpload v-model="fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
|
||||
</div>
|
||||
</template>
|
||||
<!-- <template v-if="classWorkForm.worktype =='常规作业'">
|
||||
<div class="upload-homework" v-loading="fileLoading">
|
||||
<FileUpload v-model="fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
|
||||
</div>
|
||||
</template> -->
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div v-if="classWorkForm.activeIndex==3">
|
||||
<el-row>
|
||||
<el-col :span="20">
|
||||
|
@ -196,6 +198,8 @@
|
|||
</div>
|
||||
</div> -->
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧选中的作业资源 -->
|
||||
<el-col :span="9" class="work-right">
|
||||
<div v-if="classWorkForm.worktype=='习题训练'" :style="{height: '100%', 'overflow': 'auto', 'border':'1px dotted blue','border-radius':'5px', 'background-color': '#f7f7f7'}">
|
||||
<template v-for="(item,index) in classWorkForm.quizlist" :key="item.id">
|
||||
|
@ -214,18 +218,20 @@
|
|||
|
||||
<div v-if="classWorkForm.worktype!='习题训练'" :style="{'overflow': 'auto', 'border':'1px dotted blue','border-radius':'5px', 'background-color': '#f7f7f7'}">
|
||||
<div style="margin: 5px; background-color: white">
|
||||
<template v-for="(item,index) in chooseWorkLists" :key="item.id">
|
||||
<template v-for="(item) in chooseWorkLists" :key="item.id">
|
||||
<div v-if="item.worktype==classWorkForm.worktype">
|
||||
<div style="margin-bottom: 5px; padding-left: 15px;display: flex;flex-direction: row;align-items: center;">
|
||||
<div style="font-size: 1.2em; font-weight: bold;margin-right: 5px">{{ item.worktype }}</div>
|
||||
<div style="display: flex;align-items: center; justify-content: space-around; margin-left: 15px; margin-right: 15px;flex: 1;">
|
||||
<div class="choose-work">
|
||||
<div class="choose-work-title">{{ item.worktype }}</div>
|
||||
<div class="choose-work-content">
|
||||
<div style="color: silver; display: flex;align-items: center;flex: 1;">
|
||||
<el-form-item label="分值">
|
||||
<el-input-number v-model="item.score" :min="1" :max="100" size="small"></el-input-number >
|
||||
</el-form-item>
|
||||
<div style="display: flex;align-items: center;flex: 1;justify-content: flex-end;">
|
||||
<el-button @click="prevRead(item)">预览</el-button>
|
||||
<el-button type="danger" @click="deleteClassWorkAddOfResource(item)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-button @click="prevRead(item)" icon="Search">预览</el-button>
|
||||
<el-button @click="deleteClassWorkAddOfResource(item)" type="danger" icon="Delete">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -252,6 +258,26 @@
|
|||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<!-- 预览框 -->
|
||||
<el-dialog v-if="prevReadMsg.visible" v-model="prevReadMsg.visible" class="prev-read-zy-wrap" width="90%" style="height: 80vh" append-to-body>
|
||||
<!-- <div v-if="prevReadMsg.type=='课标研读'" style="height: 100%;">
|
||||
<standard book-type="课标研读" :show-cata="true" :show-tools="false" :course-obj="courseObj" :bookdatahtml="versionObj.bookdata" :teachResObj="activeTeachResOfStandard"></standard>
|
||||
</div>
|
||||
<div v-if="prevReadMsg.type=='目标设定'" style="height: 100%;display: flex;">
|
||||
<degreeevolution :courseObj="courseObj" :show-class="true" :teachResObj="activeTeachResOfStandard" :attainmentList="attainmentList" :courseQualityList="courseQualityList"/>
|
||||
</div>
|
||||
<div v-if="prevReadMsg.type=='教材研读'" style="height: 100%;">
|
||||
<standard book-type="教材研读" :course-obj="courseObj" :show-tools="false" :bookdatahtml="versionObj.bookdata" :teachResObj="activeTeachResOfStandard"></standard>
|
||||
</div> -->
|
||||
<div v-if="prevReadMsg.type=='框架梳理'" style="height: 100%;">
|
||||
<FlowChart ref="flowref" :flowHeight="mainHeight" :dataSource="flowData"/>
|
||||
</div>
|
||||
<!-- <div v-if="prevReadMsg.type=='学科定位'" style="height: 100%;">
|
||||
<teachJsMind :course-obj="courseObj" :teachResObj="activeTeachResOfStandard"></teachJsMind>
|
||||
</div> -->
|
||||
<!-- <div v-if="prevReadMsg.type=='习题训练'">习题训练</div> -->
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -259,12 +285,17 @@
|
|||
import { onMounted, ref, nextTick, watch, reactive, getCurrentInstance } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useToolState } from '@/store/modules/tool'
|
||||
import { getCurrentTime } from '@/utils/date'
|
||||
import { processList } from '@/hooks/useProcessList'
|
||||
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
|
||||
import { updateClasswork } from '@/api/classTask'
|
||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||
import { addClassworkReturnId } from '@/api/teaching/classwork'
|
||||
import { updateClasswork, listEvaluationclue,readFile } from '@/api/classTask'
|
||||
import { listEvaluation } from '@/api/subject'
|
||||
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||
|
||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||
import { processList } from '@/hooks/useProcessList'
|
||||
import { getCurrentTime } from '@/utils/date'
|
||||
import FlowChart from "@/components/Flowchart/index.vue";
|
||||
|
||||
|
||||
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
@ -364,9 +395,16 @@ let classWorkForm = reactive({
|
|||
title: '',// 作业说明
|
||||
quizlist: [], // 作业习题列表内容
|
||||
}); // 提交的作业内容
|
||||
const chooseWorkLists = ref([]); // 选择作业资源列表? 非习题训练的list
|
||||
const chooseWorkLists = ref([]); // 框架梳理、?课堂展示
|
||||
const whiteboardObj = ref(''); // 作业资源 - 课堂展示 白板
|
||||
|
||||
// 课堂展示
|
||||
const boardLoading = ref(false);
|
||||
const question = ref(''); // 课堂展示
|
||||
const prevReadMsg = reactive({
|
||||
visible: false,
|
||||
type: ""
|
||||
});// 预览msg
|
||||
const flowData = ref({})// 框架梳理
|
||||
|
||||
/***
|
||||
* 作业类型切换
|
||||
|
@ -403,7 +441,7 @@ const queryForm = reactive({
|
|||
|
||||
|
||||
/**
|
||||
* @desc: 新查询试题
|
||||
* @desc: 1、习题训练 - 新查询试题
|
||||
* @return: {*}
|
||||
* @param {*} queryType
|
||||
* 0 - 标准查询
|
||||
|
@ -451,6 +489,41 @@ const handleQueryFromEntpCourseWork= (queryType) => {
|
|||
})
|
||||
}
|
||||
|
||||
// 教学资源,从课标分析、教材分析里来
|
||||
/**
|
||||
* 2、框架设计、教学资源,从课标分析、教材分析里来
|
||||
*/
|
||||
const getQueryFromEvaluationclue = () => {
|
||||
// props.bookobj.levelSecondId, //userStore.evalid, // // 单元下的课ID
|
||||
listEvaluationclue({ cluegroup: 'teachresource', evalid: props.bookobj.levelSecondId, pageSize: 1000 }).then((clueres) => {
|
||||
for (var i=0; i<clueres.rows.length; i++) {
|
||||
|
||||
if (clueres.rows[i].cluetag == 'standardview') {
|
||||
clueres.rows[i].worktype = '课标研读';
|
||||
} else if (clueres.rows[i].cluetag == 'targetview') {
|
||||
clueres.rows[i].worktype = '目标设定';
|
||||
} else if (clueres.rows[i].cluetag == 'contentview') {
|
||||
clueres.rows[i].worktype = '教材研读';
|
||||
} else if (clueres.rows[i].cluetag == 'frameview') {
|
||||
clueres.rows[i].worktype = '框架梳理';
|
||||
} else if (clueres.rows[i].cluetag == 'mapview') {
|
||||
clueres.rows[i].worktype = '学科定位';
|
||||
}
|
||||
|
||||
if (clueres.rows[i].childlist != '') {
|
||||
clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
|
||||
for (var j=0; j<clueres.rows[i].childArray.length; j++) {
|
||||
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
|
||||
}
|
||||
} else {
|
||||
clueres.rows[i].childArray = {};
|
||||
}
|
||||
}
|
||||
console.log("框架梳理、课标研读、目标设定、教材研读、学科定位的资源",clueres.rows);
|
||||
workResource.teachResourceList = clueres.rows;
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加资源
|
||||
* @param fromsrc - 试题来源
|
||||
|
@ -481,6 +554,103 @@ const handleClassWorkQuizAdd = (fromsrc, entpcourseworkid) => {
|
|||
ElMessage('试题已经存在')
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 预览资源
|
||||
*/
|
||||
const prevRead = async (item) => {
|
||||
prevReadMsg.visible = true;
|
||||
prevReadMsg.type = item.worktype;
|
||||
if (item.worktype==='课标研读'){
|
||||
//获取教材文件和批注信息
|
||||
listEvaluation({itemkey: 'subject', edusubject: userStore.edusubject, edustage: userStore.edustage}).then(res => {
|
||||
// TODO 课标研读-还未接入
|
||||
console.log("课标研读-还未接入",res);
|
||||
// this.versionObj = res.rows[0];
|
||||
// // 读取出课标文件的每一行
|
||||
// if (this.versionObj.fileurl.length > 0) {
|
||||
// readFile({cluelink: this.versionObj.fileurl}).then(fileres => {
|
||||
// this.versionObj.bookdata = fileres;
|
||||
// this.activeTeachResOfStandard = item;
|
||||
// })
|
||||
// }
|
||||
})
|
||||
}
|
||||
if (item.worktype==='目标设定'){
|
||||
// TODO 目标设定-还未接入
|
||||
// this.activeTeachResOfStandard = item;
|
||||
}
|
||||
if (item.worktype==='教材研读'){
|
||||
// TODO 教材研读-还未接入
|
||||
// getEvaluation(this.courseObj.evalrootid).then(bookres => {
|
||||
// this.versionObj = bookres.data;
|
||||
// if (this.versionObj.fileurl.length > 0) {
|
||||
// readFile({cluelink: this.versionObj.fileurl}).then(fileres => {
|
||||
// this.versionObj.bookdata = fileres;
|
||||
// this.activeTeachResOfStandard = item;
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
}
|
||||
if (item.worktype==='框架梳理'){
|
||||
flowData.value = {};
|
||||
const { chapterId } = await useGetHomework(props.bookobj.node)
|
||||
// this.entpcourseid = chapterId
|
||||
let queryParams = {
|
||||
entpcourseid: chapterId,
|
||||
ppttype: '教材分析',
|
||||
parentid: item.id,
|
||||
title: '逻辑框架建构',
|
||||
filetype: 'draw'
|
||||
}
|
||||
listEntpcoursefile(queryParams).then(response=>{
|
||||
if (response.rows.length == 0) {
|
||||
return;
|
||||
}
|
||||
flowData.value = JSON.parse(response.rows[0].datacontent)
|
||||
})
|
||||
}
|
||||
if (item.worktype==='学科定位'){
|
||||
// TODO 学科定位-还未接入
|
||||
// this.activeTeachResOfStandard = item;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 添加到作业
|
||||
*/
|
||||
// 把教学资源添加为作业
|
||||
const handleClassWorkAddOfResource = (work) => {
|
||||
// 当前资源下是否已存在
|
||||
let arrSole = chooseWorkLists.value.filter((item) => {
|
||||
return item.worktype === classWorkForm.worktype
|
||||
})
|
||||
// 仅能添加一个
|
||||
if(arrSole.length > 0) {
|
||||
ElMessage('该资源已存在,请勿重复添加')
|
||||
return;
|
||||
}
|
||||
//存入集合
|
||||
let arr = chooseWorkLists.value.filter((item) => {
|
||||
return item.id === work.id
|
||||
})
|
||||
if (arr.length===0) {
|
||||
work.score = 1;
|
||||
chooseWorkLists.value.push(work);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 删除作业
|
||||
*/
|
||||
const deleteClassWorkAddOfResource = (work) => {
|
||||
chooseWorkLists.value.filter((item, index) => {
|
||||
if (item.id === work.id) {
|
||||
chooseWorkLists.value.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 作业设计-提交
|
||||
|
@ -656,47 +826,66 @@ const handleClassWorkSave = async () => {
|
|||
const { chapterId } = await useGetHomework(props.bookobj.node)
|
||||
// this.entpcourseid = chapterId
|
||||
|
||||
const cform = {
|
||||
id: 0,
|
||||
workdate: classWorkForm.workdate, // //作业类型?web端这里貌似没有这个时间
|
||||
deaddate: '', // 截止时间
|
||||
entpid: userStore.deptId, //
|
||||
level: 1,
|
||||
parentid: 0,
|
||||
worktype: classWorkForm.worktype, // 作业类型
|
||||
workkey: '',
|
||||
worktag: '',
|
||||
uniquekey: classWorkForm.uniquekey,// 作业名称、编码
|
||||
classid: 0,
|
||||
classcourseid: 0,
|
||||
entpcourseid: chapterId, // 这个字段很特别
|
||||
slideid: 0,
|
||||
title: classWorkForm.title, // 作业说明?
|
||||
workcodes: JSON.stringify(classWorkForm.workcodes), // 作业内容?
|
||||
edusubject: userStore.edusubject, // 学科 语文 数学
|
||||
evalid: props.bookobj.levelSecondId, //userStore.evalid, // // 单元下的课ID
|
||||
edustage: userStore.edustage, // 学段 年纪 高中,初中,小学
|
||||
status: '10', //2024-09-11 作业布置分离后的 新模版数据; 之前老版本为空
|
||||
edituserid: userStore.userId, // 当前用户id
|
||||
entpcourseworklist: '', // 选择的 习题训练 list 需要转字符串
|
||||
|
||||
};
|
||||
|
||||
if (classWorkForm.worktype === "课堂展示") {
|
||||
this.boardLoading = true
|
||||
boardLoading.value = true
|
||||
let canvasJson = this.$refs.boardref.getCanvasJson()
|
||||
let canvasBase64 = await this.$refs.boardref.getCanvasBase64()
|
||||
var formObj = {};
|
||||
formObj.id = 0;
|
||||
formObj.workdate = this.classWorkForm.workdate;
|
||||
formObj.deaddate = '';
|
||||
formObj.entpid = this.userStore.deptId;
|
||||
formObj.level = 1;
|
||||
formObj.parentid = 0;
|
||||
formObj.worktype = this.classWorkForm.worktype;
|
||||
formObj.workkey = '';
|
||||
formObj.worktag = this.question;
|
||||
formObj.uniquekey = this.classWorkForm.uniquekey;
|
||||
formObj.classid = 0;
|
||||
formObj.classcourseid = 0;
|
||||
formObj.entpcourseid = chapterId;// 这个字段很特别
|
||||
formObj.slideid = 0;
|
||||
formObj.title = this.classWorkForm.title;
|
||||
// 课堂展示提交内容
|
||||
formObj.worktag = question.value;
|
||||
formObj.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
|
||||
formObj.edusubject = this.courseObj.edusubject;
|
||||
formObj.evalid = this.courseObj.evalid;
|
||||
formObj.edustage = this.userStore.edustage;
|
||||
formObj.status = '10'; //2024-09-11 作业布置分离后的 新模版数据; 之前老版本为空
|
||||
formObj.edituserid = this.userStore.id;
|
||||
formObj.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
|
||||
try {
|
||||
addClassworkReturnId(formObj).then(() => {
|
||||
this.classWorkForm.worktype = "习题训练";
|
||||
this.chooseWorkLists = [];
|
||||
this.whiteboardObj = '';
|
||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||
// 重置提交表单
|
||||
classWorkForm.worktype = "习题训练";
|
||||
classWorkForm.uniquekey = props.uniquekey, // 作业唯一标识 作业名称
|
||||
classWorkForm.title = "";
|
||||
classWorkForm.quizlist = [], // 作业习题列表内容
|
||||
|
||||
// 情况选择的资源缓存
|
||||
chooseWorkLists.value = [];
|
||||
whiteboardObj.value = ''; // ? // 清空白板
|
||||
// refresh the list
|
||||
//这里分离了,所以不需要更新表单数据了
|
||||
// this.getClassWorkAllList();
|
||||
this.newWorkSpace = false;
|
||||
this.newWorkSpaceEdit = false;
|
||||
this.workEdit = false;
|
||||
|
||||
// TODO 后续看是否跳转到 作业布置页面
|
||||
|
||||
//TODO 下面3个后续看是啥
|
||||
// this.newWorkSpace = false;
|
||||
// this.newWorkSpaceEdit = false;
|
||||
// this.workEdit = false;
|
||||
boardLoading.value = false
|
||||
})
|
||||
} finally {
|
||||
this.boardLoading = false
|
||||
boardLoading.value = false
|
||||
}
|
||||
}
|
||||
else if(classWorkForm.worktype === "常规作业"){
|
||||
|
@ -750,47 +939,22 @@ const handleClassWorkSave = async () => {
|
|||
// 更新 题目分值
|
||||
ll.push({'id': classWorkForm.quizlist[i].id, 'score': classWorkForm.quizlist[i].score});
|
||||
}
|
||||
}else {
|
||||
// TODO 待定 非习题训练------------
|
||||
// this.chooseWorkLists.filter((item, index) => {
|
||||
// if (item.worktype === this.classWorkForm.worktype) {
|
||||
// ll.push({'id':item.id, 'score': item.score});
|
||||
// }
|
||||
// })
|
||||
}else if( classWorkForm.worktype === "框架梳理") {
|
||||
chooseWorkLists.value.filter((item) => {
|
||||
if (item.worktype === classWorkForm.worktype) {
|
||||
ll.push({'id':item.id, 'score': item.score});
|
||||
}
|
||||
})
|
||||
}
|
||||
console.log(userStore,'userStoreuserStoreuserStore')
|
||||
const cform = {
|
||||
id: 0,
|
||||
workdate: classWorkForm.workdate, // //作业类型?web端这里貌似没有这个时间
|
||||
deaddate: '', // 截止时间
|
||||
entpid: userStore.deptId, //
|
||||
level: 1,
|
||||
parentid: 0,
|
||||
worktype: classWorkForm.worktype, // 作业类型
|
||||
workkey: '',
|
||||
worktag: '',
|
||||
uniquekey: classWorkForm.uniquekey,// 作业名称、编码
|
||||
classid: 0,
|
||||
classcourseid: 0,
|
||||
entpcourseid: chapterId, // 这个字段很特别
|
||||
slideid: 0,
|
||||
title: classWorkForm.title, // 作业说明?
|
||||
workcodes: JSON.stringify(classWorkForm.workcodes), // 作业内容?
|
||||
edusubject: userStore.edusubject, // 学科 语文 数学
|
||||
evalid: props.bookobj.levelSecondId, //userStore.evalid, // // 单元下的课ID
|
||||
edustage: userStore.edustage, // 学段 年纪 高中,初中,小学
|
||||
status: '10', //2024-09-11 作业布置分离后的 新模版数据; 之前老版本为空
|
||||
edituserid: userStore.userId, // 当前用户id
|
||||
};
|
||||
|
||||
// 习题训练 右侧选择的资源list
|
||||
if (ll.length > 0) {
|
||||
cform.entpcourseworklist = JSON.stringify(ll);
|
||||
} else {
|
||||
cform.entpcourseworklist = '';
|
||||
}
|
||||
|
||||
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
|
||||
console.log(cform,'提交的数据');
|
||||
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
|
||||
|
||||
addClassworkReturnId(cform).then(workres => {
|
||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||
// 重置提交表单
|
||||
|
@ -827,7 +991,10 @@ watch(() => props.bookobj.levelSecondId, (newVal) => {
|
|||
console.log(props.bookobj,'课程选择')
|
||||
queryForm.eid = props.bookobj.levelSecondId,
|
||||
queryForm.sectionName = props.bookobj.coursetitle,
|
||||
// 习题资源
|
||||
handleQueryFromEntpCourseWork(0);
|
||||
// 框架梳理
|
||||
getQueryFromEvaluationclue();
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -879,7 +1046,31 @@ watch(() => props.bookobj.levelSecondId, (newVal) => {
|
|||
line-height: 26px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.choose-work{
|
||||
height: 90px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.choose-work-title{
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
margin-right: 5px
|
||||
}
|
||||
|
||||
.choose-work-content{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
:deep(.el-form-item__label){
|
||||
width: 50px !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue