1.图片上传组件
使用
<el-descriptions-item label="附件图片" :span="3">
<ImageUpload v-model="picUrl" :fileSize="0" @getImg="getImg"></ImageUpload>
</el-descriptions-item>
// 图片
getImg(val){
console.log(this.imgList,val)
this.imgList = val
},
imageUpload组件封装
<template>
<div class="component-upload-image">
<el-upload
multiple
:action="uploadImgUrl"
list-type="picture-card"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
ref="imageUpload"
:on-remove="handleDelete"
:show-file-list="true"
:headers="headers"
:file-list="fileList"
:on-preview="handlePictureCardPreview"
:class="{hide: this.fileList.length >= this.limit}"
>
<i class="el-icon-plus"></i>
</el-upload>
<!-- 上传提示 -->
<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-dialog
:visible.sync="dialogVisible"
title="预览"
width="800"
append-to-body
>
<img
:src="dialogImageUrl"
style="display: block; max-width: 100%; margin: 0 auto"
/>
</el-dialog>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
export default {
props: {
value: [String, Object, Array],
// 图片数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
},
data() {
return {
number: 0,
uploadList: [],
dialogImageUrl: "",
dialogVisible: false,
hideUpload: false,
baseUrl: process.env.VUE_APP_BASE_API,
uploadImgUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传的图片服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
fileList: []
};
},
watch: {
value: {
async handler(val) {
if (val) {
// 首先将值转为数组
let list;
if (Array.isArray(val)) {
list = val;
} else {
await listByIds(val).then(res => {
list = res.data;
this.$emit("getImg", list);
})
}
// 然后将数组转为对象数组
this.fileList = list.map(item => {
// 此处name使用ossId 防止删除出现重名
item = { name: item.ossId, url: item.url, ossId: item.ossId };
return item;
});
} else {
this.fileList = [];
return [];
}
},
deep: true,
immediate: true
}
},
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
methods: {
// 上传前loading加载
handleBeforeUpload(file) {
let isImg = false;
if (this.fileType.length) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = this.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
} else {
isImg = file.type.indexOf("image") > -1;
}
if (!isImg) {
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++;
},
// 文件个数超出
handleExceed() {
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
},
// 上传成功回调
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.imageUpload.handleRemove(file);
this.uploadedSuccessfully();
}
},
// 删除图片
handleDelete(file) {
const findex = this.fileList.map(f => f.name).indexOf(file.name);
if(findex > -1) {
let ossId = this.fileList[findex].ossId;
// delOss(ossId);
this.fileList.splice(findex, 1);
this.$emit("input", this.listToString(this.fileList));
}
},
// 上传失败
handleUploadError(res) {
this.$modal.msgError("上传图片失败,请重试");
this.$modal.closeLoading();
},
// 上传结束处理
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();
}
},
// 预览
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
// 对象转成指定字符串分隔
listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
if (list[i].ossId) {
strs += list[i].ossId + separator;
}
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
}
};
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
::v-deep.hide .el-upload--picture-card {
display: none;
}
// 去掉动画效果
::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active {
transition: all 0s;
}
::v-deep .el-list-enter, .el-list-leave-active {
opacity: 0;
transform: translateY(0);
}
</style>
2.图片回显组件
使用
<ImagePreview
:src="form.picUrl"
:width="150"
:height="150"
></ImagePreview>
imagePreview组件封装
<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>
3.文件上传组件
使用
<el-descriptions-item label="附件文件" :span="3">
<FileUpload v-model="fileIds" :fileSize="0" @getfile="getfile"></FileUpload>
</el-descriptions-item>
// 文件列表
getfile(val) {
this.fileList = val;
},
fileUpload组件的封装
<template>
<div class="upload-file">
<el-upload
v-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"],
default: () => ["doc", "docx", "xls", "xlsx", "ppt", ".pptx", "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>
4.树形图组件
使用
<orginTree
v-model="queryParams.deptId"
@change="changexx"
></orginTree>
changexx(value) {
console.log(value.label);
// this.$set(this.queryParams, "deptId", value);
// console.log("this.queryParams", this.queryParams);
},
树形组件封装
<template>
<div>
<a-tree-select v-model="orgId" style="width: 100%" size="large" :dropdown-style="{ maxHeight: '400px', overflow: 'auto',zIndex:3000 }"
placeholder="请选择" allow-clear tree-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: {
type: [String, Number],
default: undefined,
},
disabled: {
type: Boolean,
default: false,
},
deptId: {
type: [String, Number],
default: '',
},
replaceFields: {
type: Object,
default: () => {
return {
children: 'children',
title: 'label',
key: 'id',
value: 'id',
}
},
},
},
data () {
return {
orgId: this.value,
vorganTreeData: [],
}
},
watch: {
value: {
handler (newVal) {
console.log(this.orgId)
this.orgId = newVal
},
immediate: true,
},
deptId:{
handler (newVal) {
this.userdepList()
},
immediate: true,
}
},
mounted () {
this.userdepList()
},
methods: {
userdepList () {
let mData = { ancestors: this.deptId }
console.log(mData)
userdepList(mData).then(res => {
this.vorganTreeData = res.data
console.log(this.vorganTreeData)
})
},
selectClear () {
this.orgId = undefined
},
onChange (value,label,node) {
this.$emit('input', value)
this.$emit('update:value', value)
this.$emit('change',value,label,node.triggerNode)
},
},
}
</script>
<style scoped lang="less">
</style>
5.多选表格组件
使用
<selectInput v-model="form.userIds" :selectRow="rowData"></selectInput>
<template>
<div>
<el-select
v-model="selectValue"
style="width: 100%"
readonly
ref="modelRef"
clearable
multiple
filterable
@focus="modelClick()"
@click.native="modelClick()"
@clear="selectClear"
@remove-tag="selectRemoveClear"
allow-create
placeholder="请选择"
>
<el-option
v-for="item in selectRow"
:key="item[userId]"
:label="item.nickName"
:value="item[userId]"
>
</el-option>
</el-select>
<el-dialog
:title="title"
width="1000px"
:visible.sync="dialogFormVisible"
append-to-body
>
<el-row :gutter="24">
<el-col :span="16">
<el-form ref="form" :model="queryParam" label-width="50px">
<el-row>
<el-col :span="8">
<el-form-item label="昵称">
<el-input v-model="queryParam.nickName"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="账号">
<el-input v-model="queryParam.userName"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-button
type="primary"
icon="el-icon-search"
@click="searchQuery"
style="margin-left: 10px"
>搜索</el-button
>
<el-button icon="el-icon-refresh-right" @click="searchReset"
>重置</el-button
>
</el-col>
</el-row>
</el-form>
<el-table
:data="tableData"
v-loading="loading"
border
@selection-change="handleSelectionChange"
@select="handleSelectionChange"
@row-click="handleRowSelectionChange"
ref="multipleTable"
:row-key="userId"
:reserve-selection="true"
>
<el-table-column
type="selection"
width="40"
:reserve-selection="true"
>
</el-table-column>
<el-table-column
:property="item.property"
:label="item.label"
v-for="(item, index) in column"
:key="index"
></el-table-column>
</el-table>
<div style="float: right; margin-top: 10px">
<el-pagination
background
layout="prev, pager, next"
:total="total"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-size="5"
>
</el-pagination>
</div>
</el-col>
<el-col :span="7" style="margin: 14px">
<span style="font-size: 16px" class="select"
>已选 {{ selectRow.length }}</span
>
<el-table :data="tableData1" border style="margin-top: 20px">
<el-table-column
size="mini"
:property="item.property"
:label="item.label"
v-for="(item, index) in column1"
:key="index"
></el-table-column>
<el-table-column prop="action" label="操作" width="50">
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="deleteRecord(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<div style="float: right; margin-top: 10px">
<el-pagination
background
layout="prev, pager, next"
:total="total1"
@current-change="handleCurrentChange1"
:current-page.sync="currentPage1"
:page-size="5"
>
</el-pagination>
</div>
</el-col>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import request from "@/utils/request";
export default {
props: {
title: {
type: String,
default: "",
},
value: {
type: String,
default: "",
},
// deptId: {
// type: String,
// default: "",
// },
},
data() {
return {
dialogFormVisible: false,
searchText: "",
queryParam: {},
column: [
{
property: "nickName",
label: "昵称",
},
{
property: "userName",
label: "账号",
},
{
property: "orgName",
label: "组织",
},
],
column1: [
{
property: "nickName",
label: "昵称",
},
{
property: "userName",
label: "账号",
},
],
options: [],
loading: false,
tableData: [],
tableData1: [],
currentPage: 1,
currentPage1: 1,
total: 0,
total1: 0,
url: "system/user/list", // 一直url
selectRowKey: [],
selectRow: [],
selectValue: [],
userId: "userId", // 唯一键值
deptId: "",
};
},
watch: {
value: {
immediate: true,
handler(val) {
if (val) {
console.log("11111", val);
this.selectValue = val.split(",");
this.ifValue();
} else {
this.selectValue = [];
this.selectRow = [];
}
},
},
// deptId: {
// immediate: true,
// handler(val) {
// console.log("val", val);
// this.selectValue = [];
// this.selectRow = [];
// // if (val) {
// // this.selectValue = val.split(",");
// // this.ifValue();
// // } else {
// // this.selectValue = [];
// // this.selectRow = [];
// // }
// },
// },
selectValue: {
deep: true,
handler(val) {
console.log("selectValue", val);
let data = val.join(",");
this.$emit("input", data);
// this.$emit("getuserList", this.tableData1);
},
},
selectRow: {
deep: true,
handler(val) {
this.pageData();
},
},
// tableData1: {
// deep: true,
// handler(val) {
// this.$bus.$emit("tableData1", this.tableData1);
// // this.$emit("getuserList", this.tableData1);
// },
// },
},
created() {},
mounted() {
this.$bus.$on("deptId", (data) => {
console.log("我是selectInput组件,收到了数据", data);
this.deptId = data;
});
},
methods: {
// handleInput(value) {
// this.queryParam.userName = value;
// this.queryParam.nickName = value;
// },
selectRemoveClear(val) {
let selectIndex = -1;
this.selectRow.forEach((item, index) => {
if (item[this.userId] == val) {
selectIndex = index;
}
});
this.currentPage1 = 1;
this.selectRow.splice(selectIndex, 1);
this.$refs.multipleTable.selection.splice(selectIndex, 1);
},
// 清空
selectClear() {
this.currentPage1 = 1;
this.selectRow = [];
this.selectValue = [];
this.$refs.multipleTable.clearSelection();
},
deleteSelect(val) {
let selectIndex = 0;
this.selectValue.forEach((item, index) => {
if (item == val[this.userId]) {
selectIndex = index;
}
});
this.selectValue.splice(selectIndex, 1);
this.selectRow.splice(selectIndex, 1);
this.$refs.multipleTable.selection.splice(selectIndex, 1);
},
// 用于将选择框中的选项添加到已选中的选项中。
//在用户选择选项时调用。
//将选择框中新选中的选项添加到 selectRow 和 selectValue 中,并更新页面数据。
addSelection() {
let mRow = JSON.parse(JSON.stringify(this.selectRow));
this.$refs.multipleTable.selection.forEach((item, index) => {
if (
!mRow.some((items) => {
return items[this.userId] == item[this.userId];
})
) {
this.selectRow.push(item);
this.selectValue.push(item[this.userId]);
}
});
},
// 用于从已选中的选项中删除选项。
// 在用户取消选中选项时调用。
// 从 selectRow 和 selectValue 中删除取消选中的选项,并更新页面数据。
deleteSelection() {
let selection = JSON.parse(
JSON.stringify(this.$refs.multipleTable.selection)
);
this.selectRow = selection;
this.selectValue = selection.map((item) => item[this.userId]);
},
// 用于检查已选中的选项是否与选择框中的选项一致。
// 在组件初始化和 value 数据变化时调用。
// 如果已选中的选项与选择框中的选项不一致,则调用 getUser 方法。
ifValue() {
if (this.selectRow.length != this.selectValue.length) {
this.getUser();
} else if (this.selectRow.length != 0) {
this.selectRow.forEach((item) => {
if (
!this.selectValue.some((items) => {
return item[this.userId] == items;
})
) {
this.getUser();
}
});
}
},
// 用于根据已选中的选项获取用户信息。
// 在 ifValue 方法中调用。
// 发送网络请求获取已选中的选项对应的用户信息,并更新 selectRow 中的数据。
getUser() {
// this.getPage("`system/user/list?id=${this.deptId}`").then((res) => {
this.getPage("system/user/list/ids", { ids: this.value }).then((res) => {
console.log("this.deptId22222", this.deptId);
console.log("有id时候res", res);
if (res.code == 200) {
let records = res.data.map((item) => {
let mItem = {
email: item.email,
nickName: item.nickName,
orgName: item.dept ? item.dept.deptName : "",
phonenumber: item.phonenumber,
userName: item.userName,
};
mItem[this.userId] = item[this.userId].toString();
return mItem;
});
this.selectRow = records;
}
});
},
// 用于删除指定的记录。
// 当用户点击已选中的选项的删除按钮时调用。
// 调用 deleteSelect 方法删除指定的选项。
deleteRecord(record) {
this.deleteSelect(record);
},
toggleSelection(rows) {
if (rows) {
rows.forEach((row) => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
ifSelectValue(val) {
let selectBoole = false;
this.selectValue.forEach((item, index) => {
if (item == val[this.userId]) {
selectBoole = true;
}
});
if (selectBoole) {
this.deleteSelect(val);
return false;
} else {
this.selectValue.push(val[this.userId]);
this.selectRow.push(val);
return true;
}
},
handleRowSelectionChange(val, row) {
if (this.ifSelectValue(val)) {
this.$refs.multipleTable.selection.push(val);
} else {
}
},
handleSelectionChange(val, row) {
this.multipleSelection = val;
this.addSelection();
if (val.length < this.selectRow.length) {
this.deleteSelection();
}
},
handleCurrentChange(val) {
this.currentPage = val;
this.getList();
},
handleCurrentChange1(val) {
this.currentPage1 = val;
this.pageData();
},
searchReset() {
this.queryParam = {};
this.currentPage = 1;
this.getList();
},
searchQuery() {
this.currentPage = 1;
this.getList();
},
getList() {
this.loading = true;
// let mData = {
// pageNum: this.currentPage,
// pageSize: 5,
// };
// console.log("this.queryParam", this.queryParam);
// let deptId = this.deptId;
this.getPage(this.url, {
deptId: this.deptId,
pageNum: this.currentPage,
pageSize: 5,
...this.queryParam,
})
// this.getPage(this.url, Object.assign(deptId, mData, this.queryParam))
.then((res) => {
this.loading = false;
if (res.code == 200) {
// console.log('this.deptId',this.deptId);
console.log(11111111, res);
this.tableData = res.rows.map((item) => {
let mItem = {
email: item.email,
nickName: item.nickName,
orgName: item.dept ? item.dept.deptName : "",
phonenumber: item.phonenumber,
userName: item.userName,
};
mItem[this.userId] = item[this.userId].toString();
return mItem;
});
this.total = res.total;
}
})
.catch((err) => {
this.loading = false;
});
},
pageData() {
let mm = JSON.parse(JSON.stringify(this.selectRow));
this.total1 = mm.length;
this.tableData1 = mm.slice(
(this.currentPage1 - 1) * 5,
this.currentPage1 * 5
);
if (this.currentPage1 > 1 && this.tableData1.length == 0) {
this.currentPage1 = this.currentPage1 - 1;
this.pageData();
}
console.log("tableData1", this.tableData1);
},
getPage(url, query) {
return request({
url: url,
method: "get",
params: query,
});
},
ifselection() {
let mmblo = false;
if (this.selectRow.length != this.$refs.multipleTable.selection.length) {
mmblo = true;
return mmblo;
}
this.selectRow.forEach((item) => {
if (
!this.$refs.multipleTable.selection.some((items) => {
return item[this.userId] == items[this.userId];
})
) {
mmblo = true;
}
});
return mmblo;
},
modelClick() {
this.dialogFormVisible = true;
this.queryParam = {};
setTimeout(() => {
this.$refs.modelRef.blur();
if (this.ifselection()) {
let mms = JSON.parse(
JSON.stringify(this.$refs.multipleTable.selection)
);
mms.forEach((item) => {
this.$refs.multipleTable.selection.pop();
});
this.selectRow.forEach((item) => {
this.$refs.multipleTable.selection.push(item);
});
this.currentPage = 1;
this.getList();
}
}, 1);
this.getList();
},
},
};
</script>
<style>
/* .select {
} */
.tableData1 {
padding-top: 10px;
/* background-color: pink; */
}
</style>
6.时间选择器格式
在el中
value-format="yyyy-MM-dd"
<el-date-picker
v-model="queryParams.appraisalYear"
type="year"
placeholder="选择年"
value-format="yyyy-MM-dd"
>
</el-date-picker>
在antd中
valueFormat="YYYY-MM-DD"
<a-form-model-item
label="计划时间:"
prop="times"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-range-picker v-model="model.times" valueFormat="YYYY-MM-DD" />
</a-form-model-item>
7.自定义校验规则
prop="liaisonUserIds"
<el-form-item label="联络员" prop="liaisonUserIds" ref="devType">
<selectInput
v-model="form.liaisonUserIds"
:selectRow="rowData"
></selectInput>
</el-form-item>
rules里面liaisonUserIds
rules: {
userId: [{ required: true, message: "请选则", trigger: "change" }],
liaisonUserIds: [
{
required: true,
validator: this.validatePass,
message: "请选择",
trigger: "change",
},
],
},
// 自定义校验规则
validatePass(rule, value, callback) {
console.log("rule", rule, "value", value);
if (!this.form.liaisonUserIds) {
return callback(new Error("联系人为空")); // 校验失败,传入错误信息
} else {
callback(); // 校验通过,不传入参数或传入 null
}
},
8.vue2数组不更新,强制更新
this.$set(this.form, "deptId", selectedUser.deptId);
9.下载
使用
downExport() {
this.download(
"/epb/dutyPerformItem/export",
{
dutyPerformId: 1,
type: 0,
...this.queryParams,
},
`党支部履责情况列表.xlsx`
);
},
在mian.js中全局注册
import { download } from '@/utils/request'
在request
import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi";
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 对应国际化资源文件后缀
axios.defaults.headers['Content-Language'] = 'zh_CN'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超时
timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
cache.session.setJSON('sessionObj', requestObj)
}
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false;
store.dispatch('LogOut').then(() => {
location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
})
}).catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
Message({ message: msg, type: 'warning' })
return Promise.reject('error')
} else if (code !== 200) {
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data
}
},
error => {
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
Message({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
// 通用下载方法
export function download(url, params, filename, config) {
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config
}).then(async (data) => {
const isBlob = blobValidate(data);
if (isBlob) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r)
Message.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
})
}
export default service
10.导出
使用
和9是一样的
handleExport(data) {
console.log("data导出", data);
this.download(
"/epb/dutyItem/export",
{
dutyAppraisalId: data.dutyAppraisalId,
},
`${data.appraisalYear + "年" + data.deptName + "责任制考核"}.xlsx`
);
},
11.导入
<el-upload
class="upload-demo"
:action="uploadFileUrl"
multiple
:show-file-list="false"
:headers="headers"
:on-success="handleUploadSuccess"
>
<el-button>导入</el-button>
</el-upload>
return {
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(),
},
};
import { getToken } from "@/utils/auth";
// 导入文件
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);
}
},
12.处理分类数据
// 处理数据
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;
},
13.文件回显
两种回显
一种
<span v-for="(item, index) in form.fileList" :key="index">
<a :href="item.fileUrl" target="_blank">{{ item.fileName }}</a
>,
</span>
showDetailModal(data) {
console.log("data", data);
this.title = "详情";
this.dialogVisible = true;
const fileArr =
data?.fileUrl?.split(",")?.map((item, index) => {
return {
fileUrl: item,
fileName: data?.fileName?.split(",")[index],
};
}) || [];
this.form = data;
console.log("fileArr", fileArr);
this.$set(this.form, "fileList", fileArr);
this.getDetail(data.taskId);
},
第二种
<FileUpload
v-model="form.fileId"
:isUpload="false"
:isShowTip="false"
:fileType="false"
></FileUpload>