当前位置: 首页 > article >正文

【JavaWeb学习Day27】

Tlias前端

员工管理

条件分页查询:

页面布局

搜索栏:

  
<!-- 搜索栏 --><div class="container"><el-form :inline="true" :model="searchEmp" class="demo-form-inline"><el-form-item label="姓名"><el-input  v-model="searchEmp.name" placeholder="请输入员工姓名" /></el-form-item><el-form-item label="性别"><el-select v-model="searchEmp.gender" placeholder="请选择"><el-option label="男" value="1" /><el-option label="女" value="2" /></el-select></el-form-item><el-form-item label="入职时间"><el-date-picker v-model="searchEmp.date" type="daterange" range-separator="到" start-placeholder="开始日期"end-placeholder="结束日期" :size="size" value-format="YYYY-MM-DD"/></el-form-item><el-form-item><el-button type="primary" @click="search">查询</el-button><el-button type="info" @click="clear">清空</el-button></el-form-item></el-form></div>

Watch:

作用:侦听一个或多个响应式数据源,并在数据源变化时调用传入的回调函数。

用法:1.导入Watch函数2.执行watch函数,传入要侦听的响应式数据源(ref对象)和回调函数

单个响应式变量:

侦听对象的全部属性:

第三个可选参数,常见两个选项:

deep(boolean)是否深度侦听,默认浅层侦听。

immediate(boolean)是否在侦听时创建立即触发的回调函数。

侦听对象的单个属性;

import { ref ,watch} from 'vue'
const searchEmp = ref({name: '',gender: '',date: [],begin: '',end: ''})
//侦听searchEmp的date
watch(() => searchEmp.value.date,(newval,oldval) => {if(searchEmp.value.date.length == 2 ){searchEmp.value.begin = newval[0]searchEmp.value.end = newval[1] }else{searchEmp.value.begin = ''searchEmp.value.end = ''}
})

按钮:

<!-- 按钮 --><div class="container"><el-button type="primary" @click="">+新增员工</el-button><el-button type="danger" @click="">-批量删除</el-button></div>

数据展示表格:

<div class="container"><el-table :data="empList" style="width: 100%"><el-table-column type="selection" width="55" /><el-table-column prop="name" label="姓名" width="120" align="center" /><el-table-column label="性别" width="120" align="center"><template #default="scope">{{ scope.row.gender == 1 ? '男' : '女' }}</template></el-table-column><el-table-column label="头像" align="center" width="180"><template #default="scope"><el-image :src="scope.row.image" style="width:40px" /></template></el-table-column><el-table-column prop="deptName" label="所属部门" width="120" align="center" /><el-table-column prop="job" label="职位" width="120" align="center"><template #default="scope"><span v-if="scope.row.job == 1">班主任</span><span v-else-if="scope.row.job == 2">讲师</span><span v-else-if="scope.row.job == 3">学工主管</span><span v-else-if="scope.row.job == 4">教研主管</span><span v-else-if="scope.row.job == 5">咨询师</span><span v-else>其他</span></template></el-table-column><el-table-column prop="entryDate" label="入职日期" width="180" align="center" /><el-table-column prop="updateTime" label="最后操作时间" width="180" align="center" /><!-- 操作 --><el-table-column label="操作" width="180" align="center"><template #default="scope"><el-button type="primary" size="small" @click=""><el-icon><EditPen /></el-icon>编辑</el-button><el-button type="danger" size="small" @click=""><el-icon><Delete /></el-icon>删除</el-button></template></el-table-column></el-table></div>

分页条:

//定义员工列表
const empList = ref([])
//分页
const currentPage = ref(1)//当前页
const pageSize = ref(10)//每页显示多少条
const background = ref(true)
const total = ref(0)
// 查询
const search = async () => {const res = await queryPageApi(searchEmp.value.name, searchEmp.value.gender,searchEmp.value.begin, searchEmp.value.end, currentPage.value, pageSize.value)if(res.code){empList.value = res.data.rowstotal.value = res.data.total }
​
}
//每页展示记录数变化时
const handleSizeChange = (val) => {search()
}
//当前页变化时
const handleCurrentChange = (val) => {search()
}
<!-- 分页条 --><div class="container"><el-paginationv-model:current-page="currentPage"v-model:page-size="pageSize":page-sizes="[5, 10, 15, 20, 25, 30, 35, 40]":background="background"layout="total, sizes, prev, pager, next, jumper":total="total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div>

页面交互:

1.页面加载完毕后,查询员工信息列表

2.点击查询按钮,查询员工信息列表

3.当页码、每页展示记录数发生变化时,查询员工信息列表

新增员工:

新增员工信息的表单包含两个部分:

员工的基本信息

员工的工作经历信息

新增/修改员工的对话框:

1.表单项数据动态展示:

性别(男/女) 职位(班主任/讲师/学工主管/教研主管/) 所属部门(动态查询)

2.工作经历:

添加工作经历:下方就会增加一个工作经历信息

删除工作经历:删除当前这一个工作经历信息

(Vue是基于数据驱动视图展示的)

  
  <!-- 新增/修改员工的对话框 -->
​<el-dialog v-model="dialogVisible" :title="dialogTitle">{{ employee }}<el-form ref="employeeFormRef" :model="employee" label-width="80px"><!-- 基本信息 --><!-- 第一行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="用户名"><el-input v-model="employee.username" placeholder="请输入员工用户名,2-20个字"></el-input></el-form-item></el-col>
​<el-col :span="12"><el-form-item label="姓名"><el-input v-model="employee.name" placeholder="请输入员工姓名,2-10个字"></el-input></el-form-item></el-col></el-row><!-- 第二行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="性别"><el-select v-model="employee.gender" placeholder="请选择性别" style="width: 100%;"><el-option v-for="g in genders" :label="g.name" :value="g.value"></el-option></el-select></el-form-item></el-col>
​<el-col :span="12"><el-form-item label="手机号"><el-input v-model="employee.phone" placeholder="请输入员工手机号"></el-input></el-form-item></el-col></el-row><!-- 第三行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="职位"><el-select v-model="employee.job" placeholder="请选择职位" style="width: 100%;"><el-option v-for="j in jobs" :label="j.name" :value="j.value"></el-option></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="薪资"><el-input v-model="employee.salary" placeholder="请输入员工薪资"></el-input></el-form-item></el-col></el-row><!-- 第四行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="所属部门"><el-select v-model="employee.deptId" placeholder="请选择部门" style="width: 100%;"><el-option v-for="d in deptList" :label="d.name" :key="d.id" :value="d.id"></el-option></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="入职日期"><el-date-picker v-model="employee.entryDate" type="date" style="width: 100%;" placeholder="选择日期"format="YYYY-MM-DD" value-format="YYYY-MM-DD"></el-date-picker></el-form-item></el-col></el-row><!-- 第五行 --><el-row :gutter="20"><el-col :span="24"><el-form-item label="头像"><el-upload class="avatar-uploader" action="/api/upload" :show-file-list="false":on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"><img v-if="employee.image" :src="employee.image" class="avatar" /><el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon></el-upload></el-form-item></el-col></el-row><!-- 工作经历 --><!-- 第六行 --><el-row :gutter="10"><el-col :span="24"><el-form-item label="工作经历"><el-button type="success" size="small" @click="addExpr">+ 添加工作经历</el-button></el-form-item></el-col></el-row><!-- 第七行 ...  工作经历 --><el-row :gutter="3" v-for="(expr, index) in employee.exprList"><el-col :span="10"><el-form-item size="small" v-model="expr.value.exprDate" label="时间" label-width="80px"><el-date-picker type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"format="YYYY-MM-DD" value-format="YYYY-MM-DD"></el-date-picker></el-form-item></el-col>
​<el-col :span="6"><el-form-item size="small" v-model="expr.company" label="公司" label-width="60px"><el-input placeholder="请输入公司名称"></el-input></el-form-item></el-col>
​<el-col :span="6"><el-form-item size="small" v-model="expr.job" label="职位" label-width="60px"><el-input placeholder="请输入职位"></el-input></el-form-item></el-col>
​<el-col :span="2"><el-form-item size="small" label-width="0px"><el-button type="danger" @click="deleteExpr(index)">- 删除</el-button></el-form-item></el-col></el-row></el-form><!-- 底部按钮 --><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="">保存</el-button></span></template>
​</el-dialog>

保存:

1.点击保存之后,发送异步请求到服务器,提交数据。

2.保存完毕后,如果成功,关闭对话框,重新加载列表数据。

3.保存完毕后,如果失败,提示错误信息。

修改员工:

查询回显:

为编辑按钮绑定事件,发送异步请求,根据ID查询员工详细信息,页面回显

 

​
//编辑员工信息
const editEmp = async (id) => {const result = await queryEmpByIdApi(id)if (result.code) {dialogVisible.value = truedialogTitle.value = '修改员工'employee.value = result.data} else {ElMessage.error(result.msg)}//对工作经历数据进行处理let exprList = employee.value.exprList//判断exprList是否有值和长度大于0if (exprList && exprList.length > 0) {exprList.forEach((expr) => {expr.exprDate = [expr.begin, expr.end]})}
}​

保存数据:

点击保存按钮,执行修改数据操作,备注:添加员工和修改员工使用的是同一个表单,需要根据id判断到底是执行新增还是修改。

//保存员工信息
const save = async () => {if (!employeeFormRef.value) {return}employeeFormRef.value.validate(async valid => {if (valid) { // 校验通过let result;if (employee.value.id) {result = await editEmpApi(employee.value)} else {result = await addEmpApi(employee.value)}if (result.code) {ElMessage.success('保存成功')dialogVisible.value = falsesearch()
​} else {ElMessage.error(result.msg)}} else {ElMessage.error('表单校验失败')}})
}

删除员工:

在删除员工信息时,有两个操作路口:

1.点击每条记录之后的“删除”按钮,删除当前这条记录

为“删除”按钮添加绑定事件,触发事件,调用函数,发送异步请求到服务端,根据id删除员工信息

//删除员工信息
const deleteById = async (id) => {ElMessageBox.confirm('你确定要删除该员工吗?', '提示',{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }).then(async () => {const result = await deleteEmpApi(id)
​if (result.code) {ElMessage.success('删除成功');search();} else {ElMessage.error(result.msg);}
​}).catch(() => {ElMessage.info('已取消删除')})
}

2.选择前面的复选框,选中要删除的员工,点击“批量删除”之后,会批量删除员工信息

为表格的复选框绑定事件,点击复选框之后,获取到目前选中的条件的id(多个id可以封装到数组中),为“批量删除”按钮绑定事件,发送异步请求到服务端,根据id批量删除员工信息。

//批量删除勾选的员工信息
const selectedIds = ref([])
//多选框选中时触发
const handleSelectionChange = (selection) => {selectedIds.value = selection.map(item => item.id)
}
//批量删除员工信息
const deleteBatch = () => {ElMessageBox.confirm('你确定要批量删除这些员工吗?', '提示',{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }).then(async () => {if (selectedIds.value && selectedIds.value.length > 0) {const result = await deleteEmpApi(selectedIds.value)
​if (result.code) {ElMessage.success('删除成功');search();} else {ElMessage.error(result.msg);}
​} else {ElMessage.error('您没有选择要删除的员工')}
​
​}).catch(() => {ElMessage.info('已取消删除')})
​
}

完整Vue代码:

<script setup>
import { Delete } from '@element-plus/icons-vue'
import { ref, watch, onMounted } from 'vue'
import { queryPageApi, addEmpApi, editEmpApi, queryEmpByIdApi, deleteEmpApi } from '@/api/emp'
import { ElMessage, ElMessageBox } from 'element-plus'
import { queryAllApi as queryAllDeptApi } from '@/api/dept'
​
//职位列表数据
const jobs = ref([{ name: '班主任', value: 1 }, { name: '讲师', value: 2 }, { name: '学工主管', value: 3 }, { name: '教研主管', value: 4 }, { name: '咨询师', value: 5 }, { name: '其他', value: 6 }])
//性别列表数据
const genders = ref([{ name: '男', value: 1 }, { name: '女', value: 2 }])
//部门列表数据
const deptList = ref([])
​
//定义钩子
onMounted(() => {search()//查询员工列表queryAllDept()//查询部门列表
})
//查询部门列表
const queryAllDept = async () => {const res = await queryAllDeptApi()if (res.code) {deptList.value = res.data}
}
//定义搜索条件
const searchEmp = ref({ name: '', gender: '', date: [], begin: '', end: '' })
​
​
​
//侦听searchEmp的date
watch(() => searchEmp.value.date, (newval, oldval) => {if (searchEmp.value.date.length == 2) {searchEmp.value.begin = newval[0]searchEmp.value.end = newval[1]} else {searchEmp.value.begin = ''searchEmp.value.end = ''}
})
// 清空
const clear = () => {searchEmp.value = { name: '', gender: '', date: [] }search()
​
​
}
​
//定义员工列表
const empList = ref([])
//分页
const currentPage = ref(1)//当前页
const pageSize = ref(10)//每页显示多少条
const background = ref(true)
const total = ref(0)
// 查询
const search = async () => {const res = await queryPageApi(searchEmp.value.name, searchEmp.value.gender,searchEmp.value.begin, searchEmp.value.end, currentPage.value, pageSize.value)if (res.code) {empList.value = res.data.rowstotal.value = res.data.total}
​
}
//每页展示记录数变化时
const handleSizeChange = (val) => {search()
}
//当前页变化时
const handleCurrentChange = (val) => {search()
}
//新增员工
const addEmp = () => {dialogVisible.value = truedialogTitle.value = '新增员工'employee.value = {username: '',name: '',gender: '',phone: '',job: '',salary: '',deptId: '',entryDate: '',image: '',exprList: []}//清空表单校验if (employeeFormRef.value) {employeeFormRef.value.resetFields()}
}
​
​
//新增/修改表单
const employeeFormRef = ref(null)
const employee = ref({username: '',name: '',gender: '',phone: '',job: '',salary: '',deptId: '',entryDate: '',image: '',exprList: []
})
​
// 控制弹窗
const dialogVisible = ref(false)
const dialogTitle = ref('新增员工')
​
//文件上传
// 图片上传成功后触发
const handleAvatarSuccess = (response, uploadFile) => {employee.value.image = response.data
}
// 文件上传之前触发
const beforeAvatarUpload = (rawFile) => {if (rawFile.type !== 'image/jpeg' && rawFile.type !== 'image/png') {ElMessage.error('只支持上传图片')return false} else if (rawFile.size / 1024 / 1024 > 10) {ElMessage.error('只能上传10M以内图片')return false}return true
}
//添加工作经历
const addExpr = () => {employee.value.exprList.push({company: '',job: '',begin: '',end: '',exprDate: []})
}
//删除工作经历
const deleteExpr = (index) => {employee.value.exprList.splice(index, 1)
}
//侦听exprList
watch(() => employee.value.exprList, (newValue, oldValue) => {if (employee.value.exprList && employee.value.exprList.length > 0) {employee.value.exprList.forEach(expr => {expr.begin = expr.exprDate[0]expr.end = expr.exprDate[1]})}
}, { deep: true });
​
//保存
//保存员工信息
const save = async () => {if (!employeeFormRef.value) {return}employeeFormRef.value.validate(async valid => {if (valid) { // 校验通过let result;if (employee.value.id) {result = await editEmpApi(employee.value)} else {result = await addEmpApi(employee.value)}if (result.code) {ElMessage.success('保存成功')dialogVisible.value = falsesearch()
​} else {ElMessage.error(result.msg)}} else {ElMessage.error('表单校验失败')}})
}
// 验证规则
const rules = ref({username: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 2, max: 20, message: '用户名长度应在2到20个字符之间', trigger: 'blur' }],name: [{ required: true, message: '请输入姓名', trigger: 'blur' },{ min: 2, max: 10, message: '姓名长度应在2到10个字符之间', trigger: 'blur' }],gender: [{ required: true, message: '请选择性别', trigger: 'change' }],phone: [{ required: true, message: '请输入手机号', trigger: 'blur' },{ pattern: /^1\d{10}$/g, message: '请输入有效的手机号', trigger: 'blur' }]
});
​
//编辑员工信息
const editEmp = async (id) => {const result = await queryEmpByIdApi(id)if (result.code) {dialogVisible.value = truedialogTitle.value = '修改员工'employee.value = result.data} else {ElMessage.error(result.msg)}//对工作经历数据进行处理let exprList = employee.value.exprList//判断exprList是否有值和长度大于0if (exprList && exprList.length > 0) {exprList.forEach((expr) => {expr.exprDate = [expr.begin, expr.end]})}
}
//删除员工信息
const deleteById = async (id) => {ElMessageBox.confirm('你确定要删除该员工吗?', '提示',{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }).then(async () => {const result = await deleteEmpApi(id)
​if (result.code) {ElMessage.success('删除成功');search();} else {ElMessage.error(result.msg);}
​}).catch(() => {ElMessage.info('已取消删除')})
}
//批量删除勾选的员工信息
const selectedIds = ref([])
//多选框选中时触发
const handleSelectionChange = (selection) => {selectedIds.value = selection.map(item => item.id)
}
//批量删除员工信息
const deleteBatch = () => {ElMessageBox.confirm('你确定要批量删除这些员工吗?', '提示',{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }).then(async () => {if (selectedIds.value && selectedIds.value.length > 0) {const result = await deleteEmpApi(selectedIds.value)
​if (result.code) {ElMessage.success('删除成功');search();} else {ElMessage.error(result.msg);}
​} else {ElMessage.error('您没有选择要删除的员工')}
​
​}).catch(() => {ElMessage.info('已取消删除')})
​
}
​
​
​
</script>
​
<template><h1>员工管理</h1><!-- 搜索栏 --><div class="container"><el-form :inline="true" :model="searchEmp" class="demo-form-inline"><el-form-item label="姓名"><el-input v-model="searchEmp.name" placeholder="请输入员工姓名" /></el-form-item><el-form-item label="性别"><el-select v-model="searchEmp.gender" placeholder="请选择"><el-option label="男" value="1" /><el-option label="女" value="2" /></el-select></el-form-item><el-form-item label="入职时间"><el-date-picker v-model="searchEmp.date" type="daterange" range-separator="到" start-placeholder="开始日期"end-placeholder="结束日期" :size="size" value-format="YYYY-MM-DD" /></el-form-item><el-form-item><el-button type="primary" @click="search">查询</el-button><el-button type="info" @click="clear">清空</el-button></el-form-item></el-form></div>
​<!-- 按钮 --><div class="container"><el-button type="primary" @click="addEmp">+新增员工</el-button><el-button type="danger" @click="deleteBatch">-批量删除</el-button></div><!-- 表格 --><div class="container"><el-table :data="empList" style="width: 100%" @selection-change="handleSelectionChange"><el-table-column type="selection" width="55" /><el-table-column prop="name" label="姓名" width="120" align="center" /><el-table-column label="性别" width="120" align="center"><template #default="scope">{{ scope.row.gender == 1 ? '男' : '女' }}</template></el-table-column><el-table-column label="头像" align="center" width="180"><template #default="scope"><el-image :src="scope.row.image" style="width:40px" /></template></el-table-column><el-table-column prop="deptName" label="所属部门" width="120" align="center" /><el-table-column prop="job" label="职位" width="120" align="center"><template #default="scope"><span v-if="scope.row.job == 1">班主任</span><span v-else-if="scope.row.job == 2">讲师</span><span v-else-if="scope.row.job == 3">学工主管</span><span v-else-if="scope.row.job == 4">教研主管</span><span v-else-if="scope.row.job == 5">咨询师</span><span v-else>其他</span></template></el-table-column><el-table-column prop="entryDate" label="入职日期" width="180" align="center" /><el-table-column prop="updateTime" label="最后操作时间" width="180" align="center" /><!-- 操作 --><el-table-column label="操作" width="180" align="center"><template #default="scope"><el-button type="primary" size="small" @click="editEmp(scope.row.id)"><el-icon><EditPen /></el-icon>编辑</el-button><el-button type="danger" size="small" @click="deleteById(scope.row.id)"><el-icon><Delete /></el-icon>删除</el-button></template></el-table-column></el-table></div><!-- 分页条 --><div class="container"><el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize":page-sizes="[5, 10, 15, 20, 25, 30, 35, 40]" :background="background"layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"@current-change="handleCurrentChange" /></div><!-- 新增/修改员工的对话框 -->
​<el-dialog v-model="dialogVisible" :title="dialogTitle"><el-form ref="employeeFormRef" :model="employee" label-width="80px" :rules="rules"><!-- 基本信息 --><!-- 第一行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="用户名" prop="username"><el-input v-model="employee.username" placeholder="请输入员工用户名,2-20个字"></el-input></el-form-item></el-col>
​<el-col :span="12"><el-form-item label="姓名" prop="name"><el-input v-model="employee.name" placeholder="请输入员工姓名,2-10个字"></el-input></el-form-item></el-col></el-row><!-- 第二行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="性别" prop="gender"><el-select v-model="employee.gender" placeholder="请选择性别" style="width: 100%;"><el-option v-for="g in genders" :label="g.name" :value="g.value"></el-option></el-select></el-form-item></el-col>
​<el-col :span="12"><el-form-item label="手机号" prop="phone"><el-input v-model="employee.phone" placeholder="请输入员工手机号"></el-input></el-form-item></el-col></el-row><!-- 第三行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="职位"><el-select v-model="employee.job" placeholder="请选择职位" style="width: 100%;"><el-option v-for="j in jobs" :label="j.name" :value="j.value"></el-option></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="薪资"><el-input v-model="employee.salary" placeholder="请输入员工薪资"></el-input></el-form-item></el-col></el-row><!-- 第四行 --><el-row :gutter="20"><el-col :span="12"><el-form-item label="所属部门"><el-select v-model="employee.deptId" placeholder="请选择部门" style="width: 100%;"><el-option v-for="d in deptList" :label="d.name" :key="d.id" :value="d.id"></el-option></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="入职日期"><el-date-picker v-model="employee.entryDate" type="date" style="width: 100%;" placeholder="选择日期"format="YYYY-MM-DD" value-format="YYYY-MM-DD"></el-date-picker></el-form-item></el-col></el-row><!-- 第五行 --><el-row :gutter="20"><el-col :span="24"><el-form-item label="头像"><el-upload class="avatar-uploader" action="/api/upload" :show-file-list="false":on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload"><img v-if="employee.image" :src="employee.image" class="avatar" /><el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon></el-upload></el-form-item></el-col></el-row><!-- 工作经历 --><!-- 第六行 --><el-row :gutter="10"><el-col :span="24"><el-form-item label="工作经历"><el-button type="success" size="small" @click="addExpr">+ 添加工作经历</el-button></el-form-item></el-col></el-row><!-- 第七行 ...  工作经历 --><el-row :gutter="3" v-for="(expr, index) in employee.exprList"><el-col :span="10"><el-form-item size="small" label="时间" label-width="80px"><el-date-picker v-model="expr.exprDate" type="daterange" range-separator="至" start-placeholder="开始日期"end-placeholder="结束日期" format="YYYY-MM-DD" value-format="YYYY-MM-DD"></el-date-picker></el-form-item></el-col>
​<el-col :span="6"><el-form-item size="small" label="公司" label-width="60px"><el-input v-model="expr.company" placeholder="请输入公司名称"></el-input></el-form-item></el-col>
​<el-col :span="6"><el-form-item size="small" label="职位" label-width="60px"><el-input v-model="expr.job" placeholder="请输入职位"></el-input></el-form-item></el-col>
​<el-col :span="2"><el-form-item size="small" label-width="0px"><el-button type="danger" @click="deleteExpr(index)">- 删除</el-button></el-form-item></el-col></el-row></el-form><!-- 底部按钮 --><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="save">保存</el-button></span></template>
​</el-dialog>
​
</template>
​
<style scoped>
.container {margin: 15px 0px;width: 100%;
}
​
.avatar {height: 40px;
}
​
.avatar-uploader .avatar {width: 78px;height: 78px;display: block;
}
​
.avatar-uploader .el-upload {border: 1px dashed var(--el-border-color);border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;transition: var(--el-transition-duration-fast);
}
​
.avatar-uploader .el-upload:hover {border-color: var(--el-color-primary);
}
​
.el-icon.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 78px;height: 78px;text-align: center;/* 添加灰色的虚线边框 */border: 1px dashed var(--el-border-color);
}
</style>

相关文章:

【JavaWeb学习Day27】

Tlias前端 员工管理 条件分页查询&#xff1a; 页面布局 搜索栏&#xff1a; <!-- 搜索栏 --><div class"container"><el-form :inline"true" :model"searchEmp" class"demo-form-inline"><el-form-item label…...

Webrtc编译官方示例实现视频通话

Webrtc编译官方示例实现视频通话 前言 webrtc官网demo中给了一个供我们学习和应用webrtc的一个很好的例子&#xff1a;peerconnection&#xff0c;这期我们就来编译和运行下这个程序看看视频通话的效果以。 1、打开源码工程 继上期源码编译完成后&#xff0c;我们使用vs打开…...

编程语言选择分析:C#、Rust、Go 与 TypeScript 编译器优化

编程语言选择分析&#xff1a;C#、Rust、Go 与 TypeScript 编译器优化 在讨论编程语言的选择时&#xff0c;特别是针对微软的 C# 和 Rust&#xff0c;以及谷歌的 Go 语言&#xff0c;以及微软试图通过 Go 来拯救 TypeScript 编译器的问题&#xff0c;我们可以从多个角度来分析和…...

信息学奥赛一本通 1610:玩具装箱 | 洛谷 P3195 [HNOI2008] 玩具装箱

【题目链接】 ybt 1610&#xff1a;玩具装箱 洛谷 P3195 [HNOI2008] 玩具装箱 【题目考点】 1. 动态规划&#xff1a;斜率优化动规 斜率优化动规模板题&#xff1a;信息学奥赛一本通 1607&#xff1a;【 例 2】任务安排 2 | 洛谷 P10979 任务安排 2 【解题思路】 玩具长度…...

数仓工具—Hive语法之不同纬度聚合

不同纬度聚合 提到不同纬度聚合,大家想到的肯定是grouping sets,或者是cube和rollup 其实这些我们之前都讲过,可以看看之前的文章 数仓工具—Hive语法之cube和rollup 数仓工具—Hive语法之grouping sets 但是我们今天遇到的问题是,使用的工具不支持grouping sets,既然…...

领码科技:在低代码技术浪潮中的分享与探索

前言&#xff1a; 25年的职业生涯&#xff0c;赋予了我深厚的技术积累与实践经验。从武汉大学的工测系毕业&#xff0c;到央企副总工的职位&#xff0c;我始终站在IT浪潮的最前沿。然而&#xff0c;离开企业后&#xff0c;我并未停止前行的脚步。从2024年11月起&#xff0c;我选…...

大数据学习(80)-数仓分层

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…...

刘强东突然发声:不该用算法压榨最底层兄弟!东哥,真正的人民企业家

今天忙了一天&#xff0c;很累&#xff0c;准备睡觉的时候&#xff0c;看到网上盛传的刘强东的朋友圈&#xff0c;东哥又在朋友圈发文了。 说实话&#xff0c;看完之后&#xff0c;感动&#xff0c;真的感动。 尤其是当我看到这两句话的时候。 1、我们所学的知识、商业模式、技…...

Java 记忆链表,LinkedList 的升级版

文章目录 记忆链表 MemoryLinkedList实战源代码 众所周知&#xff0c;ArrayList 和 LinkedList 是 Java 集合中两个基本的数据结构&#xff0c;对应数据结构理论中的数组和链表。但在这两个数据结构&#xff0c;开发者们通常使用 ArrayList&#xff0c;而不使用 LinkedList。JD…...

【构建CV图像识别系统】从传统方法到深度学习

目录 1. 图像的基本概念1.1 像素与色彩1.2 过滤与卷积 2. 图像分类与检测3. 图像特征的提取3.1 全局特征3.2 局部特征3.2.1 边缘&#xff08;Edge&#xff09;3.2.2 角点&#xff08;Corner&#xff09;3.2.3 SIFT 特征 4. 传统方法与深度学习在图像识别中的应用4.1 基于传统方…...

.net core集成MQTT服务端

程序作为MQTT的服务端&#xff0c;也是WebApi 接口地址&#xff0c;在Web页面中MQTTJS用的是Websocker协议&#xff0c;在Winfrom中用MQTT协议。导致程序需要启动两个端口。直接上代码 创建服务 引用包&#xff1a;MQTTnet&#xff0c;MQTTnet.AspNetCore&#xff0c;这包最新…...

poetry安装与使用

文章目录 安装方法创建虚拟环境其他常用命令从 poetry.lock 中安装第三方依赖包 安装方法 安装命令&#xff08;全局安装&#xff0c;不要在虚拟环境中安装&#xff0c;方便后面创建环境使用&#xff09; pip install poetry修改虚拟环境路径&#xff08;首次使用poetry时执行&…...

UVM config机制及uvm_resource_pool

目录 1. uvm_config_db 类源码 1.1 set 1.2 get 2. uvm_resource_pool 2.1 uvm_resource_pool::set 2.2 uvm_resource 3. usage 4. 小结 uvm提供一种uvm_config_db机制使得在仿真中通过变量设置来修改环境,使环境更加灵活。本文主要介绍uvm_config_db#(type)::get/set…...

JAVA学习*接口

接口 在生活中我们常听说USB接口&#xff0c;那接口是什么呢&#xff1f; 在Java中&#xff0c;接口相当于多个类的一种公共规范&#xff0c;是一种引用数据类型。 定义接口 public interface IUSB {public static final String SIZE "small";public abstract vo…...

Day11 动态规划入门

动态规划 就是 : 给定一个问题&#xff0c;我们把它拆成一个个子问题&#xff0c;直到子问题可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重复计算。再根据子问题答案反推&#xff0c;得出原问题解的一种方法. 记忆化搜索 暴力dfs 记录答案 动态规划入门思…...

WPF UI元素保存为图像文件

WPF UI元素保存为图像文件 实现功能示例代码使用示例关键代码说明WPF UI元素保存为图像文件 实现功能 将WPF界面元素(如控件、布局容器)的当前视觉内容保存为图像文件适用场景:截取控件的实时显示内容(如图表、界面快照);将动态生成的UI元素导出为图片用于分享、存档或打…...

指令型样本或偏好型样本有什么区别和联系

两者都是基于给定文本生成的训练样本&#xff0c;但侧重点和用途不同&#xff1a; 指令型样本&#xff08;Instruction-based samples&#xff09; 结构&#xff1a;通常是一个简单的指令和对应的回答&#xff0c;例如一对“问题&#xff0d;答案”或“指令&#xff0d;回答”。…...

neo4j-如何让外部设备访问wsl中的neo4j

WSL 运行在一个虚拟网络环境中&#xff0c;它的 IP 只能被宿主 Windows 访问&#xff0c;外部设备无法直接访问 WSL 的端口。你需要在 Windows 上转发端口&#xff0c;让外部设备可以访问 Windows 并映射到 WSL。 1. 获取 WSL 的 IP 地址 在 WSL 中运行以下命令获取其 IP 地址…...

Python实验:读写文本文件并添加行号

[实验目的] 熟练掌握内置函数open()的用法&#xff1b;熟练运用内置函数len()、max()、和enumerate()&#xff1b;熟练运用字符串的strip()、ljust()和其它方法&#xff1b;熟练运用列表推导式。 [实验和内容] 1.编写一个程序demo.py&#xff0c;要求运行该程序后&#xff0…...

IDEA导入jar包后提示无法解析jar包中的类,比如无法解析符号 ‘log4j‘

IDEA导入jar包后提示无法解析jar包中的类 问题描述解决方法 问题描述 IDEA导入jar包的Maven坐标后&#xff0c;使用jar中的类比如log4j&#xff0c;仍然提示比如无法解析符号 log4j。 解决方法 在添加了依赖和配置文件后&#xff0c;确保刷新你的IDE项目和任何缓存&#xff…...

抖音用户视频批量下载工具开发全解析

一、逆向工程原理剖析 1.1 抖音Web端防护体系 抖音采用五层防御机制保护数据接口: graph LRA[浏览器指纹检测] --> B[请求参数签名]B --> C[Cookie动态验证]C --> D[请求频率限制]D --> E[IP信誉评级] 1.2 核心参数解密 参数名称作用原理生成方式有效期x-bogu…...

数据结构——顺序栈seq_stack

前言&#xff1a;大家好&#x1f60d;&#xff0c;本文主要介绍了数据结构——顺序栈 目录 一、概念 1.1 顺序栈的基本概念 1.2 顺序栈的存储结构 二、基本操作 2.1 结构体定义 2.2 初始化 2.3 判空 2.4 判满 2.5 扩容 2.6 插入 入栈 2.7 删除 出栈 2.8 获取栈顶元…...

LangChain其它五类组件详解(1)—— 文档加载器(Document loaders)

LangChain其它五类组件详解(1)—— 文档加载器(Document loaders) 前言本篇摘要15. LangChain其它五类组件详解15.1 文档加载器(Document loaders)15.1.1 文档加载概述15.1.2 加载Markdown1. 基本用法2. 保留元素参考文献前言 本系列文章主要介绍WEB界面工具Gradio。Gra…...

JVM常见面试总结

JVM&#xff08;Java虚拟机&#xff09;是Java程序运行的核心&#xff0c;掌握JVM相关知识对于Java开发者至关重要。以下是JVM常见的面试问题总结&#xff1a; 1. JVM内存模型 问题&#xff1a;JVM的内存结构分为哪些部分&#xff1f; 答案&#xff1a; 方法区&#xff08;Met…...

美团Leaf分布式ID生成器使用教程:号段模式与Snowflake模式详解

引言 在分布式系统中&#xff0c;生成全局唯一ID是核心需求之一。美团开源的Leaf提供了两种分布式ID生成方案&#xff1a;号段模式&#xff08;高可用、依赖数据库&#xff09;和Snowflake模式&#xff08;高性能、去中心化&#xff09;。本文将手把手教你如何配置和使用这两种…...

python3.13.2安装详细步骤(附安装包)

文章目录 前言一、python3.13.2下载二、python3.13.2安装详细步骤1.查看安装文件2.启动安装程序3.安装模式选择4.自定义安装配置5.高级选项设置6.执行安装7.开始安装8.安装完成8.打开软件9.安装验证 前言 在数字化时代&#xff0c;Python 已成为不可或缺的编程语言。无论是开发…...

AI-Talk开发板之更换串口引脚

一、默认引脚 CSK6011A使用UART0作为Debug uart&#xff0c;AI-Talk开发板默认使用的GPIOA2和GPIOA3作为Debug uart的RX和TX&#xff0c;通过连接器CN6引出。 二 、更换到其它引脚 查看60xx_iomux_v1.0可以&#xff0c;UART0的tx和rx可以映射到很多管脚上。 结合AI-Talk开发板…...

深度解读DeepSeek:源码解读 DeepSeek-V3

深度解读DeepSeek&#xff1a;开源周&#xff08;Open Source Week&#xff09;技术解读 深度解读DeepSeek&#xff1a;源码解读 DeepSeek-V3 深度解读DeepSeek&#xff1a;技术原理 深度解读DeepSeek&#xff1a;发展历程 文章目录 整体流程模型初始化模型前向传播MoE https:/…...

JavaIO流的使用和修饰器模式(直击心灵版)

系列文章目录 JavaIO流的使用和修饰器模式 文章目录 系列文章目录前言一、字节流&#xff1a; 1.FileInputStream(读取文件)2.FileOutputStream(写入文件) 二、字符流&#xff1a; 1..基础字符流:2.处理流&#xff1a;3.对象处理流&#xff1a;4.转换流&#xff1a; 三、修饰器…...

爬虫入门re+bs4

目录 前言 1. 导入必要的库 2. 定义获取网页HTML内容的函数 get_html 3. 定义获取数据的函数 get_data 4. 定义获取文章正文内容的函数 content_text 5. 定义获取单条课程数据的函数 get_one_course_data 6. 定义保存数据的函数 save_data 7. 定义文件名合法化处理函数 sanitiz…...