Compare commits
13 Commits
ae4f7d3b49
...
6b8c6c8c7f
Author | SHA1 | Date |
---|---|---|
朱浩 | 6b8c6c8c7f | |
zhengdegang | fa5e132c2d | |
zdg | 99c6fe85d4 | |
zdg | 05074f3145 | |
lyc | 34b35d8beb | |
lyc | 921ce6ecb0 | |
lyc | 1be862a0f2 | |
lyc | 9ef553f8eb | |
lyc | e53eab0c31 | |
朱浩 | 1a51af93f6 | |
lyc | 0ba717de6e | |
lyc | 6e29229e95 | |
lyc | df84893509 |
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "electron-app",
|
||||
"version": "1.0.1",
|
||||
"name": "aix-win",
|
||||
"version": "1.0.2",
|
||||
"description": "An Electron application with Vue",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "example.com",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Electron</title>
|
||||
<title>AIx智慧教育</title>
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<!-- <meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
|
|
|
@ -17,3 +17,20 @@ export function listEntpcourse(query) {
|
|||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 布置作业
|
||||
export function saveByClassWorkArray(data) {
|
||||
return request({
|
||||
url: '/education/classwork/saveByClassWorkArray',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除classwork 作业
|
||||
export function delClasswork(id) {
|
||||
return request({
|
||||
url: '/education/classwork/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
|
@ -158,13 +158,19 @@ const getSubject = async () => {
|
|||
curBookId.value = subjectList.value[0].id
|
||||
}
|
||||
|
||||
const isHaveUnit = (id) => {
|
||||
return evaluationList.value.some(item => {
|
||||
return item.rootid == id
|
||||
})
|
||||
}
|
||||
|
||||
const getTreeData = () => {
|
||||
//数据过滤
|
||||
let upData = transData(volumeOne.value)
|
||||
let downData = transData(volumeTwo.value)
|
||||
treeData.value = upData.length ? upData : downData
|
||||
defaultExpandedKeys.value = [treeData.value[0].id]
|
||||
nextTick(() => {
|
||||
defaultExpandedKeys.value = [treeData.value[0].id]
|
||||
currentNodeId.value = getLastLevelData(treeData.value)[0].id
|
||||
currentNodeName.value = getLastLevelData(treeData.value)[0].label
|
||||
emitChangeBook()
|
||||
|
|
|
@ -1453,14 +1453,14 @@ export class History {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 清除记录
|
||||
clean() {
|
||||
this.FabricVue?.canvas?.clear()
|
||||
this.index = 0
|
||||
this.diffs = []
|
||||
this.canvasData = {}
|
||||
}
|
||||
|
||||
// 重新加载历史记录
|
||||
initHistory() {
|
||||
const canvas = this.FabricVue.canvas
|
||||
if (canvas) {
|
||||
|
|
|
@ -69,7 +69,7 @@ export const createWindow = async (type, data) => {
|
|||
// parent: mainWin, // 父窗口
|
||||
// autoClose: true, // 关闭窗口后自动关闭
|
||||
}
|
||||
// data.isConsole = true // 是否开启控制台
|
||||
data.isConsole = true // 是否开启控制台
|
||||
data.option = {...defOption, ...option}
|
||||
const win = await toolWindow(data)
|
||||
win.type = type // 唯一标识
|
||||
|
@ -145,7 +145,7 @@ export function toolWindow({url, isConsole, option={}}) {
|
|||
// 内部监听器-是否打印
|
||||
if (!!isConsole) {
|
||||
win.webContents.on('console-message', (e,leve,m,lin,s) => {
|
||||
console.log('console-msg: ', m)
|
||||
console.log(m)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
</el-button>
|
||||
</div>
|
||||
<div class="item-popover-item">
|
||||
<el-button text @click="deleteTalk(item)">
|
||||
<el-button text @click="deleteHomework(item)">
|
||||
<i class="iconfont icon-shanchu"></i>
|
||||
<span>删除</span>
|
||||
</el-button>
|
||||
|
@ -159,7 +159,7 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
emits: { 'on-move': null, 'on-delete': null, 'on-set': null },
|
||||
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-delhomework': null },
|
||||
data() {
|
||||
return {
|
||||
listenList: []
|
||||
|
@ -248,6 +248,10 @@ export default {
|
|||
//布置
|
||||
setHomeWork(item) {
|
||||
this.$emit('on-set', item)
|
||||
},
|
||||
// 删除作业
|
||||
deleteHomework(item){
|
||||
this.$emit('on-delhomework', item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
<template>
|
||||
<el-dialog v-model="dialogVisible" center top="10vh" width="600px" :show-close="false"
|
||||
<el-dialog v-model="dialogVisible" center top="10vh" width="600px" :show-close="false" append-to-body
|
||||
style="border-radius: 10px; padding: 10px 15px;">
|
||||
|
||||
<template #header>
|
||||
<div class="homerwork-header flex">
|
||||
<span>布置作业</span>
|
||||
<i class="iconfont icon-guanbi" @click="cloneDialog"></i>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form :model="form" label-width="80px">
|
||||
<el-form-item label="班级">
|
||||
<el-tree ref="treeRef" :data="treeData" :props="defaultProps" :load="getLoad" node-key="id"
|
||||
<div v-loading="setLoading">
|
||||
<el-form :model="form" label-width="80px" ref="ruleForm" :rules="rules">
|
||||
<el-form-item label="班级" prop="grade">
|
||||
<el-scrollbar max-height="200px" style="width: 100%;">
|
||||
<el-tree ref="treeRef" :data="gradeList" :props="defaultProps" :load="getLoad" node-key="id"
|
||||
@check="handleCheckChange" lazy show-checkbox />
|
||||
</el-scrollbar>
|
||||
</el-form-item>
|
||||
<el-form-item label="选中学生">
|
||||
<el-form-item label="选中学生" prop="student">
|
||||
<el-scrollbar max-height="200px">
|
||||
<el-tag v-for="(tag, index) in studentList" :key="tag.studentid" closable type="primary"
|
||||
@close="delStudent(index)">
|
||||
|
@ -22,17 +23,17 @@
|
|||
</el-tag>
|
||||
</el-scrollbar>
|
||||
</el-form-item>
|
||||
<el-form-item label="完成要求">
|
||||
<el-radio-group v-model="form.feedtype">
|
||||
<el-form-item label="完成要求" prop="feedback">
|
||||
<el-radio-group v-model="form.feedback">
|
||||
<el-radio value="必做" size="large">必做</el-radio>
|
||||
<el-radio value="选做" size="large">选做</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="截至时间">
|
||||
<el-date-picker v-model="endTime" value-format="YYYY-MM-DD HH:mm:ss" type="datetime" placeholder="请选择截至时间"
|
||||
@change="changeTime" />
|
||||
<el-form-item label="截止时间" prop="deaddate">
|
||||
<el-date-picker v-model="form.deaddate" value-format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm"
|
||||
time-format="HH:mm" type="datetime" :clearable="false" placeholder="请选择截止时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="推荐用时">
|
||||
<el-form-item label="推荐用时" prop="timelength">
|
||||
<el-input-number v-model="form.timelength" :min="1" :max="500" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
@ -41,7 +42,7 @@
|
|||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cloneDialog">取消</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
<el-button type="primary" @click="onSubmit('ruleForm')">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
|
@ -50,17 +51,27 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { listClassmain, listClassgroup } from '@/api/classManage/index'
|
||||
import { saveByClassWorkArray } from '@/api/teaching/classwork'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { uniqBy, cloneDeep } from 'lodash'
|
||||
import { uniqBy, groupBy } from 'lodash'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
entpcourseid: {
|
||||
default: ''
|
||||
},
|
||||
row: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
return {
|
||||
dialogVisible: false,
|
||||
defaultProps: {
|
||||
|
@ -68,7 +79,7 @@ export default {
|
|||
label: 'label',
|
||||
isLeaf: 'leaf',
|
||||
},
|
||||
treeData: [],
|
||||
setLoading: false,
|
||||
// 用户信息
|
||||
userInfo: null,
|
||||
// 班级列表
|
||||
|
@ -80,19 +91,26 @@ export default {
|
|||
studentList: [],
|
||||
// 表单
|
||||
form: {
|
||||
feedtype: '必做',
|
||||
endTime: '',
|
||||
feedback: '必做',
|
||||
deaddate: '',
|
||||
timelength: 1
|
||||
},
|
||||
endTime: ''
|
||||
// 表单规则
|
||||
rules: {
|
||||
grade: [
|
||||
{ validator: this.validateGrade, trigger: 'blur' }
|
||||
],
|
||||
student: [
|
||||
{ validator: this.validateStudent, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
//截至时间默认值
|
||||
this.endTime = this.getCurrentDate() + ' ' + '10:00:00'
|
||||
this.form.deaddate = this.getCurrentDate() + ' ' + '10:00:00'
|
||||
this.userInfo = useUserStore().user
|
||||
this.getGradeList()
|
||||
},
|
||||
methods: {
|
||||
// 获取班级列表
|
||||
|
@ -104,28 +122,31 @@ export default {
|
|||
item.level = 0
|
||||
item.children = []
|
||||
item.classstudentlist = JSON.parse("[" + item.classstudentlist + "]")
|
||||
item.classstudentlist.forEach(el => {
|
||||
el.classId = item.id
|
||||
})
|
||||
})
|
||||
console.log(list)
|
||||
this.gradeList = list
|
||||
this.treeData = list
|
||||
})
|
||||
},
|
||||
// 获取节点下一级
|
||||
getLoad(node, resolve) {
|
||||
console.log(node.level)
|
||||
if (node.level == 0) return resolve([])
|
||||
// 获取二级节点 小组
|
||||
if (node.level == 1) {
|
||||
listClassgroup({ classid: node.key, orderby: 'orderidx', pageSize: 100 }).then(res => {
|
||||
console.log(res)
|
||||
if (res.rows.length > 0) {
|
||||
let ary = []
|
||||
res.rows.forEach(item => {
|
||||
if (item.parentid === 0) {
|
||||
//studentGroup 小组学生
|
||||
let studentGroup = JSON.parse("[" + item.studentlist + "]")
|
||||
studentGroup.forEach(el => {
|
||||
el.label = el.name
|
||||
el.leaf = true
|
||||
el.level = 2,
|
||||
el.id = el.studentid
|
||||
el.classId = item.classid
|
||||
})
|
||||
ary.push({
|
||||
label: item.groupname,
|
||||
|
@ -135,7 +156,6 @@ export default {
|
|||
})
|
||||
}
|
||||
})
|
||||
// console.log(ary)
|
||||
resolve(ary)
|
||||
}
|
||||
else {
|
||||
|
@ -143,23 +163,28 @@ export default {
|
|||
}
|
||||
})
|
||||
}
|
||||
// 三级节点 小组学生
|
||||
if (node.level == 2) {
|
||||
resolve(node.data.children)
|
||||
}
|
||||
|
||||
},
|
||||
//节点勾选后触发 拿学生
|
||||
handleCheckChange(data, checked) {
|
||||
this.studentList = []
|
||||
// 选中节点集合
|
||||
let checkNodes = checked.checkedNodes
|
||||
let ary = []
|
||||
checkNodes.forEach(item => {
|
||||
// 一级节点 班级
|
||||
if (item.level == 0) {
|
||||
ary = [...ary, ...(item.classstudentlist)]
|
||||
}
|
||||
// 二级节点 班级下面的小组
|
||||
if (item.level == 1) {
|
||||
ary = [...ary, ...(item.children)]
|
||||
}
|
||||
// 三级节点 小组下面的学生
|
||||
if (item.level == 2) {
|
||||
ary = [...ary, item]
|
||||
}
|
||||
|
@ -170,13 +195,63 @@ export default {
|
|||
delStudent(index) {
|
||||
this.studentList.splice(index, 1)
|
||||
},
|
||||
onSubmit(formName) {
|
||||
|
||||
this.$refs[formName].validate(valid => {
|
||||
if (valid) {
|
||||
/**
|
||||
* 根据学生列表中的classId分班
|
||||
* studentList 为选中的所有学生 这些学生可能来自不同班级
|
||||
*/
|
||||
let gradeObj = groupBy(this.studentList, 'classId')
|
||||
// 处理要提交的参数
|
||||
let ary = []
|
||||
for (const value in gradeObj) {
|
||||
//这些参数 参照AIx web端 作业推送
|
||||
let obj = {
|
||||
id: 0,
|
||||
parentid: this.row.id,
|
||||
classid: value,
|
||||
classcourseid: 0,
|
||||
entpcourseid: this.entpcourseid,
|
||||
studentlist: JSON.stringify(gradeObj[value]),
|
||||
feedback: this.form.feedback,
|
||||
workkey: "",
|
||||
timelength: this.form.timelength,
|
||||
weights: 1,
|
||||
deaddate: this.form.deaddate,
|
||||
workdate: this.getCurrentDate(),
|
||||
uniquekey: this.row.uniquekey,
|
||||
entpcourseworklist: "[" + this.row.entpcourseworklist + "]",
|
||||
needMsgNotifine: 'false',
|
||||
msgkey: 'newclasswork',
|
||||
title: "作业任务",
|
||||
msgcontent: '',
|
||||
teachername: this.userInfo.nickName,
|
||||
unixstamp: new Date().getTime(),
|
||||
}
|
||||
ary.push(obj)
|
||||
}
|
||||
this.setLoading = true
|
||||
saveByClassWorkArray({
|
||||
classworkarray: JSON.stringify(ary)
|
||||
}).then(() => {
|
||||
this.setLoading = false
|
||||
ElMessage.success('操作成功')
|
||||
this.cloneDialog()
|
||||
}).catch(()=>{
|
||||
this.setLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
// 关闭弹窗
|
||||
cloneDialog() {
|
||||
this.$emit('on-close')
|
||||
},
|
||||
//
|
||||
changeTime(value) {
|
||||
console.log(value, 100)
|
||||
this.studentList = []
|
||||
this.$refs['ruleForm'].resetFields();
|
||||
},
|
||||
// 获取当前年月日
|
||||
getCurrentDate() {
|
||||
|
@ -185,13 +260,33 @@ export default {
|
|||
const month = now.getMonth() + 1; // 月份是从0开始的,所以需要+1
|
||||
const day = now.getDate()
|
||||
return `${year}-${month.length == 2 ? month : '0' + month}-${day.length == 2 ? day : '0' + day}`;
|
||||
},
|
||||
validateGrade(rule, value, callback) {
|
||||
if (this.studentList.length == 0) {
|
||||
callback(new Error('请勾选班级或者学生'));
|
||||
}
|
||||
else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
validateStudent(rule, value, callback) {
|
||||
if (this.studentList.length == 0) {
|
||||
callback(new Error('学生不能为空'));
|
||||
}
|
||||
else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
this.dialogVisible = val
|
||||
if (val) {
|
||||
this.getGradeList()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -212,4 +307,14 @@ export default {
|
|||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.dialog-footer{
|
||||
padding-bottom: 10px
|
||||
}
|
||||
|
||||
:deep(.el-checkbox){
|
||||
transform : scale(1.3)
|
||||
}
|
||||
:deep(.el-icon){
|
||||
transform : scale(1.3)
|
||||
}
|
||||
</style>
|
|
@ -65,8 +65,9 @@
|
|||
@on-move="onMoveSingleFile"
|
||||
@on-delete="deleteTalk"
|
||||
@on-set="openSet"
|
||||
@on-delhomework="delhomework"
|
||||
>
|
||||
<el-checkbox label="" :value="item" />
|
||||
<el-checkbox label="" :value="item" v-if="!item.uniquekey"/>
|
||||
</file-list-item>
|
||||
</el-checkbox-group>
|
||||
<file-oper-batch
|
||||
|
@ -82,7 +83,7 @@
|
|||
</div>
|
||||
<MoveFile v-model="isMoveDialogOpen" @on-submit="chooseMoveCata" />
|
||||
<uploadDialog v-model="isDialogOpen" @submit-file="submitFile" />
|
||||
<SetHomework v-model="setDialog" @on-close="closeHomework" />
|
||||
<SetHomework v-model="setDialog" :entpcourseid="entpcourseid" :row="row" @on-close="closeHomework" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
|
@ -106,6 +107,7 @@ import SetHomework from './container/set-homework.vue'
|
|||
import outLink from '@/utils/linkConfig'
|
||||
import { createWindow } from '@/utils/tool'
|
||||
import { uniqBy, cloneDeep } from 'lodash'
|
||||
import { delClasswork } from '@/api/teaching/classwork'
|
||||
|
||||
const { ipcRenderer } = window.electron || {}
|
||||
|
||||
|
@ -147,7 +149,8 @@ export default {
|
|||
entpcourseid: '',
|
||||
timerId: null,
|
||||
// 布置作业弹窗
|
||||
setDialog: false
|
||||
setDialog: false,
|
||||
row: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -309,9 +312,10 @@ export default {
|
|||
this.uploadData.textbookId = data.textBook.curBookId
|
||||
await this.asyncAllFile()
|
||||
if (this.uploadData.levelSecondId) {
|
||||
// 获取作业列表所需ID
|
||||
const res = await this.getChapterId()
|
||||
this.entpcourseid = res.rows[0].id
|
||||
// 获取作业列表所需ID 可能存在没有
|
||||
const { rows } = await this.getChapterId()
|
||||
if(!rows.length) return
|
||||
this.entpcourseid = rows[0].id
|
||||
// 查询作业
|
||||
this.getHomeWorkList()
|
||||
}
|
||||
|
@ -339,7 +343,7 @@ export default {
|
|||
pageSize: 500
|
||||
})
|
||||
},
|
||||
//
|
||||
// 清除查询作业列表定时器
|
||||
createTimer() {
|
||||
this.timerId = setInterval(() => {
|
||||
this.getHomeWorkList()
|
||||
|
@ -412,9 +416,22 @@ export default {
|
|||
})
|
||||
},
|
||||
// 打开布置作业窗口
|
||||
openSet() {
|
||||
openSet(row) {
|
||||
this.row = row
|
||||
this.setDialog = true
|
||||
},
|
||||
// 删除作业
|
||||
delhomework(item){
|
||||
this.isLoading = true
|
||||
delClasswork(item.id).then( async res =>{
|
||||
ElMessage.success('操作成功')
|
||||
this.isLoading = false
|
||||
await this.asyncAllFile()
|
||||
this.getHomeWorkList()
|
||||
}).catch(()=>{
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
closeHomework() {
|
||||
this.setDialog = false
|
||||
},
|
||||
|
|
|
@ -4,27 +4,28 @@
|
|||
</template>
|
||||
<script setup>
|
||||
// 功能说明:画板
|
||||
import { ref, onMounted, watchEffect } from 'vue'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import {FabricVue, TYPES} from '@/plugins/fabric'
|
||||
const canvasRef = ref(null) // 画布
|
||||
const isMouse = ref(true) // 鼠标是否在画布上
|
||||
const props = defineProps({
|
||||
modelValue: String
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
// 画板初始化配置
|
||||
onMounted(async() => {
|
||||
if (canvasRef.value) {
|
||||
FabricVue.drawConfig.drawColors = ['red']
|
||||
FabricVue.boardConfig.mode = TYPES.ActionMode.OTHER
|
||||
FabricVue.boardConfig.backgroundColor = 'transparent'
|
||||
const option = { freeDrawingCursor: 'default' }
|
||||
await FabricVue.initCanvas(canvasRef.value, option)
|
||||
}
|
||||
})
|
||||
|
||||
// 监听
|
||||
watchEffect(() => {
|
||||
// console.log('board 画板: ', props.modelValue)
|
||||
isMouse.value = false
|
||||
switch(props.modelValue) {
|
||||
watch(() => props.modelValue, (newVal, oldVal) => {
|
||||
// console.log(newVal, oldVal)
|
||||
switch(newVal) {
|
||||
case 'select': // 选择模式
|
||||
FabricVue.handleMode(TYPES.ActionMode.OTHER)
|
||||
break
|
||||
|
@ -35,6 +36,10 @@ watchEffect(() => {
|
|||
case 'eraser': // 板擦模式
|
||||
FabricVue.handleMode(TYPES.ActionMode.ERASE)
|
||||
break
|
||||
case 'clear': // 清空画布
|
||||
FabricVue.history?.clean()
|
||||
emit('update:modelValue', oldVal)
|
||||
break
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
/**
|
||||
* @description 工具栏-拖拽 自定义指令
|
||||
*/
|
||||
class Drag {
|
||||
isDrag = false // 是否开始拖拽
|
||||
rafId // requestAnimationFrame id
|
||||
x = 0 // 鼠标按下时的x坐标
|
||||
y = 0 // 鼠标按下时的y坐标
|
||||
data // 其他参数 元素实际坐标值
|
||||
el; handle; // el, handle 挂载元素和拖拽元素
|
||||
pos // 拖拽元素实际坐标值
|
||||
max // 拖拽元素最大边界
|
||||
// 构造器
|
||||
constructor(el, binding) {
|
||||
this.el = el
|
||||
const { value } = binding
|
||||
const handleSelector = value instanceof Object ? value.handle : value
|
||||
if (!!handleSelector) {
|
||||
if (handleSelector instanceof HTMLElement) this.handle = handleSelector
|
||||
else {
|
||||
this.handle = document.querySelector(handleSelector)
|
||||
// .forEach((child) => { this.handleArray.push(child) })
|
||||
}
|
||||
}
|
||||
if (!this.handle) this.handle = el // 默认为当前元素
|
||||
// 被拖拽元素初始坐标
|
||||
const pos = this.handle?.getBoundingClientRect()
|
||||
this.data = {left:this.toRound(pos.left), top:this.toRound(pos.top)}
|
||||
this.pos = pos
|
||||
this.max = {w: window.innerWidth, h: window.innerHeight}
|
||||
}
|
||||
// 移入
|
||||
down(e) {
|
||||
this.isDrag = true
|
||||
const {cx, cy} = this.getMousePos(e)
|
||||
this.x = cx
|
||||
this.y = cy
|
||||
// 手动-触发事件 v-drag-start
|
||||
this.el.dispatchEvent(new CustomEvent('v-drag-start', {detail:{drag: this}}))
|
||||
}
|
||||
// 移动过程
|
||||
move = (e) => {
|
||||
if (!this.isDrag) return
|
||||
if (this.rafId) cancelAnimationFrame(this.rafId) // 清除上一次动画
|
||||
this.rafId = requestAnimationFrame(() => this.updatePosition(e))
|
||||
}
|
||||
// 移出
|
||||
up = (e) => {
|
||||
// e.preventDefault(); // 阻止默认行为
|
||||
// e.stopPropagation(); // 阻止事件传播
|
||||
this.isDrag = false
|
||||
cancelAnimationFrame(this.rafId)
|
||||
this.rafId = null
|
||||
document.removeEventListener('mousemove', this.move);
|
||||
document.removeEventListener('mouseup', this.up);
|
||||
document.addEventListener('touchmove', this.move);
|
||||
document.addEventListener('touchend', this.up);
|
||||
}
|
||||
// 业务逻辑
|
||||
updatePosition(e) {
|
||||
const {cx, cy} = this.getMousePos(e)
|
||||
const {left, top} = this.data
|
||||
const dx = cx - this.x
|
||||
const dy = cy - this.y
|
||||
this.x = cx
|
||||
this.y = cy
|
||||
const {x, y} = this.getPos(left + dx, top + dy) // 调用边界函数
|
||||
this.data.left = x // 设置边界-x
|
||||
this.data.top = y // 设置边界-y
|
||||
// console.log(JSON.stringify(this))
|
||||
this.handle.style.left = `${this.data?.left}px`
|
||||
this.handle.style.top = `${this.data?.top}px`
|
||||
this.handle.style.bottom = 'unset'
|
||||
this.handle.style.transform = 'unset'
|
||||
this.rafId = requestAnimationFrame(() => this.updatePosition(e))
|
||||
}
|
||||
// 获取鼠标位置 | Get mouse position
|
||||
getMousePos(e){
|
||||
let cx = e.clientX || e.touches[0].clientX
|
||||
let cy = e.clientY || e.touches[0].clientY
|
||||
cx = this.toRound(cx)
|
||||
cy = this.toRound(cy)
|
||||
return {cx, cy}
|
||||
}
|
||||
// 获取移动后坐标
|
||||
getPos(x, y) {
|
||||
const w = this.max.w - this.toRound(this.el.clientWidth)
|
||||
const h = this.max.h - this.toRound(this.el.clientHeight)
|
||||
x = x < 0 ? 0 : x > w ? w : x
|
||||
y = y < 0 ? 0 : y > h ? h : y
|
||||
return { x, y }
|
||||
}
|
||||
// 小数转整数
|
||||
toRound = v => Math.round(v)
|
||||
}
|
||||
export default {
|
||||
mounted(el, binding) {
|
||||
// const { style } = binding.value
|
||||
const drag = new Drag(el, binding)
|
||||
const dragStart = (e) => {
|
||||
drag.down(e)
|
||||
document.addEventListener('mousemove', drag.move);
|
||||
document.addEventListener('mouseup', drag.up);
|
||||
document.addEventListener('touchmove', drag.move);
|
||||
document.addEventListener('touchend', drag.up);
|
||||
}
|
||||
el.addEventListener('mousedown', dragStart)
|
||||
el.addEventListener('touchstart', dragStart)
|
||||
},
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
<template>
|
||||
<div class="warp-all">
|
||||
<board-vue v-model="tabActive"></board-vue>
|
||||
<!-- 底部工具栏 -->
|
||||
<div ref="tool" class="tool-bottom-all" :style="dataPos.style"
|
||||
<!-- 底部工具栏 :style="dataPos.style"-->
|
||||
<div class="tool-bottom-all"
|
||||
@mouseenter="mouseChange(0)" @mouseleave="mouseChange(1)">
|
||||
<div @mousedown="e => dargHandle(e,'down')"
|
||||
@mousemove="e => dargHandle(e,'move')"
|
||||
@mouseup="e => dargHandle(e,'up')">
|
||||
<div v-drag="{handle:'.tool-bottom-all', dragtime}"
|
||||
@v-drag-start="dragtime = Date.now()">
|
||||
<div class="c-logo" @click="logoHandle" title="拖动 | 折叠 | 展开">
|
||||
<el-image :src="logo" />
|
||||
<el-image :src="logo" draggable="false" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-btns" v-show="!isFold">
|
||||
|
@ -16,7 +15,7 @@
|
|||
@change="tabChange">
|
||||
<template #default="{item}">
|
||||
<div class="c-btn flex flex-col items-center gap-2 p-2">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<i class="iconfont" :class="item.icon" :style="item.style"></i>
|
||||
<span>{{item.label}}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -31,27 +30,27 @@
|
|||
import { onMounted, ref, reactive } from 'vue'
|
||||
import logo from '@root/resources/icon.png' // logo
|
||||
import boardVue from './components/board.vue' // 画板
|
||||
import vDrag from '@/directive/drag'
|
||||
import { tryOnUnmounted } from '@vueuse/core'
|
||||
import vDrag from './directive/drag'
|
||||
// const Remote = require('@electron/remote') // remote对象
|
||||
const { ipcRenderer } = require('electron')
|
||||
const { ipcRenderer } = require('electron') // app使用
|
||||
// const ipcRenderer = { send: () => {} } // 网页测试使用
|
||||
|
||||
const tool = ref()
|
||||
const tabActive = ref('select') // 工具栏当前选中项
|
||||
const isFold = ref(false) // 折叠工具栏
|
||||
const isDrag = ref(false) // 开始拖拽
|
||||
const dataPos = reactive({style:{}}) // 对象属性
|
||||
const dragtime = ref(0)
|
||||
const btnList = [ // 工具栏按钮列表
|
||||
{ label: '选择', value: 'select', icon: 'icon-mouse' },
|
||||
{ label: '画笔', value: 'brush', icon: 'icon-huabi' },
|
||||
{ label: '板擦', value: 'eraser', icon: 'icon-xiangpica' },
|
||||
{ label: '互动', value: 'interact', icon: 'icon-hudong' },
|
||||
{ label: '聚焦', value: 'focus', icon: 'icon-jujiao' },
|
||||
{ label: '更多', value: 'more', icon: 'icon-xiazai9' },
|
||||
{ label: '清除', value: 'clear', icon: 'icon-xiangpica', style: 'color: #ccc' },
|
||||
// { label: '互动', value: 'interact', icon: 'icon-hudong' },
|
||||
// { label: '聚焦', value: 'focus', icon: 'icon-jujiao' },
|
||||
// { label: '更多', value: 'more', icon: 'icon-xiazai9' },
|
||||
]
|
||||
let offsetX = 0, offsetY = 0, dragtime = 0
|
||||
// ==== 方法 ===
|
||||
const tabChange = (val) => { // 切换tab-change
|
||||
console.log(val)
|
||||
switch (val) {
|
||||
case 'brush': // 画笔
|
||||
break
|
||||
|
@ -71,47 +70,11 @@ const tabChange = (val) => { // 切换tab-change
|
|||
}
|
||||
}
|
||||
const logoHandle = (e,t) => { // logo 点击-事件 折叠|展开
|
||||
if (Date.now() - dragtime < 200) {
|
||||
if (Date.now() - dragtime.value < 200) {
|
||||
isFold.value = !isFold.value
|
||||
}
|
||||
console.log('click', isDrag.value)
|
||||
}
|
||||
const dargHandle = (e, type) => { // 拖拽处理
|
||||
e.preventDefault(); // 阻止默认的拖拽行为
|
||||
if (type == 'down') {
|
||||
dragtime = Date.now()
|
||||
return isDrag.value = true
|
||||
} else if (type == 'up') {
|
||||
return isDrag.value = false
|
||||
} else {
|
||||
if (!isDrag.value) return false
|
||||
if (!e.clientX&&!e.clientY){ // 最后一次松开坐标为0
|
||||
offsetX = 0
|
||||
offsetY = 0
|
||||
return false
|
||||
}
|
||||
if (!offsetX&&!offsetY) { // 第一次, 获取元素坐标
|
||||
setStyle()
|
||||
} else {
|
||||
const x = e.clientX - offsetX
|
||||
const y = e.clientY - offsetY
|
||||
setStyle(x, y)
|
||||
}
|
||||
offsetX = e.clientX
|
||||
offsetY = e.clientY
|
||||
}
|
||||
}
|
||||
const setStyle = (x, y) => { // 拖拽-设置值
|
||||
if (offsetX && offsetY) { // 有值
|
||||
const {left, top} = dataPos.style
|
||||
const ox = parseInt(left.replace('px',''))
|
||||
const oy = parseInt(top.replace('px',''))
|
||||
dataPos.style = {...dataPos.style, left: ox + x + 'px', top: oy + y + 'px'}
|
||||
} else { // 初始值
|
||||
const {left, top} = tool.value.getBoundingClientRect() // 获取元素位置
|
||||
dataPos.style = {bottom: 'unset', transform:'unset', left: left+'px', top: top+'px'}
|
||||
}
|
||||
}
|
||||
|
||||
const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
||||
let resBool = false
|
||||
if (tabActive.value == 'select') resBool = !!bool
|
||||
|
@ -153,8 +116,7 @@ const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
|||
:deep(.el-segmented__item){
|
||||
position: relative;
|
||||
margin: 0 0.5rem;
|
||||
&:nth-last-child(1):before,
|
||||
&:nth-last-child(2):before{
|
||||
&:not(:nth-of-type(1)):before{
|
||||
content: "";
|
||||
width: 2px;
|
||||
height: calc(100% - 20px);
|
||||
|
|
Loading…
Reference in New Issue