多种拖拽= =自用留档
<template>
<div class="main-drag">
<div v-if="stencil === '0'" class="mapped-fields">
<el-form ref="mapped" :model="mapped" class="demo-fieldsForm">
<el-form-item label="切换数据集" prop="dataset" class="demo-fieldsForm">
<el-select v-model="mapped.dataset" placeholder="请选择数据集" @change="changeDataset">
<el-option v-for="(item) in mappedFieldsList" :key="item.fieldId" :label="item.fieldName"
:value="item.fieldId" />
</el-select>
</el-form-item>
</el-form>
</div>
<!--使用draggable组件-->
<div class="itxst">
<div class="drag-drop">
<div class="drag-drop-col calculators">
<p class="font-weight">拖拽字段到计算区域</p>
<transition>
<draggable v-model="calculators" v-bind="{ group: { name: 'itxst', pull: 'clone', put: false }, sort: false }"
animation="300" :move="onMove" @end="endCalculators">
<transition-group>
<div v-for="(item, index) in calculators" :key="index + 'number'"
:class="item.type === 'Number' ? 'calculators-item' : 'calculators-item-blue'">{{ item.name }}</div>
</transition-group>
</draggable>
</transition>
</div>
<!-- 数据集模块 -->
<div class="drag-drop-col">
<p class="font-weight">
{{ stencil === "0" ? '数据集的模板字段' : '数据源字段' }}
</p>
<draggable v-model="fields" v-bind="{ group: { name: 'itxst', pull: 'clone', put: false }, sort: false }"
animation="300" :move="onMove" @end="endFields">
<transition-group class="transition-groups">
<div v-for="(item, index) in fields" :key="index + 'fieldName'" class="field-item">
<Vptip :content="item.fieldName" :width="'100%'" style="max-width: 500px;" class="item">
{{ `${item.fieldName}` }}
</Vptip>
<!-- <el-tooltip class="item" effect="dark" :content="item.fieldName" placement="top"
style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">
<div>{{ item.fieldName }}</div>
</el-tooltip> -->
</div>
</transition-group>
</draggable>
</div>
<!-- 指标拖拽模块 -->
<div class="drag-drop-col">
<p class="font-weight">当前模板的指标字段</p>
<draggable v-model="indicators" v-bind="{ group: { name: 'itxst', pull: 'clone', put: false }, sort: false }"
animation="300" :move="onMove" @end="endFields">
<transition-group class="transition-groups">
<div v-for="(item, index) in indicators" :key="index + 'templateFieldName'" class="field-item"
style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">
<Vptip :content="item.templateFieldName" :width="'100%'" style="max-width: 500px;" class="item">
{{ `${item.templateFieldName}` }}
</Vptip>
<!-- <el-tooltip class="item" effect="dark" :content="item.templateFieldName"
style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;" placement="top">
<div>{{ item.templateFieldName }}</div>
</el-tooltip> -->
</div>
</transition-group>
</draggable>
</div>
</div>
<!-- 公式模块 -->
<div class="col-operations">
<div class="operations-left">
<p class="font-weight">计算区域</p>
<transition>
<draggable v-model="operations" group="itxst" animation="300" :move="onMove" @end="endOperationsOne">
<transition-group class="group-over">
<!-- 此处只能是index,因为存在上面两个列表拉下来两个的情况会产生相同的id -->
<div v-for="(item, index) in operations" :key="index" :class="decideSstyle(item.type, item.name)">
<div class="contains-item-name" v-if="item.name">
{{ item.name }}
</div>
<el-tooltip class="contains-item-names" effect="dark" placement="top" :open-delay="400"
v-if="item.templateFieldName">
<div slot="content">
<span>类型:指标字段</span><br />
<span>名称:{{ item.templateFieldName }}</span>
</div>
<div class="contains-item-name" v-if="item.templateFieldName">
{{ item.templateFieldName }}
</div>
</el-tooltip>
<el-tooltip class="contains-item-names" effect="dark" placement="top" :open-delay="400"
v-if="item.fieldName">
<div slot="content">
<span>{{ stencil === "0" ? '数据集名称' : '数据源名称' }}:{{ item.fieldBelongName }} </span><br />
<span>类型:{{ stencil === "0" ? '模板字段' : '数据源字段' }}</span><br />
<span>名称:{{ item.fieldName }} </span>
</div>
<div class="contains-item-name" v-if="item.fieldName">
{{ item.fieldName }}
</div>
</el-tooltip>
<div v-if="(item.name === 'SUM' || item.name === 'AVG') && item.open === false" class="margin-auto"
@click="item.open = true"><i class="el-icon-d-arrow-right"></i></div>
<div v-if="item.name === 'SUM' && item.open === true" class="sum-class">
<draggable :key="item.sumId + 'sum'" v-model="sumList[getSumIndex(item.sumId)].list" group="itxst"
animation="300" :move="onMove" @end="endOperationsTwo">
<transition-group class="trans-group">
<!-- 此处只能是index,因为存在上面两个列表拉下来两个的情况会产生相同的id -->
<div v-for="(itm, idx) in sumList[getSumIndex(item.sumId)].list" :key="idx + 'sum'"
class="field-item-father">
<div class="field-item" v-if="itm.name">
{{ itm.name }}
</div>
<el-tooltip class="tooltip-div" effect="dark" placement="top" :open-delay="200"
v-if="itm.templateFieldName">
<div slot="content">
<span>类型: 指标字段</span><br />
<span>名称:{{ itm.templateFieldName }}</span>
</div>
<div class="field-item" v-if="itm.templateFieldName">
{{ itm.templateFieldName }}
</div>
</el-tooltip>
<el-tooltip class="tooltip-div" effect="dark" placement="top" :open-delay="200"
v-if="itm.fieldName">
<div slot="content">
<span>{{ stencil === "0" ? '数据集名称' : '数据源名称' }}:{{ itm.fieldBelongName }}</span><br />
<span>类型: {{ stencil === "0" ? '模板字段' : '数据源字段' }}</span><br />
<span>名称:{{ itm.fieldName }}</span>
</div>
<div class="field-item" v-if="itm.fieldName">
{{ itm.fieldName }}
</div>
</el-tooltip>
</div>
</transition-group>
</draggable>
</div>
<div v-if="item.name === 'AVG' && item.open === true" class="sum-class">
<draggable :key="item.averageId + 'avg'" v-model="averageList[getAverageIndex(item.averageId)].list"
group="itxst" animation="300" :move="onMove" @end="endOperationsThree">
<transition-group class="trans-group">
<!-- 此处只能是index,因为存在上面两个列表拉下来两个的情况会产生相同的id -->
<div v-for="(itm, idx) in averageList[getAverageIndex(item.averageId)].list" :key="idx + 'avg'"
class="field-item-father">
<div class="field-item" v-if="itm.name">
{{ itm.name }}
</div>
<el-tooltip class="tooltip-div" effect="dark" placement="top" :open-delay="200"
v-if="itm.templateFieldName">
<div slot="content">
<span>类型: 指标字段</span><br />
<span>名称:{{ itm.templateFieldName }}</span>
</div>
<div class="field-item" v-if="itm.templateFieldName">
{{ itm.templateFieldName }}
</div>
</el-tooltip>
<el-tooltip class="tooltip-div" effect="dark" placement="top" :open-delay="200"
v-if="itm.fieldName">
<div slot="content">
<span>{{ stencil === "0" ? '数据集名称' : '数据源名称' }}:{{ itm.fieldBelongName }}</span><br />
<span>类型:{{ stencil === "0" ? '模板字段' : '数据源字段' }}</span><br />
<span>名称:{{ itm.fieldName }}</span>
</div>
<div class="field-item" v-if="itm.fieldName">
{{ itm.fieldName }}
</div>
</el-tooltip>
</div>
</transition-group>
</draggable>
</div>
<div v-if="(item.name === 'SUM' || item.name === 'AVG') && item.open === true" class="margin-auto"
@click="item.open = false"><i class="el-icon-d-arrow-left"></i></div>
</div>
</transition-group>
</draggable>
</transition>
<el-button class="button-calculation" size="mini" type="primary" @click="calculation()">生成计算</el-button>
</div>
<!-- 垃圾回收站 -->
<div class="operations-right" style="position: relative;">
<i class="el-icon-delete" style="position: absolute;top: 150px;left: 43%; "></i>
<draggable v-model="recycleBin" group="itxst" animation="300" :move="onMove" @end="endOperations">
<transition-group class="recycle recycle-group">
<!-- 此处只能是index,因为存在上面两个列表拉下来两个的情况会产生相同的id -->
<div v-for="(item, index) in recycleBin" :key="index" class="calculators-item">{{ item.name }}</div>
</transition-group>
</draggable>
</div>
</div>
</div>
</div>
</template>
<script>
// 拖拽组件
import Vptip from "@/components/vptip" // 自定义Tooltip 文字提示
import draggable from 'vuedraggable'
export default {
name: 'customField',
components: {
draggable,
Vptip
},
props: {
// 数据源字段
mappedFieldsList: {
type: Array,
default: () => []
},
// 区分模板还是评价 1:模板 0:评价
stencil: {
type: String,
default: ''
},
// 数据条件范围
rangeFieldList: {
type: Array,
default: () => []
},
// 页面初始渲染数据
formFieldsOne: {
type: Array,
default: () => []
}
},
data() {
return {
// 数据集
mapped: {
dataset: ''
},
// 计算器元素数组
calculators: [
{ id: 1, name: '1', type: 'Number' },
{ id: 2, name: '2', type: 'Number' },
{ id: 3, name: '3', type: 'Number' },
{ id: 4, name: '(', type: 'BracketsLeft' },
{ id: 5, name: '4', type: 'Number' },
{ id: 6, name: '5', type: 'Number' },
{ id: 7, name: '6', type: 'Number' },
{ id: 8, name: ')', type: 'BracketsRight' },
{ id: 9, name: '7', type: 'Number' },
{ id: 10, name: '8', type: 'Number' },
{ id: 11, name: '9', type: 'Number' },
{ id: 12, name: 'SUM', sumId: 1, open: true },
{ id: 13, name: '0', type: 'Number' },
{ id: 14, name: '.', type: 'DecimalPoint' },
{ id: 15, name: '/', type: 'Symbols' },
{ id: 16, name: 'AVG', averageId: 1, open: true },
{ id: 17, name: '+', type: 'Symbols' },
{ id: 18, name: '-', type: 'Symbols' },
{ id: 19, name: '*', type: 'Symbols' }
],
// 可拖拽的计算字段
fields: [],
// 可拖拽的指标字段
indicators: [],
// 计算生成的算式
operations: [],
// 进行回收的字段
recycleBin: [],
// 拖拽的是什么
moveId: '',
// 空数组之在的样式,设置了这个样式才能拖入
style: 'min-height:200px;display: block;',
// 是否通过校验
passingCalibration: true,
// SUM之中的字段
sumList: [],
// AVG之中的字段
averageList: [],
// 计算num数组从第几个开始算起
listSumId: 1,
// 计算AVG数组从第几个开始算起
listAverageId: 1,
// numId:进行新添加的id的时候从第几个开始加
numId: 20
}
},
computed: {
getSumIndex() {
return this.findSumIndex
},
getAverageIndex() {
return this.findAverageIndex
}
},
watch: {
formFieldsOne: {
handler(item1, item2) {
this.rest(this.formFieldsOne)
},
immediate: true
}
},
mounted() {
// 放入对应的数据源字段
if (this.stencil === '0') {
this.fields = []
} else {
this.fields = this.mappedFieldsList
}
// 对应指标字段
this.indicators = this.rangeFieldList
},
methods: {
// 重置操作
rest(ruleForm) {
// 数据集
this.mapped.dataset = ''
if (this.stencil === '0') {
// 可拖拽的计算字段
this.fields = []
}
// 计算生成的算式
this.operations = ruleForm[0] !== undefined ? ruleForm[0] : []
// AVG之中的字段
this.averageList = ruleForm[1] !== undefined ? ruleForm[1] : []
// SUM之中的字段
this.sumList = ruleForm[2] !== undefined ? ruleForm[2] : []
// 计算num数组从第几个开始算起
let numSum = 0
for (let i = 0; i < this.sumList.length; i++) {
if (numSum < this.sumList[i].sumId) {
numSum = this.sumList[i].sumId
}
}
this.calculators.splice(11, 1, { id: 12, name: 'SUM', sumId: numSum + 1, open: true })
this.listSumId = numSum + 1
// 计算AVG数组从第几个开始算起
let numAvg = 0
for (let i = 0; i < this.averageList.length; i++) {
if (numAvg < this.averageList[i].averageId) {
numAvg = this.averageList[i].averageId
}
}
this.calculators.splice(15, 1, { id: 16, name: 'AVG', averageId: numAvg + 1, open: true })
this.listAverageId = numAvg + 1
// numId:进行新添加的id的时候从第几个开始加
this.numId = 20
},
// 更改选项对父组件进行传值
changeDataset() {
for (let i = 0; i < this.mappedFieldsList.length; i++) {
if (this.mapped.dataset === this.mappedFieldsList[i].fieldId) {
this.fields = this.mappedFieldsList[i].fieldList
}
}
},
// 进行渲染的计算属性计算
findSumIndex(sumId) {
return this.sumList.findIndex(item => item.sumId === sumId)
},
findAverageIndex(averageId) {
return this.averageList.findIndex(item => item.averageId === averageId)
},
// 进行计算器拖拽
endCalculators(e) {
// 阻止拖拽事件
if (e.relatedContext && e.relatedContext.element instanceof HTMLElement &&
e.draggedContext.element.type === 'Symbols' &&
e.relatedContext.element.classList.contains('sum-class')) {
e.cancel()
}
// 如果拖拽的是SUM
if (this.moveId === 'SUM') {
this.calculators.splice(11, 1, { id: this.numId, name: 'SUM', sumId: this.listSumId + 1, open: true })
this.listSumId++
this.numId++
}
// 如果拖拽的是AVG
if (this.moveId === 'AVG') {
this.calculators.splice(15, 1, { id: this.numId, name: 'AVG', averageId: this.listAverageId + 1, open: true })
this.listAverageId++
this.numId++
}
const that = this
that.recycleBin = []
},
// 进行元素字段拖拽
endFields(e) {
const that = this
that.recycleBin = []
},
// 进行删除拖动
endOperations(e) {
this.recycleBin = []
},
// 进行删除拖动
endOperationsOne(e) {
this.recycleBin = []
},
// 进行删除拖动
endOperationsTwo(e) {
this.recycleBin = []
},
// 进行删除拖动
endOperationsThree(e) {
this.recycleBin = []
},
// move回调方法
onMove(e, originalEvent) {
if (this.sumList.length === 0) this.sumList = []
if (this.averageList.length === 0) this.averageList = []
this.moveId = e.draggedContext.element.name
let index = -1
for (let i = 0; i < this.sumList.length; i++) {
if (this.sumList[i].sumId === this.listSumId) {
index = i
}
}
// 如果是在进行sum拖拽添加空数组
if (e.draggedContext.element.name === 'SUM') {
if (index !== -1) {
this.sumList.splice(index, 1, { sumId: this.listSumId, list: [] })
} else {
this.sumList.push({ sumId: this.listSumId, list: [] })
}
}
// 如果是在进行AVERAGE拖拽添加空数组
let indexAvg = -1
for (let i = 0; i < this.averageList.length; i++) {
if (this.averageList[i].averageId === this.listAverageId) {
indexAvg = i
}
}
if (e.draggedContext.element.name === 'AVG') {
if (indexAvg !== -1) {
this.averageList.splice(indexAvg, 1, { averageId: this.listAverageId, list: [] })
} else {
this.averageList.push({ averageId: this.listAverageId, list: [] })
}
}
/**
* 禁止往SUM中拖拽计算器内容
* if(拖拽位置停靠在SUM内||停靠位置为第一个数据且外围有数据)
* &&不是向回收站拖拽
* &&(类型不是undefined名称&&不是SUM){不允许拖拽}
*/
if ((e.related.className === 'field-item-father' ||
(this.operations.length !== 0 && e.relatedContext.list.length === 0)) &&
e.related.className !== 'recycle recycle-group' &&
(e.draggedContext.element.type !== undefined || e.draggedContext.element.name === 'SUM' || e.draggedContext.element.name === 'AVG')
) {
return false
}
return true
},
// 操控计算区域样式
decideSstyle(type, name) {
// 如果是字段或者求和求差
if (type === undefined) {
if (name === 'AVG' || name === 'SUM') {
return 'contains-item'
}
return 'field-item-down'
// 如果是数字
} else if (type === 'Number') {
return 'calculators-item-down'
// 如果是运算符
} else {
return 'calculators-item-blue-down'
}
},
sureFieldOne() {
this.calculation()
if (this.passingCalibration === true) {
return true
} else {
return false
}
},
// 生成计算
calculation() {
this.passingCalibration = true
// 如果计算区域为空
if (this.operations.length === 0) {
// Msg0052:运算表达式不符合规则
this.$message.error(this.$manages.Msg0052)
return
}
// 括号栈
const stack = []
for (let i = 0; i < this.operations.length; i++) {
// 进行括号堆栈的判断
// 存在左括号就将左括号存进去
if (this.operations[i].type === 'BracketsLeft') {
stack.push('(')
}
// 存在右括号
if (this.operations[i].type === 'BracketsRight') {
// 如果在没有左括号的前提下存在了右括号为不合理
if (stack.length === 0) {
this.passingCalibration = false
}
// 正常情况下存在了右括号将堆栈删掉一个
stack.pop()
}
// 只看前一个和后一个的情况下
if (i > 0 && i < this.operations.length - 1) {
// 当当前为字段时
if (this.operations[i].type === undefined) {
// 上一个不能为字段
// 上一个不能为数字
// 上一个不能为小数点
// 下一个不能为字段
// 下一个不能为数字
// 下一个不能为小数点
if (this.operations[i - 1].type === undefined ||
this.operations[i - 1].type === 'Number' ||
this.operations[i - 1].type === 'DecimalPoint' ||
this.operations[i + 1].type === undefined ||
this.operations[i + 1].type === 'Number' ||
this.operations[i + 1].type === 'DecimalPoint'
) {
this.passingCalibration = false
}
// 当当前为数字时
} else if (this.operations[i].type === 'Number') {
// 上一个不能为字段
// 下一个不能为字段
if (this.operations[i - 1].type === undefined ||
this.operations[i + 1].type === undefined
) {
this.passingCalibration = false
}
// 当当前为运算符的时候
} else if (this.operations[i].type === 'Symbols') {
// 上一个不能为运算符
// 上一个不能为小数点
// 上一个不能为左括号
// 下一个不能为运算符
// 下一个不能为小数点
// 下一个不能为右括号
if (this.operations[i - 1].type === 'Symbols' ||
this.operations[i - 1].type === 'DecimalPoint' ||
this.operations[i - 1].type === 'BracketsLeft' ||
this.operations[i + 1].type === 'Symbols' ||
this.operations[i + 1].type === 'DecimalPoint' ||
this.operations[i + 1].type === 'BracketsRight'
) {
this.passingCalibration = false
}
// 当当前为左括号的时候
} else if (this.operations[i].type === 'BracketsLeft') {
// 上一个不能为小数点
// 下一个不能为小数点
if (this.operations[i - 1].type === 'DecimalPoint' ||
this.operations[i + 1].type === 'DecimalPoint' ||
this.operations[i - 1].type === 'Number' ||
this.operations[i - 1].type === undefined
) {
this.passingCalibration = false
}
// 当当前为右括号的时候
} else if (this.operations[i].type === 'BracketsRight') {
// 上一个不能为小数点
// 下一个不能为小数点
if (this.operations[i - 1].type === 'DecimalPoint' ||
this.operations[i + 1].type === 'DecimalPoint' ||
this.operations[i + 1].type === 'Number' ||
this.operations[i + 1].type === undefined
) {
this.passingCalibration = false
}
// 当为小数点时
} else if (this.operations[i].type === 'DecimalPoint') {
// 下一个只能为数字
// 上一个只能为数字
if (this.operations[i - 1].type !== 'Number' ||
this.operations[i + 1].type !== 'Number'
) {
this.passingCalibration = false
}
let j = i
j++
// 对小数点后面的数字进行判断
while (j < this.operations.length - 1) {
j++
const type = this.operations[j].type
// 如果进入到了运算符,括号证明此数字结束可以进行跳出
if (type === 'Symbols' ||
type === 'BracketsLeft' ||
type === 'BracketsRight') {
j = this.operations.length
// 如果在跳出前再次遇见小数点则证明不合理
} else if (type === 'DecimalPoint') {
this.passingCalibration = false
j = this.operations.length
}
}
}
}
}
// 如果最后括号数没归零则等式不合理
if (stack.length !== 0) {
this.passingCalibration = false
}
// 开头如果不是数字字段百分号左括号就不符合
if (this.operations[0].type !== 'Number' &&
this.operations[0].type !== undefined &&
this.operations[0].type !== 'BracketsLeft') {
this.passingCalibration = false
}
// 结尾如果不是数字字段右括号就不符合
if (this.operations[this.operations.length - 1].type !== 'Number' &&
this.operations[this.operations.length - 1].type !== undefined &&
this.operations[this.operations.length - 1].type !== 'BracketsRight') {
this.passingCalibration = false
}
// 排除掉仅有两位且还不同字段的情况,
// 排除掉两个都为后端字段的情况
if (this.operations.length === 2 && (
this.operations[0].type === undefined ||
this.operations[1].type === undefined)) {
this.passingCalibration = false
}
// 如果仅为一位的时候
if (this.operations.length === 1) {
if (this.operations[0].type === 'Number' || this.operations[0].type === undefined) {
this.passingCalibration = true
}
}
// 进行SUM和AVG是否有值的判断
for (let i = 0; i < this.operations.length; i++) {
if (this.operations[i].name === 'SUM') {
const presence = this.sumList.findIndex(item => item.sumId === this.operations[i].sumId)
// 如果SUM内容为空
if (this.sumList[presence].list.length === 0) {
this.passingCalibration = false
}
} else if (this.operations[i].name === 'AVG') {
const presence = this.averageList.findIndex(item => item.averageId === this.operations[i].averageId)
// 如果AVG内容为空
if (this.averageList[presence].list.length === 0) {
this.passingCalibration = false
}
}
}
// 如果计算列式不合理
if (this.passingCalibration === false) {
// Msg0052:运算表达式不符合规则
this.$message.error(this.$manages.Msg0052)
// 如果计算列式合理
} else {
this.$emit('get-custom-calculation', this.operations, this.averageList, this.sumList)
}
}
}
}
// 原生拖拽自带逻辑
// eslint-disable-next-line no-extend-native
Array.prototype.filter = Array.prototype.filter || function (func) {
var arr = this
var r = []
for (var i = 0; i < arr.length; i++) {
if (func(arr[i], i, arr)) {
r.push(arr[i])
}
}
return r
}
</script>
<style lang="scss" scoped>
.main-drag {
width: 60vw;
height: auto;
overflow: hidden;
}
.mapped-fields {
height: 10vh;
width: calc(60vw - 2px);
min-height: 60px;
min-width: 530px;
border: solid 1px #DCDFE6;
border-radius: 3px;
display: flex;
flex-direction: column;
justify-content: center;
margin-bottom: 20px;
.demo-fieldsForm {
margin-left: 20px;
::v-deep .el-form-item {
margin-bottom: 0;
}
}
}
.itxst {
width: 60vw;
height: auto;
overflow: hidden;
text-align: left;
}
.drag-drop {
display: flex;
border: solid 1px #DCDFE6;
border-radius: 5px;
margin-bottom: 20px;
padding: 10px 10px;
.calculators {
width: 200px;
}
}
.col-operations {
height: auto;
display: flex;
margin-top: 10px;
overflow: hidden;
.operations-left {
height: auto;
min-height: 200px;
width: 88%;
border: solid 1px #DCDFE6;
border-radius: 5px;
margin-right: 2%;
padding: 1%;
.button-calculation {
float: right;
}
}
.operations-right {
height: auto;
min-height: 200px;
width: 10%;
border: dashed 1px #DCDFE6;
border-radius: 5px;
background: #dfdfdf;
}
}
.drag-drop-col {
height: 250px;
padding: 10px;
float: left;
overflow: auto;
width: calc(29vw - 100px);
}
.drag-drop-col+.drag-drop-col {
border-left: 1px dashed #DCDFE6;
}
.col {
width: 100%;
height: 200px;
flex: 1;
padding: 10px;
border: solid 1px #DCDFE6;
border-radius: 5px;
float: left;
}
.calculators-item {
height: 22px;
line-height: 20px;
width: auto;
min-width: 32px;
float: left;
border: 1px solid #b3d8ff;
color: #409eff;
background: #ecf5ff;
font-size: 14px;
text-align: center;
border-radius: 3px;
margin: 4px;
}
.calculators-item:hover {
cursor: move;
}
.calculators-item-down {
height: 30px;
line-height: 30px;
width: auto;
min-width: 32px;
float: left;
border: 1px solid #b3d8ff;
color: #409eff;
background: #ecf5ff;
font-size: 14px;
text-align: center;
border-radius: 3px;
margin: 5px;
}
.calculators-item-down:hover {
cursor: move;
}
.calculators-item-blue {
height: 22px;
line-height: 20px;
width: auto;
min-width: 32px;
float: left;
border: 1px solid #409eff;
color: #fff;
background: #409eff;
font-size: 12px;
text-align: center;
border-radius: 3px;
margin: 4px;
}
.calculators-item-blue:hover {
cursor: move;
}
.calculators-item-blue-down {
height: 30px;
line-height: 30px;
width: auto;
min-width: 32px;
float: left;
border: 1px solid #409eff;
color: #fff;
background: #409eff;
font-size: 12px;
text-align: center;
border-radius: 3px;
margin: 5px;
}
.calculators-item-blue-down:hover {
cursor: move;
}
.field-item {
color: #e6a23c;
text-align: center;
width: 93px;
height: 24px;
line-height: 24px;
border-radius: 4px;
border: 1px solid #e6a23c;
background-color: #fdf6ec;
float: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin: 2px;
font-size: 12px;
}
.field-item-father {
float: left;
}
.field-item:hover {
cursor: move;
}
.field-item-down {
color: #e6a23c;
text-align: center;
width: 93px;
height: 30px;
line-height: 30px;
border-radius: 4px;
border: 1px solid #e6a23c;
background-color: #fdf6ec;
float: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin: 5px;
}
.field-item-down:hover {
cursor: move;
}
.contains-item {
min-height: 28px;
line-height: 28px;
width: auto;
min-width: 25px;
float: left;
margin: 5px;
color: #fff;
background: #409eff;
text-align: center;
display: flex;
border: 1px solid #409eff;
border-radius: 3px;
// height: 30px;
}
.contains-item:hover {
cursor: move;
}
.contains-item-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 35px;
margin: auto;
}
.contains-item-names {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 35px;
margin: auto;
}
.sum-class {
min-height: 26px;
min-width: 100px;
height: auto;
border-left: 1px solid #c0c0c0;
border-radius: 3px;
float: left;
background-color: #fff;
}
.group-over {
overflow: auto;
max-height: 250px;
height: auto;
min-height: 200px;
display: block;
}
.font-weight {
font-weight: 700;
}
::v-deep .transition-groups {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.margin-auto {
margin: auto;
}
.trans-group {
height: auto;
min-height: 28px;
display: block;
}
.recycle-group {
height: 200px;
display: block;
}
::v-deep .tooltip-div {
width: 93px !important;
height: 24px !important;
}
</style>
相关文章:

多种拖拽= =自用留档
<template> <div class"main-drag"> <div v-if"stencil 0" class"mapped-fields"> <el-form ref"mapped" :model"mapped" class"demo-fieldsForm"> <el-form-item label"切换数…...

贝叶斯与认知——读《贝叶斯的博弈》有感
关于对贝叶斯与认知问题的相关思考 一、贝叶斯定理二、贝叶斯与认知的本质三、经验的偏见四、总结 自古以来,人们就在思考知识来自何处,“冯翼惟象,何以识之?”,对此的思考逐渐发展成哲学的认识论分支。德国哲学家康德…...

MySQL安装失败starting the sever
MySQL安装失败starting the sever 如果电脑是第一次安装MySQL,一般不会出现这样的报错。starting the sever失败,通常是因为上次安装该软件没有清除干净。 第一种解决方法:完全卸载mysql,重新安装 完全卸载该软件的办法&#…...

合并文件夹中所有文件,并输出重复的条形码值
文章目录 一、需求二、处理方式三、代码实现 一、需求 每天会生成一个记录文件(文件名按日期yyyyMMdd格式命名),记录文件中记录有条形码的内容,需要合并最近20次的数据,并提取出有重复的条形码。 也可以进行最近30天数…...

P3089 [USACO13NOV] Pogo-Cow S 弹簧踩高跷
P3089 [USACO13NOV] Pogo-Cow S 弹簧踩高跷 洛谷题目传送门 文章目录 P3089 [USACO13NOV] Pogo-Cow S 弹簧踩高跷题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题目大意方法一(线段树维护dp)code 方法二 (单调队列维护dp&…...

计算机网络 - 第一章(下)
1.2_1 分层结构、协议、接口、服务_哔哩哔哩_bilibili1.2_1 分层结构、协议、接口、服务是王道计算机考研 计算机网络的第7集视频,该合集共计76集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV19E411D78…...

【Uniapp】小程序携带Token请求接口+无感知登录方案2.0
本次改进原文《【Uniapp】小程序携带Token请求接口无感知登录方案》,在实际使用过程中我发现以下bug: 若token恰好在用户访问接口时到期,就会直接查询为空,不反映token过期问题(例如:弹窗显示订单查询记录…...

Ubuntu常用命令
文章目录 1:文件管理2:文档编辑3:系统管理4:磁盘管理5:文件传输6:网络通讯7:设备管理8:备份压缩9:其他命令扩展:知识干货 1:文件管理 ls命令 –…...

ERP重构-SLA子分类账-分布式实现方案
背景 ERP中的GL总账模块,明细数据来源于各个业务模块如库存、成本、应收、应付、费控、资产等,统称为子模块,生成的账叫做子分类账。然而记账的业务逻辑各式各样,但是最终输出都是来源、类型、期间、科目、借贷金额等等关键信息。…...

IP路由协议(RIP、IGRP、OSPF、IS-IS、BGP)
文章目录 1、路由分类2、RIP协议1)RIP的工作原理2)RIP路由表的更新过程3)RIP路由表的更新原则4)RIP的特性5)RIP协议的版本 4、IGRP协议1)IGRP路由表的更新2)IGRP的度量标准 5、OSPF协议1&#x…...

互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
多线程访问共享资源的时候,避免不了资源竞争而导致数据错乱的问题,所以我们通常为了解决这一问题,都会在访问共享资源之前加锁。 最常用的就是互斥锁,当然还有很多种不同的锁,比如自旋锁、读写锁、乐观锁等࿰…...
Python WSGI 与 Web 开发框架
目录 文章目录 目录WSGIWSGI 的工作原理environ 参数start_resposne 参数 WSGI 的中间件 WSGI Web 开发框架OpenStack 中的应用案例进程入口WSGI Application 加载Paste/PasteDeployRoutesWebOb WSGI Server 启动 WSGI WSGI(Web Server Gateway Interfaceÿ…...

[洛谷]P6464 [传智杯 #2 决赛] 传送门
看到数据范围:n<100,嗯......脑子闪过:还在想什么呢!Floyd啊。哈哈哈 思路: 详细注释: 话不多说,上ACcode!: #include<bits/stdc.h> using namespace std; #define int lo…...

Http协议和RestTemplate协议有什么区别?
目录 一、功能不同 二、技术不同 三、使用场景不同 四、总结 RestTemplate 是一个 Spring 框架提供的用于发送 HTTP请求的客户端工具,它封装了 Java 原生的 HTTP 客户端库,并提供了一组简洁易用的 API 来发送 HTTP 请求和处理响应。而 HTTPÿ…...

基于SpringBoot+微信小程序的医院预约叫号小程序
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 该项目是基于uniappWe…...

springboot整合RabbitMQ 消费端处理数据
pom 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>写一个rabbitmq配置文件 import org.springframework.amqp.core.Binding; import org.springframewo…...

计算机中CPU、内存、缓存的关系
CPU(Central Processing Unit,中央处理器) 内存(Random Access Memory,随机存取存储器) 缓存(Cache) CPU、内存和缓存之间有着密切的关系,它们共同构成了计算机系统的核…...

【Linux实验】构造一个简单的 shell
一、实验目的 l 用 C/C++构造一个简单的 shell; l 理解 shell 程序的功能; l 学会 shell 的使用;...

【电路原理学习笔记】第2章:电压、电流和电阻:2.6 电路
第2章:电压、电流和电阻 2.6 电路 2.6.1 电流的方向 电流方向有两种说法,一种按电子流动方向,另一种是传统的认为从正极流出到负极,这本教材采用传统电流方法。(事传统派,维新派输了,1&#…...

基于深度学习的人脸检测技术
用到环境 1、pycharm community edition 2022.3.2 2、Python 3.10 整篇内容都已上传至我的csdn资源中,想用的请移步。 流程 多任务级联卷积神经网络(Multi-task Cascaded Convolutional Networks, MTCNN)算法进行人脸检测 普通人脸检测 单人人脸检测 图1 单人人…...

【linux kernel】一文总结linux内核通知链
文章目录 1、通知链简介2、通知链的类型3、原理分析和API(1)注销通知器(2)注销通知器(3)通知链的通知 4、实例代码(1)定义一个通知链(2)实现观察者模块&#…...

kafka入门,Kafka 副本(十三)
Kafka副本 副本基本信息 1)Kafka副本作用,提高数据可靠性 2)Kafka默认副本1个,生产环境一般配置2个,保证数据可靠性,太多副本会增加磁盘存储空间,增加网络上数据传输,降低效率 3&a…...

利用PPT制作简单的矢量图
1.用PPT画一个图形(可以多个图) 2.鼠标圈住图形 3.利用 Ctrl G 组合图形,再用 Ctrl C 复制 4.打开word—粘贴—选择性粘贴—图片(增强性图元文件) 确认即可。...

18-Linux 常用命令
目录 1.ls PS:FinalShell设置背景和字体 2.pwd 3.cd PS:认识 Linux 目录结构——Linux 是一个树形目录结构 PS:绝对路径 vs 相对路径 PS:使用 tab 键补全 PS:使用 ctrl c 重新输入 4.touch PS:L…...

2024考研408-计算机组成原理第六章-总线学习笔记
文章目录 前言初识总线一、总线概述1.1、总线的概述1.1.1、认识总线1.1.2、设计总线需要的特性1.1.3、总线的分类①按照数据传输格式分(串行、并行)②按照总线功能连接的总线(片内总线、系统总线、通信总线)③按照时序控制方式&am…...

uni_app 微信小程序 苹果手机 边框显示不全

vue 访问第三方 跨域, 配置vue.config.js
目录 0 config 文件被修改 一个要重启vscode 配置文件才会生效 1 第一种 (有两种写法) 1.1 配置vue.config.js 1.2 axios 使用 1.3 终端打印 2 第二种方法 --> 错误 --> 没有运行成功 2.1 配置vue.config.js --> 就是api 不被设置成 替换为 / 2.2 axios 使用…...

使用gradio库的File模块实现文件上传和展示
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...

网络安全进阶学习第四课——SSRF服务器请求伪造
文章目录 一、什么是SSRF?二、SSRF成因三、SSRF简析四、PHP存在SSRF的风险函数五、后台源码获取方式六、SSRF危害七、SSRF漏洞挖掘从WEB功能上寻找,从URL关键字中寻找 八、SSRF具体利用ssrf常利用的相关协议PHP伪协议读取文件端口扫描 九、SSRF存在的必要…...

js处理扁平数组和树结构相互转换
一、将扁平的数据转为树形结构 在 js中,可以使用递归算法将扁平的数据转换为树形结构。 扁平数据通常是一个带有 parentId 属性的数组,而树形结构通常是一个带有 children 属性的对象。 1、方法一 下面是一个简单的例子,演示如何将扁平数…...