vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。
vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。
- 1.设计思路:
- 2.设计细节
- 3.详细代码实现
1.设计思路:
左侧button列表是要拖拽的组件。中间是拖拽后的流程图。右侧是拖拽后的数据列表。
我们拖动左侧组件放入中间的流程图中,并把button携带的数据信息带过来。
2.设计细节
左侧button组件列表可拖动并携带信息,当拖动到中间流程图上方时,流程图网格变色。当鼠标释放后,数据传递,流程图变化。
拖拽事件流程和参数
dragstart:当元素开始被拖拽时触发。
drag:元素正在被拖拽时持续触发(某些浏览器支持)。
dragend:当拖拽结束时触发。
dragenter:当拖拽的元素进入目标元素时触发。
dragover:当拖拽的元素在目标元素上移动时持续触发。
dragleave:当拖拽的元素离开目标元素时触发。
drop:当拖拽的元素在目标元素上释放时触发。
3.详细代码实现
<template><div class="scriptDraweAdd"><drawer-Box:drawerVisible="drawer.visible":drawerFooter="drawer.drawerFooter":direction="drawer.direction":drawerSize="drawer.drawerSize":drawerTitle="drawer.drawerTitle"@handleDrawerOpened="handleDrawerOpened"@handleDrawerClose="handleDrawerClose"@handleDrawerSubmit="handleDrawerSubmit"><div class="main h100"><el-form ref="addFormRef" :model="editFrom" size="small" status-icon class="h100" label-width="auto"><el-row :gutter="0"><el-col><el-row :gutter="10"><el-col :span="4" class="mb20 setting-title"><span>General settings</span></el-col><el-col :span="10" class="mb20"><el-form-item prop="projectName" :rules="rules.projectName"><template v-slot:label><span>Project Name </span><el-tooltip effect="dark" content="Project Name" placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input v-model="editFrom.projectName" placeholder="Project Name" clearable></el-input></el-form-item></el-col><el-col :span="10" class="mb20"><el-form-item prop="version" :rules="rules.version"><template v-slot:label><span>Version </span><el-tooltip effect="dark" content="Software Version" placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input v-model="editFrom.version" placeholder="Software Version" clearable></el-input></el-form-item></el-col></el-row></el-col><el-col><el-row :gutter="10"><el-col :span="4" class="mb20"><span></span></el-col><!-- <el-col :span="10" class="mb20"><el-form-item prop="softwareName" :rules="rules.softwareName"><template v-slot:label><span>Software Name </span><el-tooltip effect="dark" content="Software Name" placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input v-model="editFrom.softwareName" placeholder="Software Name" clearable></el-input></el-form-item></el-col> --><el-col :span="10" class="mb20"><el-form-item prop="function" :rules="rules.function"><template v-slot:label><span>Function </span><el-tooltip effect="dark" content="Function of the script" placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-select v-model="editFrom.function" placeholder="Function"><el-option v-for="item in functionOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item></el-col></el-row></el-col><el-col><el-row :gutter="10"><el-col :span="4" class="mb20 setting-title"><span>Advanced settings</span></el-col><el-col :span="10" class="mb20"><el-form-item label="" prop="maxRunTime" :rules="rules.maxRunTime"><template v-slot:label><span>Max Run Time </span><el-tooltip effect="dark" content="The max run time of the script" placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input-number type="number" v-model="editFrom.maxRunTime" :min="0" :max="1000" placeholder="Max Run Time" style="width: 100%" /></el-form-item></el-col><el-col :span="10" class="mb20"><el-form-item prop="startStopService" :rules="rules.startStopService"><template v-slot:label><span>Start Stop Service </span><el-tooltip effect="dark" content="Service(s) needed to be pause during software installation, separate with commas." placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input v-model="editFrom.startStopService" placeholder="Start Stop Service" clearable></el-input></el-form-item></el-col></el-row></el-col><el-col><el-row :gutter="10"><el-col :span="4" class="mb20"><span></span></el-col><el-col :span="10" class="mb20"><el-form-item prop="debugEnable" :rules="rules.debugEnable"><template v-slot:label><span>Debug Enable </span><el-tooltip effect="dark" content="Used to enable logging." placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-switch v-model="editFrom.debugEnable" :active-value="true" :inactive-value="false" /></el-form-item></el-col><el-col :span="10" class="mb20"><el-form-item prop="defaultMsicLine" :rules="rules.defaultMsicLine"><template v-slot:label><span>Default MSIC Line </span><el-tooltip effect="dark" content="Default MSI commands, used for each MSI installer." placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input v-model="editFrom.defaultMsicLine" placeholder="Default MSIC Line" clearable></el-input></el-form-item></el-col></el-row></el-col><el-col><el-row :gutter="10"><el-col :span="4" class="mb20"><span></span></el-col><el-col :span="10" class="mb20"><el-form-item prop="uDriveMap" :rules="rules.uDriveMap"><template v-slot:label><span>U-Drive Map </span><el-tooltip effect="dark" content="If the software stored on U-Drive." placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-switch v-model="editFrom.uDriveMap" :active-value="true" :inactive-value="false" /></el-form-item></el-col><el-col :span="10" class="mb20"><el-form-item label="IFS Script" prop="ifsScript" :rules="rules.ifsScript"><template v-slot:label><span>IFS Script </span><el-tooltip effect="dark" content="If you need to run the script on your local computer." placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-switch v-model="editFrom.ifsScript" :active-value="true" :inactive-value="false" /></el-form-item></el-col></el-row></el-col><el-col><el-row :gutter="10"><el-col :span="4" class="mb20"><span></span></el-col><!-- <el-col :span="10" class="mb20"><el-form-item prop="patchCommands"><template v-slot:label><span>Patch Commands </span><el-tooltip effect="dark" content="Used if need to install software to alternate folder." placement="top"><i><svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /></i></el-tooltip></template><el-input v-model="editFrom.patchCommands" placeholder="Patch Commands" disabled></el-input></el-form-item></el-col> --><el-col :span="10" class="mb20"><el-form-item label="Remarks" prop="remarks" :rules="rules.remarks"><el-input v-model="editFrom.remarks" clearable placeholder="Remarks" :rows="2" type="textarea" /></el-form-item></el-col></el-row></el-col><el-col><el-row :gutter="10" class="custom-row-height"><el-col :span="8" class="mb20"><div class="searchdiv"><div style="display: flex"><el-input style="margin-right: 10px" v-model="searchScriptName" placeholder="Script Name" @keyup.enter="getScriptList()" clearable></el-input><el-button @click="getScriptList()" type="primary"><i> <svg-icon icon-class="icon_screen" class-name="iconfont font14" /> </i></el-button></div><div class="paramslabel"><el-tooltip v-for="(item, index) in scriptList" :key="index" placement="top" raw-content :content="remarkHTML(item.remarks)"><el-button draggable="true" @dragstart="dragstart($event, item)" @dragend="dragend($event, item)" class="buttondiv" :title="item.scriptName" type="primary">{{item.scriptName}}</el-button></el-tooltip></div></div></el-col><el-col :span="9" class="mb20"><div class="flowdiv"><div class="flowlabel"><div><el-button class="buttondiv" type="primary">Start</el-button><div :class="['add-contain-div', overFlag.over0 ? 'add-contain-div-active' : '']" @dragover="dragOver($event, 'over0')" @drop="drop($event, 0)"><svg-icon icon-class="downward_vertical_line" class="addline" /><svg-icon icon-class="icon_add" class="addicon" /></div></div><div v-for="(item, index) in editFrom.scriptList" :key="index" style="padding-left: 60px"><!-- <el-button v-show="true" class="buttondiv2" type="primary">{{ item.gClientScriptId }}</el-button> --><el-input style="width: 180px" v-show="false" v-model="item.gClientScriptId" placeholder="gClientScriptId" readonly></el-input><el-tooltip placement="top" raw-content :content="remarkHTML(item.remarks)"><el-button class="buttondiv" type="primary">{{ item.scriptName }}</el-button></el-tooltip><el-button type="text" @click="deleteMethod(index)" class="deletebutton"><svg-icon icon-class="icon_delete2" class="deleteline" /></el-button><div style="padding-right: 60px" @dragover="dragOver($event, 'over' + (index + 1))" @drop="drop($event, index + 1)"><div :class="['add-contain-div', overFlag['over' + (index + 1)] ? 'add-contain-div-active' : '']"><svg-icon icon-class="downward_vertical_line" class="addline" /><svg-icon icon-class="icon_add" class="addicon" /></div></div></div><el-button class="buttondiv" type="primary">End</el-button></div></div></el-col><el-col :span="7" class="mb20" style="min-width:350px"><div v-for="(item2, index2) in editFrom.scriptList" :key="index2 + 'params'"><div class="paramsdiv"><div class="params-title-parent"><el-form-item><span style="margin-left: 10px; font-weight: bold">{{ item2.scriptName }}</span></el-form-item></div><div class="paramsdiv-content"><el-form-item label-width="auto" label="Order No."> <el-input style="width: 100%" v-model="item2.orderNum" placeholder="Order No." readonly></el-input></el-form-item><el-form-item label="CmdRCOpt" label-width="auto" :prop="`scriptList[${index2}].cmdRcopt`" :rules="[{ required: true, message: `Please input CmdRCOpt`, trigger: 'change' }]"><el-select v-model="item2.cmdRcopt" placeholder="CmdRCOpt" disabled style="width: 100%"><el-option v-for="item3 in cmdRCOptOptions" :key="item3.value" :label="item3.label" :value="item3.value" /></el-select></el-form-item><div v-for="(item, index) in item2.paramslist" :key="index2 + '_' + index"><el-form-item v-show="false" label="Order No." label-width="140px"><el-input style="width: 100%" v-model="item.index" placeholder="Order No." readonly></el-input></el-form-item><div v-if="item.dataType === 'String'" class="paramsdiv-params"><el-form-item:prop="`scriptList[${index2}].paramslist[${index}].value`":rules="[{ required: true, message: `Please input ${item.name}`, trigger: 'blur' }]"label-width="auto"><template v-slot:label><span>{{ item.name }}</span><el-tooltip effect="dark" :content="item.remarks" placement="top"><i> <svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /> </i></el-tooltip><el-tag style="margin-right: 0px !important; margin-top: 3px !important" type="primary" class="mr12" effect="light" round>{{ item.dataType }}</el-tag></template><el-input style="width: 100%" v-model="item.value" :placeholder="item.name"></el-input></el-form-item></div><div v-if="item.dataType === 'Int'" class="paramsdiv-params"><el-form-item:prop="`scriptList[${index2}].paramslist[${index}].value`":rules="[{ required: true, message: `Please input ${item.name}`, trigger: 'change' }]"label-width="auto"><template v-slot:label><span>{{ item.name }}</span><el-tooltip effect="dark" :content="item.remarks" placement="top"><i> <svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /> </i></el-tooltip><el-tag style="margin-right: 0px !important; margin-top: 3px !important" type="primary" class="mr12" effect="light" round>{{ item.dataType }}</el-tag></template><!-- <el-input style="width: 100%" v-model="item.value" :placeholder="item.name"></el-input> --><el-input-number type="number" v-model="item.value" :placeholder="item.name" style="width: 100%" /></el-form-item></div><div v-if="item.dataType === 'Boolean'" class="paramsdiv-params"><el-form-item:prop="`scriptList[${index2}].paramslist[${index}].value`":rules="[{ required: true, message: `Please input ${item.name}`, trigger: 'change' }]"label-width="auto"><template v-slot:label><span>{{ item.name }}</span><el-tooltip effect="dark" :content="item.remarks" placement="top"><i> <svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /> </i></el-tooltip><el-tag style="margin-right: 0px !important; margin-top: 3px !important" type="primary" class="mr12" effect="light" round>{{ item.dataType }}</el-tag></template><el-switch v-model="item.value" :active-value="true" :inactive-value="false" :value="false" :disabled="index === 0" /></el-form-item></div><div v-if="item.dataType === 'File'" class="paramsdiv-params"><el-form-item:label="item.name":placeholder="item.name":prop="`scriptList[${index2}].paramslist[${index}].fileList`":rules="[{ required: true, message: `Please upload file`, validator: validator, trigger: 'change' }]"label-width="auto"><template v-slot:label><span>{{ item.name }}</span><el-tooltip effect="dark" :content="item.remarks" placement="top"><i> <svg-icon icon-class="icon_ notes_info" class-name="iconfont font14" /> </i></el-tooltip><el-tag style="margin-right: 0px !important; margin-top: 3px !important" type="primary" class="mr12" effect="light" round>{{ item.dataType }}</el-tag></template><el-upload:disabled="item.isOriginalFile === 1":action="upload.action":headers="upload.headers":limit="upload.limit"multiplev-model:file-list="item.fileList":on-success="(res) => handleUploadSuccess(res, item, index)":on-remove="(uploadFile, uploadFiles) => handleRemove(uploadFile, uploadFiles, item, index)":before-upload="(file) => beforeAvatarUpload(file, item, index)":on-exceed="(uploadFile, uploadFiles) => handleExceed(uploadFile, uploadFiles, item, index)":on-preview="(uploadFile) => handlePreview(uploadFile, item, index)"><el-button :disabled="item.fileList && item.fileList.length > 0" type="primary">Click to upload</el-button><template #tip><div class="el-upload__tip">.ps1, .txt files with a size less than 2M</div></template></el-upload></el-form-item><el-form-item v-show="false" label="File Name" label-width="140px"><el-input style="width: 80%" v-model="item.fileName" placeholder="File Name" readonly></el-input></el-form-item><el-form-item :prop="`scriptList[${index2}].paramslist[${index}].fileContent`" label-width="140px" style="margin-top: -20px"><el-inputv-show="false"type="textarea"readonlystyle="width: 100%"v-model="item.fileContent"placeholder="File Content":autosize="{ minRows: 3, maxRows: 10000 }"></el-input></el-form-item></div></div></div></div></div></el-col></el-row></el-col></el-row></el-form></div></drawer-Box></div>
</template>
<script>
import { toRefs, reactive, onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import DrawerBox from '../drawer/index'
import gClientApi from '@/api/gClientApi'
import gClientManagementApi from '@/api/gClientManagementApi'
import { removeProperty } from '@/utils/validate'
import { Session } from '@/utils/storage'
export default {name: 'GclientScriptMenagement',emits: ['handleSearch', 'handleClose', 'downScriptFile'],components: {DrawerBox// vxeTable},props: {drawer: {type: Object,default: () => {return {}}},GclientScriptMenagement: {type: Object,default: () => {return {}}}},setup(props, ctx) {// 列表数组 接口返回的数据const vxeData = reactive({tableList: []})const addFormRef = ref(null)// 复选框数组const vxeList = reactive({checkList: []})const useTableHeader = reactive({})const state = reactive({upload: {action: process.env.VUE_APP_API_URL + '/portal/v1/GClientScript/scriptUpload',headers: {Authorization: Session.get('token')},accept: '.ps1, .txt',fileSize: 2,limit: 1},functionOptions: [{ lable: 'Install', value: 'Install' },{ lable: 'Uninstall', value: 'Uninstall' }],typeOptions: [{ label: 'String', value: 'String' },{ label: 'Int', value: 'Int' },{ label: 'Boolean', value: 'Boolean' },{ label: 'File', value: 'File' }],cmdRCOptOptions: [{ label: 'Continue running', value: 0 },{ label: 'Command failed,stop running', value: 1 },{ label: 'Command failed,continue running', value: 2 }],editFrom: {softwareName: '',version: '',projectName: '',// applicationName: '',patchCommands: '',maxRunTime: 90,startStopService: '',debugEnable: true,defaultMsicLine: '',uDriveMap: false,function: 'Install',ifsScript: false,remarks: '',scriptList: []},editFrom2: {softwareName: '',version: '',projectName: '',// applicationName: '',patchCommands: '',maxRunTime: 90,startStopService: '',debugEnable: true,defaultMsicLine: '',uDriveMap: false,function: 'Install',ifsScript: false,remarks: '',scriptList: []},scriptList: [],rules: {softwareName: [{ required: true, message: 'Please input Software Name', trigger: 'blur' }],version: [{ required: true, message: 'Please input Version', trigger: 'blur' }],projectName: [{ required: true, message: 'Please input Project Name', trigger: 'blur' }],// applicationName: [{ required: true, message: 'Please input Application Name', trigger: 'blur' }],patchCommands: [{ required: true, message: 'Please input Patch Commands', trigger: 'blur' }],maxRunTime: [{ required: true, message: 'Please input Max Run Time', trigger: 'blur' }],startStopService: [{ required: true, message: 'Please input Start Stop Service', trigger: 'blur' }],debugEnable: [{ required: true, message: 'Please input Debug Enable', trigger: 'blur' }],defaultMsicLine: [{ required: true, message: 'Please input Default MSIC Line', trigger: 'blur' }],uDriveMap: [{ required: true, message: 'Please input U-Drive Map', trigger: 'blur' }],function: [{ required: true, message: 'Please input Function', trigger: 'blur' }],ifsScript: [{ required: true, message: 'Please input IFS Script', trigger: 'blur' }]},paramsIndex: 1,searchScriptName: '',overFlag: {}})const getParamsName = (index) => {return `Param Name ${index + 1}`}const getParamsRules = (name) => {let msg = `Please input ${name}`let tips = [{ required: true, message: msg, trigger: 'blur' }]return tips}const validator = (rule, value, callback) => {if (value && value.length > 0) {callback() // 表示验证通过} else {callback(new Error('length>0'))}}const deleteMethod = (index) => {const newArray = state.editFrom.scriptList.filter((element, index2) => index2 !== index)state.editFrom.scriptList = newArraystate.editFrom.scriptList.forEach((val, index) => {val.orderNum = index + 1})}const SubmitList = (checkData) => {vxeList.checkList = checkData}// 数据提交const handleDrawerSubmit = async () => {addFormRef.value.validate(async (valid) => {if (valid) {const data = { ...state.editFrom }console.log(data)const res = await gClientManagementApi.add(data)if (res.code === 200) {resetForm(addFormRef.value)handleDrawerClose()ctx.emit('handleSearch')ElMessage({showClose: true,message: res.message,type: 'success'})} else {ElMessage({showClose: true,message: res.message,type: 'error'})}} else {console.log('error submit!')return false}})}// Drawer 打开时触发const handleDrawerOpened = () => {getScriptList()}// Drawer 关闭const handleDrawerClose = () => {state.editFrom = JSON.parse(JSON.stringify(state.editFrom2))ctx.emit('handleClose', 'Add')}const dragstart = (event, item) => {// console.log(event, item)// 使用 dataTransfer 对象传递JSON数据作为文本event.dataTransfer.setData('text/plain', JSON.stringify(item))}const dragend = (event, item) => {state.overFlag = {}}const dragOver = (event, name) => {// 阻止浏览器默认操作,允许drop事件发生event.preventDefault()state.overFlag = {}state.overFlag[name] = true// console.log(state.overFlag)}const drop = (event, index) => {// 阻止浏览器默认操作event.preventDefault()// 获取传递的JSON数据const jsonData = event.dataTransfer.getData('text/plain')// 解析JSON数据const data = JSON.parse(jsonData)state.overFlag = {}state.editFrom.scriptList.splice(index, 0, data)state.editFrom.scriptList = JSON.parse(JSON.stringify(state.editFrom.scriptList))state.editFrom.scriptList.forEach((val, index) => {val.orderNum = index + 1})console.log('get', state.editFrom.scriptList)}// 表单 Resetconst resetForm = (formEl) => {if (!formEl) returnformEl.resetFields()state.editFrom = JSON.parse(JSON.stringify(state.editFrom2))}const handleBlur = () => {// console.log('1111', state.editFrom.scriptList)}const getScriptList = async () => {// console.log(columns.value)// console.log(exportColumns.value)// 条件检索const query = removeProperty(JSON.parse(JSON.stringify({ scriptName: state.searchScriptName })))console.log(query)const res = await gClientApi.getDownLoadData({ ...query })if (res.code === 200) {const _arr = res.data.map((item) => {let paramslist = []if (item.paramsNameList && item.paramsNameList.length > 0) {item.paramsNameList.map((element) => {if (null !== element.value && undefined !== element.value && '' !== element.value) {paramslist.push({ ...element })} else {paramslist.push({ ...element, value: '', fileList: [], fileName: '', fileContent: '' })}})}item.paramslist = paramslistitem.gClientScriptId = item.idlet _item = { ...item }return _item})state.scriptList = JSON.parse(JSON.stringify(_arr))// ElMessage({// message: res.message,// type: 'success'// })} else {ElMessage({message: res.message,type: 'error'})}}// 上传图片验证const beforeAvatarUpload = (file, item, index) => {// 校检文件类型if (state.upload.accept) {// 文件后缀名let fileExtension = ''if (file.name.lastIndexOf('.') > -1) {fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)}const isTypeOk = state.upload.accept.indexOf(fileExtension) > -1if (!isTypeOk) {ElMessage({showClose: true,message: `The file format is incorrect. Please upload the file in ${state.upload.accept} format!`,type: 'error'})return false}}// 校检文件大小if (state.upload.fileSize) {const isLt = file.size / 1024 / 1024 < state.upload.fileSizeif (!isLt) {ElMessage({showClose: true,message: `The uploaded file size cannot exceed ${state.upload.fileSize} MB!`,type: 'error'})return false}}return true}// 文件个数超出const handleExceed = (files, uploadFiles, item, index) => {ElMessage({showClose: true,message: `The number of uploaded files cannot exceed ${state.upload.limit} !`,type: 'error'})}// 文件上传成功时的钩子const handleUploadSuccess = (res, item, index) => {switch (res.code) {case 200:item.fileContent = res.data.fileContentitem.fileName = res.data.fileNameitem.value = res.data.fileName// ruleForm.systemScreenshot = res.data.filePathElMessage({showClose: true,message: res.message,type: 'success'})breakcase 401:Session.clear()window.location.reload()breakcase 403:Session.clear()window.location.reload()breakdefault:ElMessage({showClose: true,message: res.message,type: 'error'})}}// 文件列表移除文件时的钩子const handleRemove = (uploadFile, uploadFiles, item, index) => {item.fileList = []item.fileContent = ''item.fileName = ''item.value = ''}// 点击文件列表中已上传的文件时的钩子const handlePreview = (uploadFile, item, index) => {// ctx.emit('downScriptFile', item)}const handleChange = (value, item) => {console.log(value, item)}const fileChange = (name, item) => {addFormRef.value.validateField(name, (val) => {if (!val) {return true} else {return false}})}const remarkHTML = (remark) => {// return remark.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');if (remark) {return remark.replace(/\n|\r\n/g, '<br/>').replace(/ /g, ' ')}return ''}onMounted(() => {})return {...toRefs(state),...toRefs(vxeData),...toRefs(vxeList),...toRefs(useTableHeader),addFormRef,handleDrawerOpened,handleDrawerClose,handleDrawerSubmit,SubmitList,getParamsName,getParamsRules,deleteMethod,resetForm,getScriptList,dragstart,dragOver,drop,dragend,handleBlur,validator,beforeAvatarUpload,handleExceed,handleUploadSuccess,handleRemove,handleChange,handlePreview,fileChange,remarkHTML}}
}
</script>
<style lang="scss">
.scriptDraweAdd {// .setting-title {// font-size: var(--el-form-label-font-size);// color: var(--el-text-color-regular);// height: 32px;// line-height: 32px;// padding: 0 12px 0 0;// box-sizing: border-box;// font-weight: bold;// }.drawer_title {font-weight: bold;margin-bottom: 16px;}.name-parent {display: flex;.title {font-weight: bold;width: 5px;height: 30px;margin-right: 5px;background-color: var(--color-primary) !important;}.blank {font-weight: bold;width: 5px;height: 30px;margin-right: 5px;}.label {flex: 1;}}.title {font-weight: bold;width: 5px;height: 30px;margin-right: 5px;background-color: var(--color-primary) !important;}.no-label .el-form-item__label {display: none;}.custom-row-height {/* 使用calc()函数从100vh中减去100px */// height: calc(100vh - 600px);min-height: 400px;.searchdiv {flex: 1;height: 100%;padding: 5px;border-radius: 4px;border: 1px solid #cccccc;box-sizing: border-box;.paramslabel {margin-top: 10px;display: flex; /* 启用Flexbox布局 */flex-direction: column; /* 子元素纵向排列 */justify-content: center; /* 子元素在父容器内水平居中(纵向上的居中) */align-items: center; /* 子元素在父容器内水平居中(横向上的居中) */.buttondiv {width: 60%;// min-width: 290px;max-width: 300px;height: 30px;margin: 7px;color: var(--color-primary) !important;background-color: #fff;border: 2px solid var(--color-primary);}}}.flowdiv {min-width: 500px;flex: 1;height: 100%;padding: 5px;border-radius: 4px;border: 1px solid #cccccc;box-sizing: border-box;.deletebutton {width: 48px;height: 32px;color: #606266 !important;.deleteline {width: 40px;height: 32px;color: #606266 !important;}}.flowlabel {margin-top: 10px;display: flex; /* 启用Flexbox布局 */flex-direction: column; /* 子元素纵向排列 */justify-content: center; /* 子元素在父容器内水平居中(纵向上的居中) */align-items: center; /* 子元素在父容器内水平居中(横向上的居中) */.add-contain-div {margin: -5px 5px -5px 5px;height: 60px;// background-color: var(--color-primary) !important;position: relative;.addline {position: absolute;width: 100%;height: 100%;color: #606266;}.addicon {position: absolute;width: 40%;height: 40%;color: #606266;margin-left: 130px;margin-top: 17px;}}.add-contain-div-active {border: 1px dashed var(--color-primary);}.buttondiv {width: 300px;height: 30px;margin: 5px;color: var(--color-primary) !important;background-color: #fff;border: 2px solid var(--color-primary);}.buttondiv2 {width: 250px;height: 30px;margin: 5px;color: var(--color-primary) !important;background-color: #fff;border: 2px solid var(--color-primary);&:hover {border: 2px solid var(--el-color-primary);background-color: var(--el-color-primary) !important;color: #fff !important;}&:active,&:focus {background-color: var(--color-primary) !important;color: #fff !important;}}// .deletediv{// float:right;// right:0px;// width:auto;// }}}}.paramsdiv {min-width: 500px;flex: 1 1 0%;height: 100%;border-radius: 2px;border: 1px solid #cccccc;box-sizing: border-box;margin-left: 0px;padding-bottom: 25px;margin-bottom: 20px;margin-right: 0px;.paramsdiv-content {padding: 5px;.paramsdiv-params {margin-bottom: 30px;}}.params-title-parent {padding: 5px 5px 5px 5px;display: flex;justify-content: space-between;/* 如果需要,可以添加以下样式以确保父 div 占据整个宽度 */width: 100%;border-bottom: 1px solid rgb(230, 230, 230);background-color: #fbfbfb;margin-bottom: 20px;.child {/* 你可以根据需要添加子 div 的样式 */}.left {/* 你可以在这里添加左边子 div 的特定样式 */}.right {/* 你可以在这里添加右边子 div 的特定样式 */}}}
}
</style>
相关文章:

vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。
vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。 1.设计思路:2.设计细节3.详细代码实现 1.设计思路: 左侧button列表是要拖拽的组件。中间是拖拽后的流程图。右侧是拖拽后的数据列表。 我们拖动左侧组件放入中间的流…...

linux上使用cmake编译的方法
一、hello 例程仅基于一个cpp文件 C文件或工程进行编译时可以使用g指令(需要对每一个程序和源文件分别使用g指令编译),当程序变大时,一个工程文件往往会包含很文件夹和源文件,这时我们需要的编译指令将越来越长&#…...

如何实现el-select多选下拉框中嵌套复选框并加校验不为空功能呢?
如何实现el-select多选下拉框中嵌套复选框并加校验不为空功能呢? 要实现的效果图选择部分品牌但不选选项效果问题概述实现方案el-select组件与el-checkbox组件无缝衔接给form表单加自定义校验规则 要实现的效果图 选择部分品牌但不选选项效果 问题概述 相信大家看到…...
源码理解 UE4中的 FCookStatsManager::FAutoRegisterCallback RegisterCookStats
官方文档:https://dev.epicgames.com/documentation/zh-cn/unreal-engine/API/Runtime/Core/ProfilingDebugging/FCookStatsManager文档中的注释: When a cook a complete that is configured to use stats (ENABLE_COOK_STATS), it will broadcast this…...
Android 根据内存大小显示MTP模式连接PC时的名称
项目有两种内存,要求根据连接电脑拷贝文件时的盘符名称根据内存大小显示不同名称。 frameworks/base/media/java/android/mtp/MtpDatabase.java//mh import android.app.ActivityManager; ...-894,7 896,19 public class MtpDatabase implements AutoCloseable {p…...
不只是mini-react第一节:实现最简单mini-react
项目总结构: ├─ 📁core │ ├─ 📄React.js │ └─ 📄ReactDom.js ├─ 📁node_modules ├─ 📁tests │ └─ 📄createElement.spec.js ├─ 📄App.js ├─ 📄in…...

前端路由layout布局处理以及菜单交互(三)
上篇介绍了前端项目部署以及基本依赖的应用,这次主要对于路由以及布局进行模块化处理 一、 创建layout模块 1、新建src/layout/index.vue <template><el-container class"common-layout"><!-- <el-aside class"aside">&l…...
小结:DNS,HTTP,SMTP,IMAP,FTP,Telnet,TCP,ARP,ICMP
DNS(Domain Name System,域名系统) 是互联网的重要组成部分,它负责将人类易读的域名(如 www.google.com)转换为机器可以识别的 IP 地址(如 142.250.72.206)。这一过程被称为域名解析…...

【C++】P2550 [AHOI2001] 彩票摇奖
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式:输出格式:输入输出样例: 💯题解思路1. 问题解析 💯我的实现实现逻辑问题分析 💯老…...

并发服务器框架——zinx
zinx框架 Zinx 是一个用 Go 语言编写的高性能、轻量级的 TCP 服务器框架,它被设计为简单、快速且易于使用。Zinx 提供了一系列的功能,包括但不限于连接管理、数据编解码、业务处理、负载均衡等,适用于构建各种 TCP 网络服务,如游戏…...

Unity 中计算射线和平面相交距离的原理
有此方法 能够计算射线和平面是否相交以及射线起点到平面交点的距离 代码分析 var dot Vector3.Dot(ray.direction, plane.normal);计算射线和平面法线的点积,如果大于等于0,则说明射线和平面没有相交,否则,说明射线和平面相交…...
浅谈棋牌游戏开发流程七:反外挂与安全体系——守护游戏公平与玩家体验
一、前言:为什么反外挂与安全这么重要? 对于任何一款线上棋牌游戏而言,公平性和玩家安全都是最重要的核心要素之一。如果游戏环境充斥着各式各样的外挂、作弊方式,不仅会毁坏玩家体验,更会导致游戏生态崩塌、口碑下滑…...

《无力逃脱》V1.0.15.920(59069)官方中文版
艾丹是一名三臂赏金猎人,他必须追捕银河系中最危险、最难以捉摸的割喉者。 有些悬赏是金钱,有些则是有价值的信息。艾丹可以利用这些信息找到让他走上这条路的人,同时也会卷入一个全银河系的阴谋中。 拥有三条手臂可以让你同时对付更多的敌…...
六种主流服务器的选择与使用
网络的运行离不开各种服务器,它们各司其职,为我们提供稳定的网络服务。本文带大家了解6种常见服务器类型。 服务器的六大种类 第一种:Web服务器 Web服务器是互联网的核心。当你打开一个网站,比如百度或淘宝,浏览器会…...
TiDB 升级至高版本提示'mysql.tidb_runaway_watch' doesn't exist 问题处理
作者: asd80703406 原文来源: https://tidb.net/blog/90394c97 背景 近期发现很多人从低版本升级至TiDB v7 或者v8版本,均遇到了tidb-server启动失败,提示报错如下: ["get runaway watch record failed"…...

GRU-PFG:利用图神经网络从股票因子中提取股票间相关性
“GRU-PFG: Extract Inter-Stock Correlation from Stock Factors with Graph Neural Network” 论文地址:https://arxiv.org/pdf/2411.18997 摘要 股票预测模型可以分为两个主要类别:第一类,例如GRU和ALSTM,这些模型仅基于股票…...

数字化供应链创新解决方案在零售行业的应用研究——以开源AI智能名片S2B2C商城小程序为例
摘要: 在数字化转型的浪潮中,零售行业正经历着前所未有的变革。特别是在供应链管理方面,线上线下融合、数据孤岛、消费者需求多样化等问题日益凸显,对零售企业的运营效率与市场竞争力构成了严峻挑战。本文深入探讨了零售行业供应…...
安卓Activity执行finish后onNewIntent也执行了
测试反应投屏时下一集可能播放不成功。 首先看一下日志: onCompletion onCast handlerMessage: 2 finish: PlayerActivityabc7fdc onPause: PlayerActivityabc7fdc onNewIntent: PlayerActivityabc7fdc onResume: PlayerActivityabc7fdc onPause: PlayerActivityab…...

数据结构.期末复习.学习笔记(c语言)
《数据结构》复习概要 一、概论 二、基础1. 基本概念2. 四种逻辑结构及特点3. 算法的概念、特性4. 算法设计的4个要求 三、线性结构1.顺序表2.单链表3.循环链表双向链表4.栈(后进先出)5.队列(先进先出) 四、树和二叉树1.树2.二叉…...

Kafaka安装与启动教程
1.下载 先去官网Apache Kafka可以查看到每个版本的发布时间。选择你要安装的版本。 然后进入linux建立要存放的文件夹,用wget命令下载 2.安装 先解压缩: tar -xvzf kafka_2.12-3.5.1.tgz -C ../ 3.配置文件 修改server.properties: cd .…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...