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

能源党建后台项目总结

1.引入

本次框架是Ruoyi-plus+vue2+element组合。

2.样式

由于是后台项目,样式要求统一,不可以有的输入框长有的短。着重几点:

1.关于form表单应该如何水平布局

在element中,form有个属性叫::inline="true"时候就会水平。但是有问题有的输入框比较长,像日期选择器和普通输入框大小就不一致。此时就不应该使用这个属性。应该用el-row,el-col。因为输入框默认是独占一行的就像div

代码如下

 <el-form :model="queryParams" ref="queryForm" label-width="80px"><el-row :gutter="20"><el-col :span="8"><el-form-item label="考核年度" prop="appraisalYear"><el-date-pickerv-model="queryParams.appraisalYear"type="year"placeholder="选择年"value-format="yyyy-MM-dd"></el-date-picker></el-form-item></el-col><el-col :span="8"><el-form-item label="负责人" prop="userId"><el-select v-model="queryParams.userId" placeholder="请选择"><el-optionv-for="(item, index) in userList":key="index":label="item.nickName":value="item.userId"></el-option></el-select></el-form-item></el-col><el-col :span="8"><el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button><el-button icon="el-icon-refresh-right" @click="resetQuery">重置</el-button></el-col></el-row></el-form>

2.当form表单过多时,如何布局

添加一个模板  <template v-if="advanced">利用advanced去控制遮住还是隐藏

    <el-form :model="queryParams" ref="queryForm" label-width="80px"><el-row :gutter="20"><el-col :span="8"><el-form-item label="时间" prop="date"><el-date-pickerv-model="queryParams.date"type="daterange"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"></el-date-picker></el-form-item></el-col><el-col :span="8"><el-form-item label="名称" prop="taskName"><el-inputv-model="queryParams.taskName"placeholder="请输入"clearable/></el-form-item></el-col><template v-if="advanced"><el-col :span="8"><el-form-item label="紧急程度" prop="level"><el-select v-model="queryParams.level" placeholder="请选择"><el-option label="一般" value="0"></el-option><el-option label="急" value="1"></el-option><el-option label="紧急" value="2"></el-option></el-select></el-form-item></el-col><el-col :span="8"><el-form-item label="阅读状态" prop="isRead"><el-select v-model="queryParams.isRead" placeholder="请选择"><el-option label="未读" value="0"></el-option><el-option label="已读" value="1"></el-option></el-select></el-form-item></el-col><el-col :span="8"><el-form-item label="任务状态" prop="status"><el-select v-model="queryParams.status" placeholder="请选择"><el-option label="未开始" value="0"></el-option><el-option label="进行中" value="1"></el-option><el-option label="已提交" value="2"></el-option><el-option label="已完成" value="3"></el-option></el-select></el-form-item></el-col></template><el-col :span="8"><div style="margin-left: 30px"><el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button><el-button icon="el-icon-refresh-right" @click="resetQuery">重置</el-button><a @click="toggleAdvanced" style="margin-left: 16px">{{ advanced ? "收起" : "展开" }}<i:class="advanced ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i></a></div></el-col></el-row></el-form>

3.业务逻辑

重点!!!先说说详情,编辑,行复制,删除,导入,导出,多选框的表格,单选框的表格,时间搜索,vue2数组和表单数据的渲染,文件的回显,图片的回显,还有es6语法,js逻辑。

1.详情

详情的话可以取决于你的页面是否和新增长的一样,如果长的一样,可以表单控制一个disabled属性来控制禁止输入

例子

 <el-form-item label="考核年度" prop="fulfillYear"><el-date-pickerv-model="form.fulfillYear"type="year"placeholder="选择年度"value-format="yyyy":disabled="disabled"></el-date-picker></el-form-item>

2.新增

外层的新增和编辑我会使用一个页面,没啥好说的。重点是内层新增她还可以编辑这个重点。如何编辑完可以拿到回调的值,这个难。

在编辑的页面增加一个标识符判断编辑还是新增

 save() {console.log("this.form", this.form);// this.$emit("getList", this.form);this.$emit("getList", {...this.form,addType: this.title === "新增考评指标" ? "add" : "edit",time: new Date().getTime(),});this.innerVisible = false;},

在新增的页面判断是新增还是编辑

    getList(value) {let newAddData = [];console.log("我收到了子组件新增标准的值", value);if (value.addType === "edit") {// 创建一个与this.tableData相同结构和内容的新数组// 使用JSON.parse(JSON.stringify(object))来深拷贝对象,避免直接修改原对象let marr = JSON.parse(JSON.stringify(this.tableData));// marr.forEach((item, index) => {//   if (index == value.index) {//     item = value;//   }// });marr[value.index] = value;console.log(marr);this.tableData = marr;console.log(marr);} else {if (Array.isArray(value)) {newAddData = [...this.tableData, ...value];} else {// 若 res.data 不是数组,将其包装成数组再进行合并newAddData = [...this.tableData, value];}// const newList = [...this.tableData, value];this.tableData = newAddData;// this.tableData.sort((a, b) => {//   // 先按照sort字段降序排序//   if (a.sort !== b.sort) {//     return a.sort - b.sort;//   } // 如果sort相同,则按照time字段升序排序(转换为毫秒)//   else {//     return b.time - a.time;//   }// });}// const newList = [...this.tableData, value];// this.tableData = newList;console.log("this.tableData", this.tableData);console.log("this.deptOptions", this.deptOptions);// 遍历tableData数组,根据deptId查找对应的labelthis.tableData = this.tableData.map((item) => {const deptName = this.findLabelById(item.deptId, this.deptOptions);const userIds = item.userIds?.split(",");if (userIds) {const userNames = userIds.map((item2) => {const user = this.userList.find((item3) => item3.userId === item2);// console.log("userNames", userNames);return user ? user.nickName : null;}).join(",");return { ...item, deptName, userNames };} else {return { ...item, deptName };}});console.log("this.tableData", this.tableData);},

这边要注意什么是浅拷贝和深拷贝,我之前都是浅拷贝,这边要改成深拷贝,深拷贝的话避免直接修改原对象。

3.编辑

编辑的话,通常后台需要传当前行的数据进去,后端会提供一个id,去查找数据,数据回显就好了。主要是文件和图片的回显看下面

4.行复制

代码如下 深拷贝一个对象这样不会影响原对象, delete copy.createTime;删除对象属性 es6语法,这边的逻辑就是复制一个和原对象无关的对象,然后用接口新增。 这边重点是es6语法和深浅拷贝的了解与引用

1.深拷贝

const copy = JSON.parse(JSON.stringify(row));

2. 浅拷贝

 const copy = Object.assign({}, row);
  • 如果修改的是第一层(直接)属性且它们是原始类型,row 不受影响;
  • 如果修改的是第一层(直接)属性且它们是引用类型(如其他对象或数组),实际上是在修改共享的嵌套对象,此时 row 会相应地发生改变。
  • 例子如下
  • const row = {name: 'John',address: {street: 'Main St.',number: 123,},
    };const copy = Object.assign({}, row);// 修改第一层属性(字符串),不影响 row
    copy.name = 'Jane'; // row.name仍然是'John'// 修改嵌套对象的属性,会影响 row
    copy.address.street = 'New St.'; // row.address.street现在也是'New St.'

 async copyRow(row) {console.log("row", row);// this.loading = true;const copy = JSON.parse(JSON.stringify(row));delete copy.createTime;copy.dutyAppraisalId = null;copy.status = nullcopy.isRead = 0copy.progress = 0console.log("copy", copy);await this.getDetail(row.dutyAppraisalId);addDemo({status: 0,type: 0,...copy,dutyItems: this.tableData,}).then((res) => {if (res.code == 200) {this.$message({message: "新建成功",type: "success",});this.loading = false;this.getList();}});// .finally(() => {//   this.loading = false;// });},

5.删除

在这个项目中有3中删除

第一种:利用接口拿到id,接口删除

  del(No, data) {// console.log("No", No, "DATA", data);if (data.workItemId) {delDetailList(data.workItemId).then((res) => {if (res.code == 200) {this.$message({message: "删除成功",type: "success",});this.deleteFuc(No, data);}});} else {this.deleteFuc(No, data);}},

第二种:不需要调用接口时候,利用filter es6的语法

 // 使用数组的filter方法,传入一个回调函数作为筛选条件// 回调函数接受当前遍历项(item)作为参数,检查其"No"属性是否与传入的No参数相异// 若相异则保留该项,否则过滤掉const filterData = this.originalData.filter((item) => {return item.No !== No;});

第三种:直接用数组splice

      this.fileList.splice(index, 1);

6.导入

三部曲

第一步:

 <el-uploadclass="upload-demo":action="uploadFileUrl"multiple:show-file-list="false":headers="headers":on-success="handleUploadSuccess"><el-button>导入</el-button></el-upload>

第二步:定义, id不存在,存在,不确定存不存在的写法都在下方

import { getToken } from "@/utils/auth";
export default {components: { contentSet, editStandard },data() {return {activeName: "first",activeName2: "first",form: {},title: "",dialogVisible: false,// 接收数据tableData: [],updatedData: [],// 字典值List: [],showData: [], //展示数据originalData: [], //真正的数据// rowData: {}, //行数据uploadFileUrl: `${process.env.VUE_APP_BASE_API}/epb/workItem/importData${this.form && this.form.id ? "?workId=" + this.form.id : ""}`,// uploadFileUrl: `${process.env.VUE_APP_BASE_API}/epb/workItem/importData?workId=${this.form.id}`, // 上传文件服务器地址// uploadFileUrl: process.env.VUE_APP_BASE_API + "/epb/workItem/importData", // 上传文件服务器地址headers: {Authorization: "Bearer " + getToken(),},show: false,workList: [],loading: false,};},

第三步:

 // 导入文件handleUploadSuccess(res, file) {// console.log("res", res, "file", file);if (res.code == 200) {//深拷贝let mArr = JSON.parse(JSON.stringify(tableData));// 页面操作  concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。mArr = mArr.concat(res.data.workItemVos);mArr = mArr.map((item, index) => {return {...item,sort: item.sort + 1, //一开始就遍历加上序号markTime: new Date().getTime(),};});// console.log("mArr", mArr);this.getContentList(mArr);// this.workList = [];this.workList = this.workList.concat(res.data.workLabelVos);console.log("this.workList", this.workList);}},

7.导出

 <el-buttontype="primary"plainicon="el-icon-download"@click="handleExport">导出</el-button>/** 导出按钮操作 */handleExport() {this.download("/epb/dutyFulfill/export",{...this.queryParams,},`责任落实档案列表.xlsx`);},

8.多选框的表格

9.单选框的表格

10.时间搜索

    getList() {// this.getTime();let mData = Object.assign({pageNum: this.pagination.current,pageSize: this.pagination.pageSize,},// this.queryParams{...this.queryParams,startTime: this.queryParams?.date?.length ? dayjs(this.queryParams.date[0]).format("YYYY-MM-DD") : undefined,endTime: this.queryParams?.date?.length > 1 ? dayjs(this.queryParams.date[1]).format("YYYY-MM-DD") : undefined,});mData.createUserId = store.getters.userId;this.loading = true;listDemo(mData).then((res) => {if (res.code == 200) {console.log("res", res);this.remindersList = res.rows;console.log("this.remindersList", this.remindersList);this.pagination.total = res.total;this.loading = false;}}).finally(() => {this.loading = false;});},

11.对象的键名

   //         const obj = {//             a: 1,//             b: 2,//             c: []//           }//           obj['c']就是数组,拿到的是obj.c的值,可以用push
  groupAndMergeData(arr) {// console.log("a2222", arr);let groupedData = {}; // 遍历newAddData,按workContent字段分类arr.forEach((item) => {//         const obj = {//             a: 1,//             b: 2,//             c: []//           }//           obj['c']就是数组,拿到的是obj.c的值,可以用pushif (!groupedData[item.workContent]) {// [item.workContent]表示键名groupedData[item.workContent] = [item];} else {groupedData[item.workContent].push(item);// groupedData[item.workContent].sort((a, b) => a.sort - b.sort);groupedData[item.workContent].sort((a, b) => {// 先按照sort字段降序排序if (a.sort !== b.sort) {return a.sort - b.sort;} // 如果sort相同,则按照time字段升序排序(转换为毫秒)else {return b.markTime - a.markTime;}});}});// console.log("arr11111", arr);// console.log("groupedData", groupedData);// 合并所有子数组let mergedData = [];for (let category in groupedData) {mergedData = [...mergedData, ...groupedData[category]];}// console.log("mergedData", mergedData);// 全部数据保存到这个真正的数据里const sortData = [...mergedData].map((item, index) => {return {...item,No: index + 1, //一开始就遍历加上序号};});return sortData;},

分组 一种是对象的分组,一种的数组的分组

数组的分组

  let classifyWorkContentList = []; //类别数组[...sourceData].forEach((item) => {// .includes()方法返回一个布尔值(true或false)if (classifyWorkContentList.indexOf(item.workContent) === -1) {classifyWorkContentList.push(item.workContent);}});

12.文件的回显

  const fileArr =data?.fileUrl?.split(",")?.map((item, index) => {return {fileUrl: item,fileName: data?.fileName?.split(",")[index],};}) || [];this.form = data;this.$set(this.form, "fileList", fileArr);<el-descriptions-item label="附件" :span="2"><span v-for="(item, index) in form.fileList" :key="index"><a :href="item.fileUrl" target="_blank">{{ item.fileName }}</a>,</span></el-descriptions-item>

这边的index因为fileUrl和fileName不是一个数组里的,俩个本来是俩个字符串,然后用split分隔成俩个数组,这边的操作就是把它们弄到一个数组里

13.图片的回显

<template><div><el-image v-for="(item,index) in realSrcList" :key="index":src="`${item}`"fit="cover":style="`width:${realWidth};height:${realHeight};`":preview-src-list="realSrcList"><div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div></el-image></div></template><script>export default {name: "ImagePreview",props: {src: {type: String,default: ""},width: {type: [Number, String],default: ""},height: {type: [Number, String],default: ""}},computed: {realSrc() {if (!this.src) {return;}let real_src = this.src.split(",")[0];return real_src;},realSrcList() {if (!this.src) {return;}let real_src_list = this.src.split(",");let srcList = [];real_src_list.forEach(item => {return srcList.push(item);});return srcList;},realWidth() {return typeof this.width == "string" ? this.width : `${this.width}px`;},realHeight() {return typeof this.height == "string" ? this.height : `${this.height}px`;}},
};
</script><style lang="scss" scoped>
.el-image {border-radius: 5px;background-color: #ebeef5;box-shadow: 0 0 5px 1px #ccc;::v-deep .el-image__inner {transition: all 0.3s;cursor: pointer;&:hover {transform: scale(1.2);}}::v-deep .image-slot {display: flex;justify-content: center;align-items: center;width: 100%;height: 100%;color: #909399;font-size: 30px;}
}
</style>

父组件

 <ImagePreview:src="form.picUrl":width="150":height="150"></ImagePreview>

14.es6语法

map,filter

15.js逻辑关于党务工作清单的 

第一步:要先判断是编辑还是新增。第二步:要确定传给后端的格式。第三步:展示数据的格式。第四步:删除的排序要判断是有id的还是直接删除。第五步:当导入进来的时候,相当于新增,要进行,说明新增的时候要进行判断,如果是数据还是对象。第六步:对于这种提交数据和展示数据不一样数据格式时候要注意操作。

第一步:

  getContentList(value) {// console.log("我收到子组件传递的值", value);let newData = [];let newAddData = [];if (value.addType === "edit") {// console.log("this.originalData", this.originalData);newData = this.originalData.map((item) => {if (item.No === value.No) {return value;}return item;});} else {if (Array.isArray(value)) {newData = [...this.originalData, ...value];} else {// 若 res.data 不是数组,将其包装成数组再进行合并newData = [...this.originalData, value];}}// console.log("value111", value);// console.log("更新后的newData:", newData);const sortData = this.groupAndMergeData(newData);// 赋值给真正的数组this.originalData = sortData;// console.log("sortData时间字段", sortData);// 赋值给展示数据this.showData = this.handleData(sortData);},

数据分类

   // 分类排序groupAndMergeData(arr) {// console.log("a2222", arr);let groupedData = {}; // 遍历newAddData,按workContent字段分类arr.forEach((item) => {//         const obj = {//             a: 1,//             b: 2,//             c: []//           }//           obj['c']就是数组,拿到的是obj.c的值,可以用pushif (!groupedData[item.workContent]) {// [item.workContent]表示键名groupedData[item.workContent] = [item];} else {groupedData[item.workContent].push(item);// groupedData[item.workContent].sort((a, b) => a.sort - b.sort);groupedData[item.workContent].sort((a, b) => {// 先按照sort字段降序排序if (a.sort !== b.sort) {return a.sort - b.sort;} // 如果sort相同,则按照time字段升序排序(转换为毫秒)else {return b.markTime - a.markTime;}});}});// console.log("arr11111", arr);// console.log("groupedData", groupedData);// 合并所有子数组let mergedData = [];for (let category in groupedData) {mergedData = [...mergedData, ...groupedData[category]];}// console.log("mergedData", mergedData);// 全部数据保存到这个真正的数据里const sortData = [...mergedData].map((item, index) => {return {...item,No: index + 1, //一开始就遍历加上序号};});return sortData;},

 重点是对象键名 变数组

  //         const obj = {//             a: 1,//             b: 2,//             c: []//           }//           obj['c']就是数组,拿到的是obj.c的值,可以用push

 展示数据处理

 // 处理数据handleData(sourceData) {// 分类let classifyWorkContentList = []; //类别数组[...sourceData].forEach((item) => {// .includes()方法返回一个布尔值(true或false)if (classifyWorkContentList.indexOf(item.workContent) === -1) {classifyWorkContentList.push(item.workContent);}});console.log("classifyWorkContentList", classifyWorkContentList);// 按照表格样式修改数据结构// 例如[{workContent: 'xxx', workNormList: [{workItemId: 1111,workId: 11111 ,workContent:'xxx',sort: 1,workNorm:'xxx',No: 1,isDone: 0}]const handleData = classifyWorkContentList.map((item) => {return {workContent: item,workNormList: sourceData.filter((item2) => item2.workContent === item),};});return handleData;},

删除数据 

    deleteFuc(No, data) {const filterData = this.originalData.filter((item) => {return item.No !== No;});const sortData = filterData.map((item, index) => {return {...item,No: index + 1, //一开始就遍历加上序号};});this.originalData = sortData;// 赋值给展示数据this.showData = this.handleData(sortData);},// 删除del(No, data) {// console.log("No", No, "DATA", data);if (data.workItemId) {delDetailList(data.workItemId).then((res) => {if (res.code == 200) {this.$message({message: "删除成功",type: "success",});this.deleteFuc(No, data);}});} else {this.deleteFuc(No, data);}},

 导入文件

 // 导入文件handleUploadSuccess(res, file) {// console.log("res", res, "file", file);if (res.code == 200) {const tableData = [];let mArr = JSON.parse(JSON.stringify(tableData));// 页面操作  concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。mArr = mArr.concat(res.data.workItemVos);mArr = mArr.map((item, index) => {return {...item,sort: item.sort + 1, //一开始就遍历加上序号markTime: new Date().getTime(),};});// console.log("mArr", mArr);this.getContentList(mArr);// this.workList = [];this.workList = this.workList.concat(res.data.workLabelVos);console.log("this.workList", this.workList);}},

16.树形下拉框

子组件 

<template><div><a-tree-selectv-model="orgId"style="width: 100%"size="large":dropdown-style="{ maxHeight: '400px', overflow: 'auto', zIndex: 3000 }"placeholder="请选择"allow-cleartree-default-expand-all:disabled="disabled":tree-data="vorganTreeData":replaceFields="replaceFields"@change="onChange"></a-tree-select></div>
</template><script>
//注意!!!!!
//在modal弹窗组件中使用该组件需要在关闭弹窗方法里清空数据否则会报错
import { userdepList } from "@/api/user/user";
export default {name: "vorganTree",props: {value: {// 如果希望value可以接收int类型的值而不报错,可以将type类型修改为可以兼容字符串和整数的类型type: [String, Number],default: "",},disabled: {type: Boolean,default: false,},replaceFields: {type: Object,default: () => {return {children: "children",title: "label",key: "id",value: "id",};},},},data() {return {orgId: this.value,vorganTreeData: [],deptId: "",};},watch: {value: {handler(newVal) {this.orgId = newVal;},immediate: true,},},mounted() {// this.$bus.$on("id", (data) => {//   console.log("我是任务组件,收到了数据", data);//   this.deptId = data;// });this.deptId = this.$bus.id;this.userdepList();},methods: {userdepList() {userdepList({ ancestors: this.deptId }).then((res) => {console.log("res.data", res);this.vorganTreeData = res.data;});},selectClear() {this.orgId = undefined;},onChange(value, item, xx) {console.log(11111, value, item, xx);// this.$emit("update:value", value);this.$emit("getdep", value);},},
};
</script><style scoped lang="less">
</style>

父组件 

      <orginTree v-model="form.deptId" @getdep="getdep"></orginTree>

17.时间的回显

this.$set(this.form, "date", [dayjs(data.startTime).format("YYYY-MM-DD"),dayjs(data.endTime).format("YYYY-MM-DD"),]);

18.富文本去除标签 富文本组件事Editor

    <Editor v-model="form.requirement" :height="100"></Editor>// 提交数据时去除<p>标签const processedRequirement = that.form.requirement?.replace(/<\/?p>/g,"");

19.props接收兼容性写法

 props: {value: {// 如果希望value可以接收int类型的值而不报错,可以将type类型修改为可以兼容字符串和整数的类型type: [String, Number],default: "",},disabled: {type: Boolean,default: false,},replaceFields: {type: Object,default: () => {return {children: "children",title: "label",key: "id",value: "id",};},},},

20.文本的总体代码

<template><div class="upload-file"><el-uploadv-if="isUpload"multiple:action="uploadFileUrl":before-upload="handleBeforeUpload":file-list="fileList":limit="limit":on-error="handleUploadError":on-exceed="handleExceed":on-success="handleUploadSuccess":show-file-list="false":headers="headers"class="upload-file-uploader"ref="fileUpload"><!-- 上传按钮 --><el-button size="mini" type="primary">选取文件</el-button><!-- 上传提示 --><div class="el-upload__tip" slot="tip" v-if="showTip">请上传<template v-if="fileSize">大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template><template v-if="fileType">格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>的文件</div></el-upload><!-- 文件列表 --><transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul" v-if="isFileList"><li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" style="padding: 0 4px" v-for="(file, index) in fileList"><el-link :href="`${file.url}`" :underline="false" target="_blank"><span class="el-icon-document"> {{ getFileName(file.name) }} </span></el-link><div class="ele-upload-list__item-content-action" v-if="isUpload"><el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link></div></li></transition-group></div>
</template><script>
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";export default {name: "FileUpload",props: {// 值value: [String, Object, Array],// 数量限制limit: {type: Number,default: 5,},// 大小限制(MB)fileSize: {type: Number,default: 5,},// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array | Boolean,default: () => ["doc", "xls", "ppt", "txt", "pdf"],},// 是否显示提示isShowTip: {type: Boolean,default: true,},// 是否显示文件列表isFileList: {type: Boolean,default: true,},dataIndex: {type: Number | String,default: 0,},// 是否可以上传isUpload: {type: Boolean,default: true,},},data() {return {number: 0,uploadList: [],baseUrl: process.env.VUE_APP_BASE_API,uploadFileUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传文件服务器地址headers: {Authorization: "Bearer " + getToken(),},fileList: [],};},watch: {value: {async handler(val) {if (val) {let temp = 1;// 首先将值转为数组let list;if (Array.isArray(val)) {list = val;} else {console.log(val);await listByIds(val).then((res) => {list = res.data.map((oss) => {oss = {name: oss.originalName,url: oss.url,ossId: oss.ossId,};return oss;});this.$emit("getfile", list, this.dataIndex);});}// 然后将数组转为对象数组this.fileList = list.map((item) => {item = { name: item.name, url: item.url, ossId: item.ossId };item.uid = item.uid || new Date().getTime() + temp++;return item;});} else {this.fileList = [];return [];}},deep: true,immediate: true,},},computed: {// 是否显示提示showTip() {return this.isShowTip && (this.fileType || this.fileSize);},},methods: {// 上传前校检格式和大小handleBeforeUpload(file) {// 校检文件类型if (this.fileType) {const fileName = file.name.split(".");const fileExt = fileName[fileName.length - 1];const isTypeOk = this.fileType.indexOf(fileExt) >= 0;if (!isTypeOk) {this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);return false;}}// 校检文件大小if (this.fileSize) {const isLt = file.size / 1024 / 1024 < this.fileSize;if (!isLt) {this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);return false;}}this.$modal.loading("正在上传文件,请稍候...");this.number++;return true;},// 文件个数超出handleExceed() {this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);},// 上传失败handleUploadError(err) {this.$modal.msgError("上传文件失败,请重试");this.$modal.closeLoading();},// 上传成功回调handleUploadSuccess(res, file) {if (res.code === 200) {this.uploadList.push({name: res.data.fileName,url: res.data.url,ossId: res.data.ossId,});this.uploadedSuccessfully();} else {this.number--;this.$modal.closeLoading();this.$modal.msgError(res.msg);this.$refs.fileUpload.handleRemove(file);this.uploadedSuccessfully();}},// 删除文件handleDelete(index) {let ossId = this.fileList[index].ossId;// delOss(ossId);this.fileList.splice(index, 1);this.$emit("input", this.listToString(this.fileList));},// 上传结束处理uploadedSuccessfully() {if (this.number > 0 && this.uploadList.length === this.number) {this.fileList = this.fileList.concat(this.uploadList);this.uploadList = [];this.number = 0;this.$emit("input", this.listToString(this.fileList));this.$modal.closeLoading();}},// 获取文件名称getFileName(name) {// 如果是url那么取最后的名字 如果不是直接返回if (name.lastIndexOf("/") > -1) {return name.slice(name.lastIndexOf("/") + 1);} else {return name;}},// 对象转成指定字符串分隔listToString(list, separator) {let strs = "";separator = separator || ",";for (let i in list) {strs += list[i].ossId + separator;}return strs != "" ? strs.substr(0, strs.length - 1) : "";},},
};
</script><style scoped lang="scss">
.upload-file-uploader {margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {border: 1px solid #e4e7ed;line-height: 2;margin-bottom: 10px;position: relative;
}
.upload-file-list .ele-upload-list__item-content {display: flex;justify-content: space-between;align-items: center;color: inherit;
}
.ele-upload-list__item-content-action .el-link {margin-right: 10px;
}
</style>

父组件

 <el-table-column label="操作"  prop="action" width="100"><template slot-scope="scope"><!-- <el-upload class="upload-demo" action="https://jsonplaceholder.typicode.com/posts/" :on-change="handleChange" :show-file-list="false"><el-button size="small" type="primary">点击上传</el-button></el-upload> --><FileUploadv-model="tableData[scope.$index].materialIds":dataIndex="scope.$index":isShowTip="false":fileType="false":isFileList="false":isUpload="scope.row.status == 3 || scope.row.status == 0 || scope.row.status == null"@getfile="getfile"></FileUpload></template></el-table-column>

相关文章:

能源党建后台项目总结

1.引入 本次框架是Ruoyi-plusvue2element组合。 2.样式 由于是后台项目&#xff0c;样式要求统一&#xff0c;不可以有的输入框长有的短。着重几点&#xff1a; 1.关于form表单应该如何水平布局 在element中&#xff0c;form有个属性叫&#xff1a;:inline"true"…...

股票高胜率的交易法则是什么?

股票交易中的高胜率交易法则并非一成不变&#xff0c;而是根据市场状况、个人投资风格和经验等多种因素综合而定的。以下是一些有助于提升交易胜率的法则和策略&#xff1a; 1.趋势跟踪法则&#xff1a;在股票交易中&#xff0c;趋势跟踪是一种有效的策略。通过观察大盘和个股…...

C语言 | sizeof与strlen的区别(附笔试题)

目录&#xff1a; 1. sizeof和strlen的对比 2. 数组和指针 笔试题解析 3. 指针运算 笔试题解析 内容多多&#xff0c;需耐心看完&#xff0c;加油&#xff01;&#xff01;&#xff01; 一.sizeof和strlen的对比 1.1 sizeof 在学习操作符的时候&#xff0c;我们学习了 s…...

AI自动绘画器介绍和应用场景

AI自动绘画器是一种利用人工智能技术来生成绘画作品的工具。以下是一些常见的AI自动绘画器&#xff1a; DeepDream&#xff1a; 风格&#xff1a;可以生成三种风格的图片&#xff0c;包括深度梦幻风格、深度风格和浅层风格。应用场景&#xff1a;起初设计用于帮助研究人员理解…...

java二叉树前中后序遍历

代码随想录解题思路&#x1f192;力扣前序题目&#x1f192;力扣中序题目&#x1f192;力扣后序题目 递归遍历 // 前序遍历 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> res new ArrayList<>();preorder(root…...

【LeetCode刷题笔记】LeetCode 1365.有多少小于当前数字的数字

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…...

室内定位中文综述阅读

1 室内高精度定位技术总结与展望 [4]柳景斌,赵智博,胡宁松等.室内高精度定位技术总结与展望[J].武汉大学学报(信息科学 版),2022,47(07):997-1008.DOI:10.13203/j.whugis20220029. 1.1.1 WiFi‐RTT定位 2016 年 12 月&#xff0c;随着新版 IEEE802.11 标准的公布&#xff0c…...

微信小程序uniapp+vue电力巡线任务故障报修管理系统2q91t

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 前端开发:vue 语言&#xff1a;javapythonnodejsphp均支持 运行软件:idea/eclipse/vscode/pycharm/wamp均支持 框架支持:Ssm/django/flask/t…...

springboot国际化多语言

1,新建国际化多语言文件 在resources目录下新建 messages.properties 其他语言的文件 编辑messages.properties文件,下方从text切换到Resource Bundle ,即可对照着编辑多语言文件 (如果没有找到Resource Bundle,先在settings->plugins中安装Resource Bundle Editor) 2,配…...

set和map

这里是目录标题 setinsertfinderasecountlower_boundupper_boundmultisetset的应用 mappairinsertinsert的pair map的遍历map对[ ]的重载(重点)multimap set set的普通迭代器和const迭代器都不支持修改。(这点可以根据源代码看出来&#xff0c;都是对const iterator进行了type…...

Open CASCADE学习|求曲面的参数空间

在三维空间中&#xff0c;任意的曲面都可以通过特定的方法映射到一个二维参数平面上&#xff0c;从而对其进行详细的几何分析和处理。首先&#xff0c;我们需要从三维模型中提取出特定的曲面&#xff0c;这通常被称为“Face”。一个face可以被视为三维空间中的一个封闭区域&…...

代码随想录阅读笔记-二叉树【总结】

二叉树的理论基础 代码随想录 (programmercarl.com)&#xff1a;二叉树的种类、存储方式、遍历方式、定义方式 二叉树的遍历方式 深度优先遍历 代码随想录阅读笔记-二叉树【递归遍历】-CSDN博客&#xff1a;递归三部曲初次亮相代码随想录阅读笔记-二叉树【迭代遍历】-CSDN博…...

【SpringBoot整合系列】SpringBoot整合FastDFS(二)

目录 SpringBoot整合FastDFSJava客户端/依赖常用api接口解释1.uploadFile参数返回值 2.uploadSlaveFile参数返回值 3.getMetadata参数返回值 4.overwriteMetadata参数&#xff1a;返回值&#xff1a;无 5.mergeMetadata参数&#xff1a;返回值&#xff1a;无 6.queryFileInfo参…...

L2-2 巴音布鲁克永远的土(二分+并查集)

思路&#xff1a;我们可以二分答案&#xff0c;然后判断当前答案合不合理。 对于判断答案合理&#xff0c;可以用并查集&#xff0c;看mid能否把所有检查点连进一个集合中&#xff0c;枚举每个结点&#xff0c;如何当前结点周围的四个方向可以连的话&#xff0c;就加进同一个集…...

Spring Cloud学习笔记:Eureka简介,Eureka简单样例

这是本人学习的总结&#xff0c;主要学习资料如下 - 马士兵教育 [TOC](目录)1、Eureka 1.1、架构 Eureka是SpringCloud Nexflix的核心子模块&#xff0c;其中包含Server和Client。 Server提供服务注册&#xff0c;存储所有可用服务节点。 Client用于简化和Server的通讯复杂…...

【漏洞复现】WordPress Welcart 任意文件读取漏洞(CVE-2022-4140)

0x01 产品简介 Welcart 是一款免费的 WordPress 电子商务插件。Welcart 具有许多用于制作在线商店的功能和自定义设置。您可以轻松创建自己的原始在线商店。 0x02 漏洞概述 Welcart存在任意文件读取漏洞&#xff0c;未授权的攻击者可以通过该漏洞读取任意文件&#xff0c;获…...

快速排序:深入解析其原理、实现与性能特性

快速排序&#xff0c;以其名字所示&#xff0c;是一种追求速度的高效排序算法。作为分治法在排序问题上的典型应用&#xff0c;快速排序凭借其平均情况下近乎理想的O(n log n)时间复杂度和简洁的实现逻辑&#xff0c;在实际编程与数据处理中占据着重要地位。本篇博客将详细解析…...

一文看懂Mac地址

一、Mac地址是什么&#xff1f; 虽然IP地址已经成为一个家喻户晓的术语&#xff0c;但还有一个同样重要的数字标识符值得我们关注——MAC地址。在本文中&#xff0c;我们旨在阐明网络中这个经常被忽视的方面。加入我们&#xff0c;深入研究 MAC 地址的世界&#xff0c;了解它们…...

2024.4.10作业

#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } //显示时间 void Widget::timerEvent(QTimerEvent *e) { QT…...

python - Django创建项目

项目运行命令 根目录下运行命令:   python manage.py runserver win环境创建项目 直接使用 Pycharm 创建项目 在 cmd 或 Linux 命令行环境下创建 Django 项目 django-admin startproject mysite 这样就会在当前目录下创建一个叫做 mysite 的Django项目。   可以看到Djang…...

WPF —— 动画缩放变换

ScaleTransform:在二维x-y坐标系统内缩放对象; 在故事板中依赖的属性为RenderTransform.ScaleX或RenderTransform.ScaleY,这要根据你要沿哪个轴进行缩放,X代表x轴,Y代表y轴; key属性当我们使用静态资源访问时候--> <!--TargetType"{x:Type Button} 直接应用…...

SQL注入---盲注

文章目录 目录 一.盲注概述 布尔盲注&#xff1a; 时间盲注&#xff1a; 一.盲注概述 注是一种SQL注入攻击的形式&#xff0c;在这种攻击中&#xff0c;攻击者向目标应用程序发送恶意注入代码&#xff0c;然后通过观察应用程序的响应来推断出数据库中的信息。与常规的SQL注入…...

PlanUML和Mermaid哪个好?

引言 在当今信息化快速发展的时代&#xff0c;数据可视化和图表工具不仅对于程序员&#xff0c;也对于非技术背景的人士至关重要。绘图工具可以帮助我们更好地理解和表达复杂的概念或数据流。PlantUML和Mermaid是两款被广泛使用的绘图语言&#xff0c;它们都能够通过简洁的文本…...

leetcode 343. 整数拆分

题目 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36 解释: 1…...

【MATLAB源码-第180期】基于matlab的PTS,SLM,CPFilter三种降低OFDM系统的PAPR仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 限幅和滤波&#xff08;Clipping and Filtering&#xff09; 原理简介 限幅和滤波是一种基础且直观的方法&#xff0c;用于降低OFDM信号的PAPR。在限幅阶段&#xff0c;信号的幅度在达到设定阈值时会被削减&#xff0c;…...

学透Spring Boot — 004. Spring Boot Starter机制和自动配置机制

如果你项目中一直用的是 Spring Boot&#xff0c;那么恭喜你没有经历过用 Spring 手动集成其它框架的痛苦。 都说 Spring Boot 大大简化了 Spring 框架开发 Web 应用的难度&#xff0c;这里我们通过配置 Hibernate 的两种方式来深刻体会这一点&#xff1a; 使用 Spring 框架集…...

面试算法-170-二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 解 class Solution {public int maxDepth(TreeNod…...

【数据结构】哈希

文章目录 1. 哈希概念2. 哈希冲突3. 哈希函数4. 哈希冲突解决4.1 闭散列4.2 开散列 unordered 系列的关联式容器之所以效率比较高&#xff0c;是因为其底层使用了哈希结构。 1. 哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff…...

Kubernetes(k8s)监控与报警(qq邮箱+钉钉):Prometheus + Grafana + Alertmanager(超详细)

Kubernetes&#xff08;k8s&#xff09;监控与报警&#xff08;qq邮箱钉钉&#xff09;&#xff1a;Prometheus Grafana Alertmanager&#xff08;超详细&#xff09; 1、部署环境2、基本概念简介2.1、Prometheus简介2.2、Grafana简介2.3、Alertmanager简介2.4、Prometheus …...

STM32-04基于HAL库(CubeMX+MDK+Proteus)中断案例(按键中断扫描)

文章目录 一、功能需求分析二、Proteus绘制电路原理图三、STMCubeMX 配置引脚及模式&#xff0c;生成代码四、MDK打开生成项目&#xff0c;编写HAL库的按键检测代码五、运行仿真程序&#xff0c;调试代码 一、功能需求分析 在完成GPIO输入输出案例之后&#xff0c;开始新的功能…...