Vue3 + Element-plus + TS —— 动态表格自由编辑

9a69fede8b2044a79dd834e3e48f20b4.png前期回顾   

《 穿越时空的代码、在回首:Evil.js两年后的全新解读 》-CSDN博客

Vue3 + TS + Element-Plus 封装Tree组件 《亲测可用》_ icon-default.png?t=N7T8https://blog.csdn.net/m0_57904695/article/details/131664157?spm=1001.2014.3001.5501  

态表格 自由编辑

 

目录

♻️ 效果图 

 🚩 Vue2 版本

🐗 Vue3 版本


♻️ 效果图 

👉 在线预览

 🚩 Vue2 版本

<template>
  <!-- 可编辑表格V2 -->
  <div id="hello">
    <!-- 表格 -->
    <p class="tips">单击 右键菜单,单击 左键编辑</p>
    <el-table
      :data="tableData"
      height="500px"
      border
      style="width: 100%; margin-top: 10px"
      @cell-click="cellDblclick"
      @header-contextmenu="(column, event) => rightClick(null, column, event)"
      @row-contextmenu="rightClick"
      :row-class-name="tableRowClassName"
    >
      <el-table-column
        v-if="columnList.length > 0"
        type="index"
        :label="'No.'"
      />
      <el-table-column
        v-for="(col, idx) in columnList"
        :key="col.prop"
        :prop="col.prop"
        :label="col.label"
        :index="idx"
      />
    </el-table>
 
    <div>
      <h3 style="text-align: center">实时数据展示</h3>
      <label>当前目标:</label>
      <p>{{ JSON.stringify(curTarget) }}</p>
      <label>表头:</label>
      <p v-for="col in columnList" :key="col.prop">{{ JSON.stringify(col) }}</p>
      <label>数据:</label>
      <p v-for="(data, idx) in tableData" :key="idx">
        {{ JSON.stringify(data) }}
      </p>
    </div>
 
    <!-- 右键菜单框 -->
    <div v-show="showMenu" id="contextmenu" @mouseleave="showMenu = false">
      <p style="margin-bottom: 10px">列:</p>
      <el-button size="mini" type="primary" @click="addColumn()">
        前方插入一列
      </el-button>
      <el-button size="mini" type="primary" @click="addColumn(true)">
        后方插入一列
      </el-button>
 
      <el-button
        type="primary"
        size="mini"
        @click="openColumnOrRowSpringFrame('列')"
      >
        删除当前列
      </el-button>
 
      <el-button size="mini" type="primary" @click="renameCol($event)">
        更改列名
      </el-button>
 
      <div class="line"></div>
 
      <p style="margin-bottom: 12px">行:</p>
      <el-button
        size="mini"
        type="primary"
        @click="addRow()"
        v-show="!curTarget.isHead"
      >
        上方插入一行
      </el-button>
      <el-button
        size="mini"
        type="primary"
        @click="addRow(true)"
        v-show="!curTarget.isHead"
      >
        下方插入一行
      </el-button>
      <el-button
        size="mini"
        type="primary"
        @click="addRowHead(true)"
        v-show="curTarget.isHead"
      >
        下方插入一行
      </el-button>
      <el-button
        type="primary"
        size="mini"
        @click="openColumnOrRowSpringFrame('行')"
        v-show="!curTarget.isHead"
      >
        删除当前行
      </el-button>
    </div>
 
    <!-- 单元格/表头内容编辑框 -->
    <div v-show="showEditInput" id="editInput">
      <el-input
        v-focus
        placeholder="请输入内容"
        v-model="curTarget.val"
        clearable
        @change="updTbCellOrHeader"
        @blur="showEditInput = false"
        @keyup="onKeyUp($event)"
      >
        <template #prepend>{{ curColumn.label || curColumn.prop }}</template>
      </el-input>
    </div>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      columnList: [
        { prop: "name", label: "姓名" },
        { prop: "age", label: "年龄" },
        { prop: "city", label: "城市" },
        { prop: "tel", label: "电话" }
      ],
      tableData: [
        { name: "张三", age: 24, city: "广州", tel: "13312345678" },
        { name: "李四", age: 25, city: "九江", tel: "18899998888" }
      ],
      showMenu: false, // 显示右键菜单
      showEditInput: false, // 显示单元格/表头内容编辑输入框
      curTarget: {
        // 当前目标信息
        rowIdx: null, // 行下标
        colIdx: null, // 列下标
        val: null, // 单元格内容/列名
        isHead: undefined // 当前目标是表头?
      },
      countCol: 0 // 新建列计数
    };
  },
  computed: {
    curColumn() {
      return this.columnList[this.curTarget.colIdx] || {};
    }
  },
  methods: {
    // 删除当前列或当前行
    openColumnOrRowSpringFrame(type) {
      this.$confirm(
        `此操作将永久删除该 ${type === "列" ? "列" : "行"}, 是否继续 ?, '提示'`,
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(() => {
          if (type === "列") {
            this.delColumn();
          } else if (type === "行") {
            this.delRow();
          }
          this.$message({
            type: "success",
            message: "删除成功!"
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除"
          });
        });
    },
    // 回车键关闭编辑框
    onKeyUp(e) {
      if (e.keyCode === 13) {
        this.showEditInput = false;
      }
    },
    // 单元格双击事件 - 更改单元格数值
    cellDblclick(row, column, cell, event) {
      this.showEditInput = false;
      if (column.index == null) return;
      this.locateMenuOrEditInput("editInput", 200, event); // 编辑框定位
      this.showEditInput = true;
      // 当前目标
      this.curTarget = {
        rowIdx: row.row_index,
        colIdx: column.index,
        val: row[column.property],
        isHead: false
      };
    },
    // 单元格/表头右击事件 - 打开菜单
    rightClick(row, column, event) {
      // 阻止浏览器自带的右键菜单弹出
      event.preventDefault(); // window.event.returnValue = false
      this.showMenu = false;
      if (column.index == null) return;
      this.locateMenuOrEditInput("contextmenu", 140, event); // 菜单定位
      this.showMenu = true;
      // 当前目标
      this.curTarget = {
        rowIdx: row ? row.row_index : null, // 目标行下标,表头无 row_index
        colIdx: column.index, // 目标项下标
        val: row ? row[column.property] : column.label, // 目标值,表头记录名称
        isHead: !row
      };
    },
    // 去更改列名
    renameCol($event) {
      this.showEditInput = false;
      if (this.curTarget.colIdx === null) return;
      this.locateMenuOrEditInput("editInput", 200, $event); // 编辑框定位
      this.showEditInput = true;
    },
    // 更改单元格内容/列名
    updTbCellOrHeader(val) {
      if (!this.curTarget.isHead)
        // 更改单元格内容
        this.tableData[this.curTarget.rowIdx][this.curColumn.prop] = val;
      else {
        // 更改列名
        if (!val) return;
        this.columnList[this.curTarget.colIdx].label = val;
      }
    },
    // 新增行
    addRow(later) {
      this.showMenu = false;
      const idx = later ? this.curTarget.rowIdx + 1 : this.curTarget.rowIdx;
      let obj = {};
      this.columnList.forEach((p) => (obj[p.prop] = ""));
      this.tableData.splice(idx, 0, obj);
    },
    // 表头下新增行
    addRowHead() {
      // 关闭菜单
      this.showMenu = false;
      // 新增行
      let obj = {};
      // 初始化行数据
      this.columnList.forEach((p) => (obj[p.prop] = ""));
      // 插入行数据
      this.tableData.unshift(obj);
    },
    // 删除行
    delRow() {
      this.showMenu = false;
      this.curTarget.rowIdx !== null &&
        this.tableData.splice(this.curTarget.rowIdx, 1);
    },
    // 新增列
    addColumn(later) {
      this.showMenu = false;
      const idx = later ? this.curTarget.colIdx + 1 : this.curTarget.colIdx;
      const colStr = { prop: "col_" + ++this.countCol, label: "" };
      this.columnList.splice(idx, 0, colStr);
      this.tableData.forEach((p) => (p[colStr.prop] = ""));
    },
    // 删除列
    delColumn() {
      this.showMenu = false;
      this.tableData.forEach((p) => {
        delete p[this.curColumn.prop];
      });
      this.columnList.splice(this.curTarget.colIdx, 1);
    },
    // 添加表格行下标
    tableRowClassName({ row, rowIndex }) {
      row.row_index = rowIndex;
    },
    // 定位菜单/编辑框
    locateMenuOrEditInput(eleId, eleWidth, event) {
      let ele = document.getElementById(eleId);
      ele.style.top = event.clientY - 100 + "px";
      ele.style.left = event.clientX - 50 + "px";
      if (window.innerWidth - eleWidth < event.clientX) {
        ele.style.left = "unset";
        ele.style.right = 0;
      }
    }
  }
};
</script>
 
<style lang="scss" scoped>
#hello {
  position: relative;
  height: 100%;
  width: 100%;
}
.tips {
  margin-top: 10px;
  color: #999;
}
#contextmenu {
  position: absolute;
  top: 0;
  left: 0;
  height: auto;
  width: 120px;
  border-radius: 3px;
  box-shadow: 0 0 10px 10px #e4e7ed;
  background-color: #fff;
  border-radius: 6px;
  padding: 15px 0 10px 15px;
  button {
    display: block;
    margin: 0 0 5px;
  }
}
.hideContextMenu {
  position: absolute;
  top: -4px;
  right: -5px;
}
#editInput,
#headereditInput {
  position: absolute;
  top: 0;
  left: 0;
  height: auto;
  min-width: 200px;
  max-width: 400px;
  padding: 0;
}
#editInput .el-input,
#headereditInput .el-input {
  outline: 0;
  border: 1px solid #c0f2f9;
  border-radius: 5px;
  box-shadow: 0px 0px 10px 0px #c0f2f9;
}
.line {
  width: 100%;
  border: 1px solid #e4e7ed;
  margin: 10px 0;
}
</style>

🐗 Vue3 版本

<template>
	<div id="table-wrap">
		<!-- 可编辑表格-Vue3 + ElementPlus -->
		<el-table
			:data="questionChoiceVOlist"
			stripe
			border
			@cell-click="cellClick"
			@row-contextmenu="rightClick"
			:row-class-name="tableRowClassName"
			@header-contextmenu="(column: any, event: MouseEvent) => rightClick(null, column, event)"
		>
			<el-table-column
				type="index"
				label="序号"
				align="center"
				:resizable="false"
				width="70"
			/>

			<template #empty>
				<el-empty description="暂无数据" />
			</template>

			<el-table-column
				:resizable="false"
				align="center"
				v-for="(col, idx) in columnList"
				:key="col.prop"
				:prop="col.prop"
				:label="col.label"
				:index="idx"
			>
				<template #default="{ row }">
					<div
						v-if="col.type === 'button'"
						style="height: 75px; padding-top: 26px; width: 100%"
					>
						<el-badge type="warning" :value="getRiskLenght(row.riskIds)">
							<el-button size="small">
								{{ paramsIdType == 'detail' ? '查看' : '选择' }}
							</el-button>
						</el-badge>
					</div>
					<el-input-number
						v-if="col.type === 'input-number'"
						v-model.number="row[col.prop]"
						:min="0"
						:max="10"
						:step="0.1"
						:precision="2"
					/>
				</template>
			</el-table-column>
		</el-table>

		<!-- 右键菜单框 -->
		<div v-show="showMenu" id="contextmenu" @mouseleave="showMenu = false">
			<p style="margin-bottom: 10px; text-align: left">列:</p>
			<el-button :icon="CaretTop" @click="addColumn(false)"> 前方插入一列 </el-button>
			<el-button :icon="CaretBottom" @click="addColumn(true)"> 后方插入一列 </el-button>
			<el-button :icon="DeleteFilled" @click="openColumnOrRowSpringFrame('列')">
				删除当前列
			</el-button>
			<el-button @click="renameCol" :icon="EditPen"> 更改列名 </el-button>

			<div style="color: #ccc">-----------------------</div>

			<p style="margin-bottom: 12px">行:</p>
			<el-button :icon="CaretTop" @click="addRow(false)" v-show="!curTarget.isHead">
				上方插入一行
			</el-button>
			<el-button :icon="CaretBottom" @click="addRow(true)" v-show="!curTarget.isHead">
				下方插入一行
			</el-button>
			<el-button :icon="DeleteFilled" @click="addRowHead" v-show="curTarget.isHead">
				下方插入一行
			</el-button>
			<el-button
				:icon="DeleteFilled"
				@click="openColumnOrRowSpringFrame('行')"
				v-show="!curTarget.isHead"
			>
				删除当前行
			</el-button>
		</div>

		<!-- 输入框 -->
		<div v-show="showEditInput" id="editInput">
			<el-input
				ref="iptRef"
				placeholder="请输入内容"
				v-model="curTarget.val"
				clearable
				@change="updTbCellOrHeader"
				@blur="showEditInput = false"
				@keyup="onKeyUp($event)"
			>
				<template #prepend>{{ curColumn.label || curColumn.prop }}</template>
			</el-input>
		</div>

		<!-- 实时数据展示 Start-->
		<!-- 
		第二个和第三个参数来格式化JSON输出,其中null作为替换函数(这里不进行替换),2表示缩进级别。
		这样JSON数据会以格式化的形式展示,增加了可读性
		 -->
		<div>
			<h3 style="text-align: center; margin-top: 15px">实时数据展示</h3>
			<label>当前目标:</label>
			<pre><code>{{ JSON.stringify(curTarget, null, 2) }}</code></pre>
			<div style="width: 100%; height: auto">
				<label>表头:</label>
				<pre><code v-for="col in columnList" :key="col.prop">{{ JSON.stringify(col, null, 2) }}</code></pre>
			</div>

			<div>
				<label>数据:</label>
				<pre><code v-for="(data, idx) in questionChoiceVOlist" :key="idx">
					{{ JSON.stringify(data, null, 2) }}
				</code></pre>
			</div>
		</div>
		<!-- 实时数据展示 End-->
	</div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, toRefs, nextTick } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { DeleteFilled, CaretBottom, CaretTop, EditPen } from '@element-plus/icons-vue';
// Tips: locateMenuOrEditInput 可调整编辑框位置
interface Column {
	prop: string;
	label: string;
	type?: string;
}

interface Data {
	choiceCode: string;
	choiceContent: string;
	riskIds: string;
	itemScore: string | number;
	[key: string]: unknown;
}

interface Target {
	rowIdx: number | null;
	colIdx: number | null;
	val: string | null;
	isHead: boolean | undefined;
}

// 接收addEdit父组件传过来的数据,用于判断是新增、编辑、详情页面
const paramsIdType = 'detail';

const state = reactive({
	columnList: [
		{ prop: 'choiceCode', label: '选项编码' },
		{ prop: 'choiceContent', label: '选项内容' },
		{ prop: 'riskIds', label: '风险点', type: 'button' },
		{ prop: 'itemScore', label: '选项分值', type: 'input-number' },
	] as Column[],
	questionChoiceVOlist: [
		{
			choiceCode: 'A',
			choiceContent: '是',
			riskIds: '45,47',
			itemScore: 1,
			isClickCheckBtn: true,
			id: 1,
		},
		{
			choiceCode: 'B',
			choiceContent: '否',
			riskIds: '46',
			itemScore: 4,
			isClickCheckBtn: true,
			id: 2,
		},
		{
			choiceCode: 'C',
			choiceContent: '否',
			riskIds: '',
			itemScore: 4,
			isClickCheckBtn: true,
			id: 3,
		},
	] as Data[],
	showMenu: false, // 显示右键菜单
	showEditInput: false, // 显示单元格/表头内容编辑输入框
	curTarget: {
		// 当前目标信息
		rowIdx: null, // 行下标
		colIdx: null, // 列下标
		val: null, // 单元格内容/列名
		isHead: undefined, // 当前目标是表头?
	} as Target,
	countCol: 0, // 新建列计数
});
const iptRef = ref();

const { columnList, questionChoiceVOlist, showMenu, showEditInput, curTarget } = toRefs(state);

// 当前列
const curColumn = computed(() => {
	return curTarget.value.colIdx !== null
		? columnList.value[curTarget.value.colIdx]
		: { prop: '', label: '' };
});

// 计算风险点数量
const getRiskLenght = computed(() => {
	return (riskIds: string) => riskIds.split(',').filter(Boolean).length;
});

/**
 * 删除列/行
 * @method  delColumn
 * @param {  string }  type - '列' | '行'
 **/
const openColumnOrRowSpringFrame = (type: string) => {
	ElMessageBox.confirm(`此操作将永久删除该${type === '列' ? '列' : '行'}, 是否继续 ?, '提示'`, {
		confirmButtonText: '确定',
		cancelButtonText: '取消',
		type: 'warning',
	})
		.then(() => {
			if (type === '列') {
				delColumn();
			} else if (type === '行') delRow();

			ElMessage.success('删除成功');
		})
		.catch(() => ElMessage.info('已取消删除'));
};

// 回车键关闭编辑框
const onKeyUp = (e: KeyboardEvent) => {
	if (e.key === 'Enter') {
		showEditInput.value = false;
	}
};

// 控制某字段不能打开弹框
const isPop = (column: { label: string }) => {
	return column.label === '风险点' || column.label === '选项分值';
};

// 左键输入框
const cellClick = (
	row: { [x: string]: any; row_index: any },
	column: { index: null; property: string | number; label: string },
	_cell: any,
	event: MouseEvent
) => {
	// 如果是风险点或选项分值,不执行后续代码
	if (isPop(column)) return;

	iptRef.value.focus();
	if (column.index == null) return;
	locateMenuOrEditInput('editInput', -300, event); // 左键输入框定位 Y
	showEditInput.value = true;
	iptRef.value.focus();

	// 当前目标
	curTarget.value = {
		rowIdx: row.row_index,
		colIdx: column.index,
		val: row[column.property],
		isHead: false,
	};
};

// 表头右击事件 - 打开菜单
const rightClick = (row: any, column: any, event: MouseEvent) => {
	event.preventDefault();

	if (column.index == null) return;
	// 如果tableData有数据并且当前目标是表头,那么就返回,不执行后续操作
	// if (questionChoiceVOlist.value.length > 0 && !row) return;
	if (isPop(column)) return;

	showMenu.value = false;
	locateMenuOrEditInput('contextmenu', -500, event); // 右键输入框
	showMenu.value = true;
	curTarget.value = {
		rowIdx: row ? row.row_index : null,
		colIdx: column.index,
		val: row ? row[column.property] : column.label,
		isHead: !row,
	};
};

// 更改列名
const renameCol = () => {
	showEditInput.value = false;
	if (curTarget.value.colIdx === null) return;
	showEditInput.value = true;
	nextTick(() => {
		iptRef.value.focus();
	});
};

// 更改单元格内容/列名
const updTbCellOrHeader = (val: string) => {
	if (!curTarget.value.isHead) {
		if (curTarget.value.rowIdx !== null) {
			(questionChoiceVOlist.value[curTarget.value.rowIdx] as Data)[curColumn.value.prop] =
				val;
		}
	} else {
		if (!val) return;
		if (curTarget.value.colIdx !== null) {
			columnList.value[curTarget.value.colIdx].label = val;
		}
	}
};
// 新增行
const addRow = (later: boolean) => {
	showMenu.value = false;
	const idx = later ? curTarget.value.rowIdx! + 1 : curTarget.value.rowIdx!;
	let obj: any = {};
	columnList.value.forEach((p) => obj[p.prop]);
	questionChoiceVOlist.value.splice(idx, 0, obj);
	// 设置新增行数据默认值
	questionChoiceVOlist.value[idx] = {
		choiceCode: '',
		choiceContent: '',
		riskIds: '',
		itemScore: 0,
		id: Math.floor(Math.random() * 100000),
	};
};

// 表头下新增行
const addRowHead = () => {
	showMenu.value = false;
	let obj: any = {};
	columnList.value.forEach((p) => obj[p.prop]);
	questionChoiceVOlist.value.unshift(obj);
	questionChoiceVOlist.value[0] = {
		choiceCode: '',
		choiceContent: '',
		riskIds: '',
		itemScore: 0,
		id: Math.floor(Math.random() * 100000),
	};
};
// 删除行
const delRow = () => {
	showMenu.value = false;
	curTarget.value.rowIdx !== null &&
		questionChoiceVOlist.value.splice(curTarget.value.rowIdx!, 1);
};

// 新增列
const addColumn = (later: boolean) => {
	showMenu.value = false;
	const idx = later ? curTarget.value.colIdx! + 1 : curTarget.value.colIdx!;
	const colStr = { prop: 'Zk-NewCol - ' + ++state.countCol, label: '' };
	columnList.value.splice(idx, 0, colStr);
	questionChoiceVOlist.value.forEach((p) => (p[colStr.prop] = ''));
};

// 删除列
const delColumn = () => {
	showMenu.value = false;
	questionChoiceVOlist.value.forEach((p) => {
		delete p[curColumn.value.prop];
	});
	columnList.value.splice(curTarget.value.colIdx!, 1);
};

// 添加表格行下标
const tableRowClassName = ({ row, rowIndex }: { row: any; rowIndex: number }) => {
	row.row_index = rowIndex;
};

// 定位菜单/编辑框
const locateMenuOrEditInput = (eleId: string, distance: number, event: MouseEvent) => {
	if (window.innerWidth < 1130 || window.innerWidth < 660)
		return ElMessage.warning('窗口太小,已经固定菜单位置,或请重新调整窗口大小');
	const ele = document.getElementById(eleId) as HTMLElement;
	const x = event.pageX;
	const y = event.clientY + 200; //右键菜单位置 Y
	let left = x + distance + 200; //右键菜单位置 X
	let top;
	if (eleId == 'editInput') {
		// 左键
		top = y + distance;
		left = x + distance - 120;
	} else {
		// 右键
		top = y + distance + 170;
	}
	ele.style.left = `${left}px`;
	ele.style.top = `${top}px`;
};

defineExpose({
	questionChoiceVOlist,
});
</script>

<style lang="scss" scoped>
#table-wrap {
	width: 100%;
	height: 100%;
	/* 左键 */
	#contextmenu {
		position: absolute;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		z-index: 999999;
		top: 0;
		left: 0;
		height: auto;
		width: 200px;
		border-radius: 3px;
		border: #e2e2e2 1px solid;
		box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
		background-color: #fff;
		border-radius: 6px;
		padding: 15px 10px 14px 12px;

		button {
			display: block;
			margin: 0 0 5px;
		}
	}
	/* 右键 */
	#editInput {
		position: absolute;
		top: 0;
		left: 0;
		z-index: 999999;
	}
	/* 实时数据 */

	pre {
		border: 1px solid #cccccc;
		padding: 10px;
		overflow: auto;
	}
}
</style>

7730e2bd39d64179909767e1967da702.jpeg

 _______________________________  期待再见  _______________________________

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/739670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IS022000与HACCP:提升食品安全管理的完美结合

国际标准化组织&#xff08;ISO&#xff09;于2005年9月发布了IS022000:2005标准&#xff0c;这是一项针对食品安全管理体系的国际标准。我国以等同采用的方式制定了国家标准GB/T 22000-2006《食品安全管理体系食品链中各类组织的要求》&#xff08;以下简称“GB/T22000”&…

Docker搭建yolov8并训练、验证、推理化学仪器数据集

目录 1、安装docker 2、创建yolov8镜像 3、下载代码包 4、下载模型预训练权重 5、制作数据集 6、训练、验证及推理 &#xff08;1&#xff09;训练 &#xff08;2&#xff09;验证 &#xff08;3&#xff09;推理 中文标签显示问题 本文通过docker的方式搭建yolov8运…

C语言入门课程学习笔记10:结构体联合体位域

C语言入门课程学习笔记10 第48课 - 自定义数据类型&#xff08;上&#xff09;实验-typedef实验小结 第49课 - 自定义数据类型&#xff08;中&#xff09;实验实验小结 第50课 - 自定义数据类型&#xff08;下&#xff09;实验实验小结 第51课 - 多文件程序设计实验实验实验小结…

python项目加密和增加时间许可证

1.bat&#xff0c;执行如下的命令&#xff0c;第一句是更新或增加许可证 第二句是加密draw_face.py python offer.py pyarmor obfuscate -O dist draw_face.py绘制自制人脸.py&#xff0c;调用加密的代码draw_face代码 import sys import os import cv2# 添加加密模块所在的路…

[MYSQL] 数据库基础

1.什么是数据库 从数据库的名字可以看出,它是用来操作(增删查改....)数据的,事实上也的确如此,通过数据库,我们可以更方便.更高效的来操作.管理数据 以文件形式存储数据的缺点 文件的安全问题文件不利于数据的查询和删除文件不利于存储海量数据操作文件并不方便 为了解决上述问…

煤矿运输新篇章:数字孪生模型引领智能化转型

在科技日新月异的今天&#xff0c;煤矿行业也迎来了前所未有的发展机遇。在这个充满挑战与机遇的时代&#xff0c;煤矿运输数字孪生模型以其独特的魅力和巨大的潜力&#xff0c;引领着煤矿运输领域走向智能化、高效化的新时代。 数字孪生模型&#xff0c;就是在虚拟世界中构建一…

喜讯:ISO年度审核通过!

在数字化时代&#xff0c;质量是我们不变的追求。近日&#xff0c;矩阵起源迎来了一个值得庆祝的时刻——三项ISO体系年度考核顺利通过&#xff01;分别为&#xff1a;ISO9001 质量管理体系标准认证、ISO20000信息技术服务管理体系认证及ISO27001 信息安全管理体系认证。 ISO标…

【分布式事务】分布式事务理论

CAP 理论 一致性&#xff08;Consistency&#xff09; 分布式系统中所有数据备份&#xff0c;在同一时刻是否是同样的值 可用性&#xff08;Availability&#xff09; 集群中一部分节点故障后&#xff0c;集群整体是否还能响应客户端的读写请求 分区容错性&#xff08;Partit…

移动硬盘损坏无法读取:故障解析与数据恢复策略

一、现象描述&#xff1a;移动硬盘损坏无法读取的困境 在数字化时代&#xff0c;移动硬盘作为数据存储的重要工具&#xff0c;广泛应用于个人和企业中。然而&#xff0c;当移动硬盘突然损坏&#xff0c;无法被系统正常读取时&#xff0c;往往会带来极大的困扰。用户可能会遇到…

《2024天猫618大促-首波男装销售报告》

这份报告主要分析了2024年天猫618大促期间的首波男装销售情况,从多个维度进行了深入的复盘和分析。报告中不仅包含了销售数据的统计分析,还对消费者行为、品牌表现、产品趋势等方面进行了详细的解读。通过对这些数据和信息的深入挖掘,报告揭示了当前男装市场的一些重要趋势和特…

冻干食品市场飙升至新高度,预计到 2030 年将达到 717 亿美元

冻干食品市场&#xff0c;近年来经历了显著增长&#xff0c;2021 年价值 372 亿美元&#xff0c;预计到 2030 年将达到 717 亿美元。 从2022年到2030年&#xff0c;这一强劲的扩张是由7.7%的复合年增长率推动的&#xff0c;这是由于多种因素造成的&#xff0c;包括食品加工行…

Linux命令重温

目录 Linux安装基础命令lsllcdpwdmkdirrmdirtouchcpmvrmvi/vim>和>>catheadlessmoretailechoclearwhich 进阶命令其他命令 Linux安装 通过vmware设置模拟硬件环境安装centos系统进行相应的网络配置安装xshell bin 存放二进制可执行文件(ls,cat,mkdir等) boot 存放用…

【STM32+FPGA】先进算力+强安全+边缘AI,64位STM32MP2聚焦工业4.0应用

工业应用数字化和智能化程度&#xff0c;是衡量新质生产力的重要标准。STM32最新一代64位微处理器STM32MP2凭借先进算力、丰富接口和高安全性&#xff0c;为高性能和高度互联的工业4.0应用赋能。 STM32MP2四大关键特性&#xff0c;为工业4.0应用赋能 STM32MP2系列的第一颗产品S…

Java项目:基于SSM框架实现的电子竞技管理平台【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的电子竞技管理平台 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

【Python时序预测系列】基于LSTM实现单变量时序序列多步预测(案例+源码)

这是我的第307篇原创文章。 一、引言 单站点单变量输入单变量输出多步预测问题----基于LSTM实现。 单输入就是输入1个特征变量 单输出就是预测出1个标签的结果 多步就是利用过去N天预测未来M天的结果 二、实现过程 2.1 读取数据集 # 读取数据集 data pd.read_csv(data.c…

超级内卷时代,这样做,刻不容缓

分享一个月入十万的赚钱项目 别再抱怨手上项目不好做&#xff0c;生意不好做了&#xff0c;这只是个开始&#xff0c;长远来看&#xff0c;2024应该是未来几年中经济环境最好的一年&#xff0c;我们所有人都已经进入到“超级内卷”时代&#xff01; 随着竞争环境越来越激烈&…

欢乐钓鱼大师游戏攻略:内置免费辅助工具的云手机!自动钓鱼!

《欢乐钓鱼大师》是一款极具趣味性和挑战性的钓鱼模拟游戏&#xff0c;玩家可以在虚拟的世界中体验到真实钓鱼的乐趣。本文将详细介绍游戏的各个方面&#xff0c;包括基本操作、鱼种识别、装备选择、技巧提升等&#xff0c;帮助玩家快速上手并逐步提升钓鱼技能。 《欢乐钓鱼大师…

010-基于Sklearn的机器学习入门:聚类(上)

本节及后续章节将介绍深度学习中的几种聚类算法&#xff0c;所选方法都在Sklearn库中聚类模块有具体实现。本节为上篇&#xff0c;将介绍几种相对基础的聚类算法&#xff0c;包括K-均值算法和均值漂移算法。 目录 10.1 聚类概述 10.1.1 聚类的种类 10.1.2 Sklearn聚类子模…

前年升2区,去年升TOP,目前扩刊中,投稿难度较小,这本SSCI可纳入考虑~

【SciencePub学术】今天给大家推荐的是一本经济管理领域的SSCI&#xff0c;大家都称之为TOP刊中的易中“水刊”。据说很多人已经靠信息差吃上了这本TOP刊的红利&#xff0c;接下来给大家解析一下这本期刊。 《Socio-Economic Planning Sciences》是一本国际性的学术期刊&#x…

数据分析:微生物组差异丰度方法汇总

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 微生物数据具有一下的特点&#xff0c;这使得在做差异分析的时候需要考虑到更多的问题&…