vue2组件的封装+antd

1.vue2表格的封装使用

表格使用

   <standard-tables:columns="columns":dataSource="dataSource":loading="loading"bordered:pagination="{ ...pagination, onChange: onPageChange }"><div slot="warnType" slot-scope="{ text, record }"><span>{{ text | textList(warnTypeData) }}</span></div><div slot="warnLevel" slot-scope="{ text, record }"><span>{{ text | textList(warnLevelData) }}</span></div><div slot="status" slot-scope="{ text, record }"><span v-if="text == 0">待指派</span><span v-if="text == 1">待处置</span><span v-if="text == 2">已处置</span></div><div slot="action" slot-scope="{ text, record }"><a @click="viewRecord(record)"> 详情 </a><a-divider type="vertical" /><a @click="editRecord(record)" v-if="record.status != 2"> 指派 </a></div></standard-tables>pagination: {current: 1,pageSize: 10,total: 0,showTotal: (total) => `共 ${total} 条数据`, // 展示总共有几条数据},//方法onPageChange(page, pageSize) {this.pagination.current = page;this.pagination.pageSize = pageSize;this.getData();},

表格封装组件的模样

<template><div class="standard-table"><a-table:bordered="bordered":loading="loading":columns="columns":dataSource="dataSource":rowKey="(record, index) => {return index;}":pagination="pagination":expandedRowKeys="expandedRowKeys":expandedRowRender="expandedRowRender"@change="onChange"><templateslot-scope="text, record, index":slot="slot"v-for="slot in Object.keys($scopedSlots).filter((key) => key !== 'expandedRowRender')"><slot :name="slot" v-bind="{ text, record, index }"></slot></template><template :slot="slot" v-for="slot in Object.keys($slots)"><slot :name="slot"></slot></template><templateslot-scope="record, index, indent, expanded":slot="$scopedSlots.expandedRowRender ? 'expandedRowRender' : ''"><slotv-bind="{ record, index, indent, expanded }":name="$scopedSlots.expandedRowRender ? 'expandedRowRender' : ''"></slot></template></a-table></div>
</template><script>
export default {name: "StandardTables",props: {bordered: Boolean,loading: [Boolean, Object],columns: Array,dataSource: Array,rowKey: {type: [String, Function],default: "key",},pagination: {type: [Object, Boolean],default: false,},selectedRows: Array,expandedRowKeys: Array,expandedRowRender: Function,},data() {return {needTotalList: [],};},methods: {equals(record1, record2) {if (record1 === record2) {return true;}//  使用解构赋值从当前组件实例(this)中提取rowKey属性。//  rowKey通常用于标识对象的独特性,类似于数据库中的主键const { rowKey } = this;// 检查rowKey是否存在且其类型为字符串。如果满足条件,说明我们可以通过rowKey属性来判断两个对象是否相等。if (rowKey && typeof rowKey === "string") {return record1[rowKey] === record2[rowKey];}//  如果rowKey存在且是函数,这意味着用户提供了自定义的比较函数。else if (rowKey && typeof rowKey === "function") {//  执行这个自定义函数,将record1和record2分别作为参数传入,然后比较函数返回值是否相等。return rowKey(record1) === rowKey(record2);}return false;},contains(arr, item) {if (!arr || arr.length === 0) {return false;}console.log("this", this);const { equals } = this;for (let i = 0; i < arr.length; i++) {if (equals(arr[i], item)) {return true;}}return false;},onSelectAll(selected, rows) {const { getKey, contains } = this;const unselected = this.dataSource.filter((item) => !contains(rows, item, this.rowKey));const _selectedRows = this.selectedRows.filter((item) => !contains(unselected, item, this.rowKey));const set = {};_selectedRows.forEach((item) => (set[getKey(item)] = item));rows.forEach((item) => (set[getKey(item)] = item));const _rows = Object.values(set);this.$emit("update:selectedRows", _rows);this.$emit("selectedRowChange",_rows.map((item) => getKey(item)),_rows);},getKey(record) {const { rowKey } = this;if (!rowKey || !record) {return undefined;}if (typeof rowKey === "string") {return record[rowKey];} else {return rowKey(record);}},onSelect(record, selected) {const { equals, selectedRows, getKey } = this;const _selectedRows = selected? [...selectedRows, record]: selectedRows.filter((row) => !equals(row, record));this.$emit("update:selectedRows", _selectedRows);this.$emit("selectedRowChange",_selectedRows.map((item) => getKey(item)),_selectedRows);},initTotalList(columns) {return columns.filter((item) => item.needTotal).map((item) => {return {...item,total: 0,};});},onClear() {this.$emit("update:selectedRows", []);this.$emit("selectedRowChange", [], []);this.$emit("clear");},onChange(pagination, filters, sorter, { currentDataSource }) {this.$emit("change", pagination, filters, sorter, { currentDataSource });},},created() {this.needTotalList = this.initTotalList(this.columns);},watch: {selectedRows(selectedRows) {this.needTotalList = this.needTotalList.map((item) => {return {...item,total: selectedRows.reduce((sum, val) => {let v;try {v = val[item.dataIndex]? val[item.dataIndex]: eval(`val.${item.dataIndex}`);} catch (_) {v = val[item.dataIndex];}v = !isNaN(parseFloat(v)) ? parseFloat(v) : 0;return sum + v;}, 0),};});},},computed: {selectedRowKeys() {return this.selectedRows.map((record) => this.getKey(record));},},
};
</script><style scoped lang="less">
.standard-table {.alert {margin-bottom: 16px;.message {a {font-weight: 600;}}.clear {float: right;}}
}
</style>

2.vue2图片上传组件封装

使用

   <imgUpload v-model="assetsData.imageUrl"></imgUpload>

封装代码

<template><div><div class="clearfix"><a-upload:disabled="disabled"name="file"list-type="picture-card"class="avatar-uploader":show-upload-list="false"action="/upms/file/upload?fileType=image&dir=material/":before-upload="beforeUpload":headers="headers"@change="upchangeImg"><imgv-if="imgUrl":src="imgUrl"alt="avatar"style="height: 100px; width: 100px"/><div v-else><a-icon :type="loading ? 'loading' : 'plus'" /><div class="ant-upload-text">上传</div></div></a-upload><a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel"><img alt="example" style="width: 100%" :src="previewImage" /></a-modal></div></div>
</template><script>
//注意!!!!!
//在modal弹窗组件中使用该组件需要在关闭弹窗方法里清空数据否则会报错
import Cookie from "js-cookie";
export default {name: "vorganTree",props: {value: {type: String,default: undefined,},disabled: {type: Boolean,default: false,},placeholder: {type: String,default: "请选择所属组织",},},data() {return {headers: {// 请求头部Authorization: Cookie.get("Authorization"),},imgUrl: this.value,loading: false,previewVisible: false,previewImage: "",};},watch: {// value: {//   handler(newVal) {//     this.imgUrl = newVal;//   },//   immediate: true// }value(val) {this.imgUrl = val;},},methods: {//   图片handleCancel() {this.previewVisible = false;},// 图片上传的函数beforeUpload(file) {const isJpgOrPng =file.type === "image/jpeg" || file.type === "image/png";if (!isJpgOrPng) {this.$message.error("只能上传jpeg和png格式的图片!");}const isLt2M = file.size / 1024 / 1024 < 2;if (!isLt2M) {this.$message.error("图片必须小于2MB!");}return isJpgOrPng && isLt2M;},upchangeImg(info) {// handleChange2 (info) {if (info.file.status === "uploading") {this.loading = true;return;}if (info.file.status === "done") {this.imgUrl = info.file.response.link;this.onChange(info.file.response.link);this.loading = false;}if (info.file.status === "error") {this.$message.error("上传失败,请重试!");this.loading = false;}},onChange(value) {console.log("111111111111", value);// this.$emit("update:value", value);this.$emit("input", value);this.$emit("change", value);this.$emit("change:value", value);},},
};
</script><style scoped lang="less"></style>

预览

 <imgstyle="width: 100%":src="basicData.imageUrl":preview="basicData.imageUrl"/>

3.vue2树形下拉框封装

使用

  <a-form-item label="所属单位:"><vorganTreeplaceholder="请选择"v-model="assetsData.orgId"@change="getOrg"></vorganTree></a-form-item>getUsrOrg(e, e2) {this.assetsData.useOrgName = e2[0];},

封装的代码

<template><div><a-tree-select v-model="orgId" style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }":placeholder="placeholder" allow-clear  :disabled="disabled" :tree-data="vorganTreeData":replaceFields="replaceFields" @change="onChange"></a-tree-select><!-- tree-default-expand-all --></div>
</template><script>
//注意!!!!!
//在modal弹窗组件中使用该组件需要在关闭弹窗方法里清空数据否则会报错
import { getVorganTree } from "@/api/index"export default {name: 'vorganTree',props: {value: {type: String,default: undefined,},disabled: {type: Boolean,default: false,},placeholder: {type: String,default: '请选择'},replaceFields: {type: Object,default: () => {return {children: 'children',title: 'name',key: 'id',value: 'id',}},},},data () {return {orgId: this.value,vorganTreeData: [],}},watch: {value: {handler (newVal) {this.orgId = newVal},immediate: true,},},mounted () {this.getVorganTree()},methods: {getVorganTree () {getVorganTree().then(res => {this.vorganTreeData = res.data})},selectClear () {this.orgId = undefined},onChange (value,label) {this.$emit('update:value', value)this.$emit('change', value,label)},},model: {prop: 'value',event: 'change'}
}
</script><style scoped lang="less">
</style>

4.vue2单选表格封装

使用

    <selectUserv-model="assetsData.userId"@change="getUser"></selectUser>getUser(e) {this.assetsData.userName = e[0].nickName;},

封装代码分成3块,一个嵌套一个

第一步

<template><!-- 定义在这里的参数都是不可在外部覆盖的,防止出现问题 --><input-select:value="value":ellipsisLength="25":listUrl="url.list":columns="columns"v-on="$listeners"v-bind="attrs":disabled="disabled"@change="change"/>
</template><script>
import inputSelect from "@/components/inputSelect/index.vue";export default {name: "selectTop",components: { inputSelect },props: {value: {type: String,default: "",},disabled: {type: Boolean,default: false,},},data() {return {url: { list: "/upms/user/page" },columns: [{title: "用户名称",align: "center",width: "60%",widthRight: "70%",dataIndex: "nickName",},{ title: "手机号", align: "center", width: "40%", dataIndex: "phone" },],// 定义在这里的参数都是可以在外部传递覆盖的,可以更灵活的定制化使用的组件default: {name: "用户",width: "80%",displayKey: "nickName",returnKeys: ["id", "nickName"],rowKey: "id",valueKey: "id",queryParamText: "用户名称",queryParamCode: "nickName",multiple: false,buttons: false,},};},computed: {attrs() {const a = Object.assign(this.default, this.$attrs);console.log("a", a);return a;},},methods: {change(val) {console.log(val);this.$emit("changes", val);},},
};
</script><style lang="less" scoped></style>

第二步

<template><a-row class="j-select-biz-component-box" type="flex" :gutter="8"><a-col class="left" :class="{ full: !buttons }"><slot name="left"><a-selectmode="multiple":placeholder="placeholder"v-model="selectValue":options="selectOptions"allowClear:disabled="disabled":open="selectOpen"style="width: 100%"@dropdownVisibleChange="handleDropdownVisibleChange"@click.native="visible = buttons ? visible : true"/></slot></a-col><a-col v-if="buttons" class="right"><a-buttontype="primary"icon="search":disabled="disabled"@click="visible = true">{{ selectButtonText }}</a-button></a-col><select-modalv-model="selectValue":visible.sync="visible"v-bind="modalProps"@options="handleOptions"/></a-row>
</template><script>
import selectModal from "./selectModal";export default {name: "JSelectBizComponent",components: { selectModal },props: {value: {type: String,default: "",},/** 是否返回 id,默认 false,返回 code */returnId: {type: Boolean,default: false,},placeholder: {type: String,default: "请选择",},disabled: {type: Boolean,default: false,},// 是否支持多选,默认 truemultiple: {type: Boolean,default: true,},// 是否显示按钮,默认 truebuttons: {type: Boolean,default: true,},// 显示的 KeydisplayKey: {type: String,default: null,},// 返回的 keyreturnKeys: {type: Array,default: () => ["id", "id"],},// 选择按钮文字selectButtonText: {type: String,default: "选择",},},data() {return {selectValue: [],selectOptions: [],dataSourceMap: {},visible: false,selectOpen: false,};},computed: {valueKey() {return this.returnId ? this.returnKeys[0] : this.returnKeys[1];},modalProps() {return Object.assign({valueKey: this.valueKey,multiple: this.multiple,returnKeys: this.returnKeys,displayKey: this.displayKey || this.valueKey,},this.$attrs);},},mounted() {console.log("Received props:", this.$props);},watch: {value: {immediate: true,handler(val) {if (val) {this.selectValue = val.split(",");} else {this.selectValue = [];}},},selectValue: {deep: true,handler(val) {let rows = val.map((key) => this.dataSourceMap[key]);let data = val.join(",");if (data !== this.value) {this.$emit("select", rows);this.$emit("input", data);this.$emit("change", rows);}},},},methods: {handleOptions(options, dataSourceMap) {console.log("options", options, "dataSourceMap", dataSourceMap);this.selectOptions = options;this.dataSourceMap = dataSourceMap;},handleDropdownVisibleChange() {// 解决antdv自己的bug —— open 设置为 false 了,点击后还是添加了 open 样式,导致点击事件失效this.selectOpen = true;this.$nextTick(() => {this.selectOpen = false;});},},
};
</script><style lang="less" scoped>
.j-select-biz-component-box {@width: 82px;.left {width: calc(100% - @width - 8px);}.right {width: @width;}.full {width: 100%;}/deep/ .ant-select-search__field {display: none !important;}
}
</style>

第三步

<template><j-modalcentered:title="name + '选择'":width="width":visible="visible"switchFullscreen@ok="handleOk"@cancel="close"cancelText="关闭"><a-row :gutter="18"><a-col :span="16"><!-- 查询区域 --><div class="table-page-search-wrapper"><a-form layout="inline"><a-row :gutter="24"><a-col :span="14"><a-form-item :label="queryParamText || name"><a-inputv-model="queryParam[queryParamCode || valueKey]":placeholder="'请输入' + (queryParamText || name)"@pressEnter="searchQuery"/></a-form-item></a-col><a-col :span="8"><spanstyle="float: left; overflow: hidden"class="table-page-search-submitButtons"><a-button type="primary" @click="searchQuery" icon="search">查询</a-button><a-buttontype="primary"@click="searchReset"icon="reload"style="margin-left: 8px">重置</a-button></span></a-col></a-row></a-form></div><a-tablesize="middle"bordered:rowKey="rowKey":columns="innerColumns":dataSource="dataSource":pagination="ipagination":loading="loading":scroll="{ y: 240 }":rowSelection="{selectedRowKeys,onChange: onSelectChange,type: multiple ? 'checkbox' : 'radio',}":customRow="customRowFn"@change="handleTableChange"></a-table></a-col><a-col :span="8"><a-card:title="'已选' + name":bordered="false":head-style="{ padding: 0 }":body-style="{ padding: 0 }"><a-tablesize="middle":rowKey="rowKey"borderedv-bind="selectedTable"><span slot="action" slot-scope="text, record, index"><a @click="handleDeleteSelected(record, index)">删除</a></span></a-table></a-card></a-col></a-row></j-modal>
</template><script>
import { getAction } from "@/api/manage";
import Ellipsis from "@/components/jeecg/Ellipsis";
import JModal from "@/components/jeecg/JModal";
import { listSelect } from "@/mixins/listSelect";
import { cloneObject, pushIfNotExist } from "@/utils/util";export default {name: "JSelectBizComponentModal",mixins: [listSelect],components: { Ellipsis, JModal },props: {value: {type: Array,default: () => [],},visible: {type: Boolean,default: false,},valueKey: {type: String,required: true,},multiple: {type: Boolean,default: true,},width: {type: [Number, String],default: "80%",},name: {type: String,default: "",},listUrl: {type: String,required: true,default: "",},// 根据 value 获取显示文本的地址,例如存的是 username,可以通过该地址获取到 realnamevalueUrl: {type: String,default: "",},displayKey: {type: String,default: null,},columns: {type: Array,required: true,default: () => [],},// 查询条件CodequeryParamCode: {type: String,default: null,},// 查询条件文字queryParamText: {type: String,default: null,},rowKey: {type: String,default: "id",},// 过长裁剪长度,设置为 -1 代表不裁剪ellipsisLength: {type: Number,default: 12,},},data() {return {innerValue: [],// 已选择列表selectedTable: {pagination: false,scroll: { y: 240 },columns: [{...this.columns[0],width: this.columns[0].widthRight || this.columns[0].width,},{title: "操作",dataIndex: "action",align: "center",width: 60,scopedSlots: { customRender: "action" },},],dataSource: [],},renderEllipsis: (value) => (<ellipsis length={this.ellipsisLength}>{value}</ellipsis>),url: { list: this.listUrl },/* 分页参数 */ipagination: {current: 1,pageSize: 5,pageSizeOptions: ["5", "10", "20", "30"],showTotal: (total, range) => {return range[0] + "-" + range[1] + " 共" + total + "条";},showQuickJumper: true,showSizeChanger: true,total: 0,},options: [],dataSourceMap: {},};},computed: {// 表头innerColumns() {console.log("this.columns", this.columns);let columns = cloneObject(this.columns);columns.forEach((column) => {// 给所有的列加上过长裁剪if (this.ellipsisLength !== -1) {column.customRender = (text) => this.renderEllipsis(text);}});return columns;},},watch: {value: {deep: true,immediate: true,handler(val) {this.innerValue = cloneObject(val);this.selectedRowKeys = [];this.valueWatchHandler(val);this.queryOptionsByValue(val);},},dataSource: {deep: true,handler(val) {this.emitOptions(val);this.valueWatchHandler(this.innerValue);},},selectedRowKeys: {immediate: true,deep: true,handler(val) {this.selectedTable.dataSource = val.map((key) => {for (let data of this.dataSource) {if (data[this.rowKey] === key) {pushIfNotExist(this.innerValue, data[this.valueKey]);return data;}}for (let data of this.selectedTable.dataSource) {if (data[this.rowKey] === key) {pushIfNotExist(this.innerValue, data[this.valueKey]);return data;}}console.warn("未找到选择的行信息,key:" + key);return {};});},},},methods: {/** 关闭弹窗 */close() {this.$emit("update:visible", false);},valueWatchHandler(val) {val.forEach((item) => {this.dataSource.concat(this.selectedTable.dataSource).forEach((data) => {if (data[this.valueKey] === item) {pushIfNotExist(this.selectedRowKeys, data[this.rowKey]);}});});},queryOptionsByValue(value) {if (!value || value.length === 0) {return;}// 判断options是否存在value,如果已存在数据就不再请求后台了let notExist = false;for (let val of value) {let find = false;for (let option of this.options) {if (val === option.value) {find = true;break;}}if (!find) {notExist = true;break;}}if (!notExist) return;getAction(this.valueUrl || this.listUrl, {// 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确[this.valueKey]: value.join(",") + ",",pageNo: 1,pageSize: value.length,}).then((res) => {console.log(res);if (res.success) {let dataSource = res;if (!(dataSource instanceof Array)) {dataSource = res.records;}this.emitOptions(dataSource, (data) => {pushIfNotExist(this.innerValue, data[this.valueKey]);pushIfNotExist(this.selectedRowKeys, data[this.rowKey]);pushIfNotExist(this.selectedTable.dataSource, data, this.rowKey);});}});},emitOptions(dataSource, callback) {dataSource.forEach((data) => {let key = data[this.valueKey];this.dataSourceMap[key] = data;pushIfNotExist(this.options,{ label: data[this.displayKey || this.valueKey], value: key },"value");typeof callback === "function" ? callback(data) : "";});this.$emit("options", this.options, this.dataSourceMap);},/** 完成选择 */handleOk() {let value = this.selectedTable.dataSource.map((data) => data[this.valueKey]);this.$emit("input", value);this.close();},/** 删除已选择的 */handleDeleteSelected(record, index) {this.selectedRowKeys.splice(this.selectedRowKeys.indexOf(record[this.rowKey]),1);this.selectedTable.dataSource.splice(index, 1);},customRowFn(record) {return {on: {click: () => {let key = record[this.rowKey];if (!this.multiple) {this.selectedRowKeys = [key];this.selectedTable.dataSource = [record];} else {let index = this.selectedRowKeys.indexOf(key);if (index === -1) {this.selectedRowKeys.push(key);this.selectedTable.dataSource.push(record);} else {this.handleDeleteSelected(record, index);}}},},};},},
};
</script>
<style lang="less" scoped>
</style>
<template><a-modalref="modal":class="getClass(modalClass)":style="getStyle(modalStyle)":visible="visible"v-bind="_attrs"v-on="$listeners"@ok="handleOk"@cancel="handleCancel"><slot></slot><template v-if="!isNoTitle" slot="title"><a-row class="j-modal-title-row" type="flex"><a-col class="left"><slot name="title">{{ title }}</slot></a-col><a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen"><a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/></a-col></a-row></template><!-- 处理 scopedSlots --><template v-for="slotName of scopedSlotsKeys" :slot="slotName"><slot :name="slotName"></slot></template><!-- 处理 slots --><template v-for="slotName of slotsKeys" v-slot:[slotName]><slot :name="slotName"></slot></template></a-modal>
</template><script>import { getClass, getStyle } from '@/utils/props-util'import { triggerWindowResizeEvent } from '@/utils/util'export default {name: 'JModal',props: {title: String,// 可使用 .sync 修饰符visible: Boolean,// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符fullscreen: {type: Boolean,default: false},// 是否允许切换全屏(允许后右上角会出现一个按钮)switchFullscreen: {type: Boolean,default: false},// 点击确定按钮的时候是否关闭弹窗okClose: {type: Boolean,default: true},},data() {return {// 内部使用的 slots ,不再处理usedSlots: ['title'],// 实际控制是否全屏的参数innerFullscreen: this.fullscreen,}},computed: {// 一些未处理的参数或特殊处理的参数绑定到 a-modal 上_attrs() {let attrs = { ...this.$attrs }// 如果全屏就将宽度设为 100%if (this.innerFullscreen) {attrs['width'] = '100%'}return attrs},modalClass() {return {'j-modal-box': true,'fullscreen': this.innerFullscreen,'no-title': this.isNoTitle,'no-footer': this.isNoFooter,}},modalStyle() {let style = {}// 如果全屏就将top设为 0if (this.innerFullscreen) {style['top'] = '0'}return style},isNoTitle() {return !this.title && !this.allSlotsKeys.includes('title')},isNoFooter() {return this._attrs['footer'] === null},slotsKeys() {return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))},scopedSlotsKeys() {return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))},allSlotsKeys() {return this.slotsKeys.concat(this.scopedSlotsKeys)},// 切换全屏的按钮图标fullscreenButtonIcon() {return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'},},watch: {visible() {if (this.visible) {this.innerFullscreen = this.fullscreen}},innerFullscreen(val) {this.$emit('update:fullscreen', val)},},methods: {getClass(clazz) {return { ...getClass(this), ...clazz }},getStyle(style) {return { ...getStyle(this), ...style }},close() {this.$emit('update:visible', false)},handleOk() {if (this.okClose) {this.close()}},handleCancel() {this.close()},/** 切换全屏 */toggleFullscreen() {this.innerFullscreen = !this.innerFullscreentriggerWindowResizeEvent()},}}
</script><style lang="less">.j-modal-box {&.fullscreen {top: 0;left: 0;padding: 0;// 兼容1.6.2版本的antdv& .ant-modal {top: 0;padding: 0;height: 100vh;}& .ant-modal-content {height: 100vh;border-radius: 0;& .ant-modal-body {/* title 和 footer 各占 55px */height: calc(100% - 55px - 55px);overflow: auto;}}&.no-title, &.no-footer {.ant-modal-body {height: calc(100% - 55px);}}&.no-title.no-footer {.ant-modal-body {height: 100%;}}}.j-modal-title-row {.left {width: calc(100% - 56px - 56px);}.right {width: 56px;position: inherit;.ant-modal-close {right: 56px;color: rgba(0, 0, 0, 0.45);&:hover {color: rgba(0, 0, 0, 0.75);}}}}}@media (max-width: 767px) {.j-modal-box.fullscreen {margin: 0;max-width: 100vw;}}
</style>

5.vue2表格如果内容有图片需要放大

   <a-tablerowKey="id"bordered:columns="columns":data-source="dataSource"@change="handleTableChange":loading="loading":pagination="ipagination"><template slot="avatarslot" slot-scope="text, record, index"><div class="anty-img-wrap"><a-avatarshape="square":src="record.imageUrl"@click="handlePreviewPicture(record)"icon="picture"/></div></template><span slot="status" slot-scope="status"><a-tag:color="status == '0'? 'green': status == 1? 'blue': status == 2? 'volcano': status == 3? 'purple': 'pink'">{{ status | statusText }}</a-tag></span></a-table>//   图片handleCancel() {this.previewVisible = false;},// 图片查看弹窗弹出handlePreviewPicture(record) {if (record.imageUrl) {this.previewVisible = true;this.previewImage = record.imageUrl;} else {this.$message.info("无图片");}},

6.样式

效果图

       <a-card class="card" title="资产使用轨迹" :bordered="false"><div class="itembox"><div v-for="(item, index) of datalist2" :key="index"><div class="content"><b>{{ item.operateType | statusText }}</b><span>操作人:{{ item.creator }}</span><span>{{ item.createTime }}</span><div :class="index < datalist2.length - 1 ? 'arrow' : ''"></div></div></div></div></a-card>

 7.vue2步骤条组件封装

效果图

使用

   <ApprovalProgress :ininstanceId="instanceId"></ApprovalProgress>

封装

<template><div style="margin-left: 30px"><!-- <a-card title="审批进度" style="margin-top: 10px"><a-table size="default" :columns="columns" :data-source="schedule" bordered><span slot="action" slot-scope="text, record" class="flx-row-c-c">{{ record.result | listText(resultList) }}</span></a-table></a-card> --><a-steps progress-dot :current="current" direction="vertical"><a-step v-for="(item, index) of schedule" :key="index"><template v-slot:title><div style="display: flex"><div>{{ item.name }}</div><div style="margin-left: 10px; font-size: 12px; line-height: 23px">{{ item.result | listText(resultList) }}</div><div style="margin-left: 10px; font-size: 12px; line-height: 23px">{{ item.endTime }}</div></div></template><template v-slot:description><div style="display: flex; margin: 5px" v-for="(item2, index2) of item.assignees" :key="index2"><div style="">{{ item2.username }}</div><div style="margin-left: 20px">{{ item2.isExecutor ? "已处理" : "未处理" }}</div></div></template></a-step></a-steps></div>
</template>
<script>
import { historicFlow } from "@/api/wms";
export default {data() {return {schedule: [],Svgimg: "",columns: [{title: "时间",align: "center",dataIndex: "createTime",},{title: "操作人",align: "center",dataIndex: "username",},{title: "操作",dataIndex: "action",align: "center",scopedSlots: { customRender: "action" },},],current: 0,resultList: [{label: "待审核",value: "0",},{label: "处理中",value: "1",},{label: "已同意",value: "2",},{label: "驳回",value: "3",},{label: "撤回",value: "4",},{label: "删除",value: "5",},],};},props: {ininstanceId: {type: String,default: "",},Initiator: {type: String,default: "",},},watch: {ininstanceId: {immediate: true,handler(val) {this.getSchedule(val);},},},filters: {listText(val, list) {let mm = "";list.forEach((item) => {if (item.value == val) {mm = item.label;}});return mm;},},methods: {getSchedule(val) {historicFlow(val).then((res) => {let row = res.data;let index = row.findLastIndex((item) => item.assignees && item.assignees.some((item2) => item2.isExecutor === true));row.unshift({name: "发起",});row.push({name: "结束",});this.current = index + 2;this.schedule = row;});},},
};
</script>
<style lang="less" scoped>
/deep/ .ant-steps-dot .ant-steps-item-content,
.ant-steps-dot.ant-steps-small .ant-steps-item-content {width: 16.292vw;
}/deep/ .ant-steps-vertical .ant-steps-item-content {display: block;min-height: 5.5vw;overflow: hidden;
}
</style>

8.vue2表格总封装

代码

import T from "ant-design-vue/es/table/Table";
import get from "lodash.get"
export default {data() {return {needTotalList: [],selectedRows: [],selectedRowKeys: [],localLoading: false,localDataSource: [],localPagination: Object.assign({}, T.props.pagination)};},props: Object.assign({}, T.props, {rowKey: {type: [String, Function],default: 'id'},data: {type: Function,required: true},pageNum: {type: Number,default: 1},pageSize: {type: Number,default: 10},showSizeChanger: {type: Boolean,default: true},showAlertInfo: {type: Boolean,default: false},showPagination: {default: 'auto'},deleteShow: { // 删除键type: Boolean,default: false},bordered: {type: Boolean,default: true},}),watch: {'localPagination.current'(val) {this.$router.push({name: this.$route.name,params: Object.assign({}, this.$route.params, {current: val}),});},pageNum(val) {Object.assign(this.localPagination, {current: val});},pageSize(val) {Object.assign(this.localPagination, {pageSize: val});},showSizeChanger(val) {Object.assign(this.localPagination, {showSizeChanger: val});}},zzh(){//const that = this.call(this);const that = thisreturn that;},created() {this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, {current: this.pageNum,pageSize: this.pageSize,showSizeChanger: this.showSizeChanger});this.needTotalList = this.initTotalList(this.columns)this.loadData();},methods: {// 加载状态loadingShow(value) {this.localLoading = value},refresh() {var mm = {current: 1,total: 0,size: this.pageSize,}this.loadData(mm);},// 刷新删除deleteRefresh() {this.loadData()},loadData(pagination, filters, sorter) {this.localLoading = truevar result = this.data(Object.assign({current: (pagination && pagination.current) ||this.localPagination.current,size: (pagination && pagination.pageSize) ||this.localPagination.pageSize},(sorter && sorter.field && {sortField: sorter.field}) || {},(sorter && sorter.order && {sortOrder: sorter.order}) || {}, {...filters}));if (result instanceof Promise) {result.then(r => {this.localPagination = Object.assign({}, this.localPagination, {current: (pagination && pagination.current) ||this.localPagination.current,  // 返回结果中的当前分页数total: r.totalCount, // 返回结果中的总记录数showSizeChanger: this.showSizeChanger,pageSize: (pagination && pagination.pageSize) ||this.localPagination.pageSize});!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)this.localDataSource = r.data; // 返回结果中的数组数据this.localLoading = false});}},initTotalList(columns) {const totalList = []columns && columns instanceof Array && columns.forEach(column => {if (column.needTotal) {totalList.push({ ...column,total: 0})}})return totalList},updateSelect(selectedRowKeys, selectedRows) {this.selectedRowKeys = selectedRowKeysthis.selectedRows = selectedRowslet list = this.needTotalListthis.needTotalList = list.map(item => {return {...item,total: selectedRows.reduce((sum, val) => {let total = sum + get(val, item.dataIndex)return isNaN(total) ? 0 : total}, 0)}})// this.$emit('change', selectedRowKeys, selectedRows)},updateEdit() {this.selectedRows = []},onClearSelected() {this.selectedRowKeys = []this.selectedRows = []this.updateSelect([], [])this.$emit('emptyData',{selectedRowKeys:[],selectedRows:[]})this.$emit('onSelect', { selectedRowKeys: [], selectedRows: [] })},onDeleteSelected() {this.$emit('DeleteData')},renderMsg(h) {const _vm = thisthis.that = thislet d = []// 构建 已选择// d.push(//   h('span', {//     style: {//       marginRight: '12px'//     }//   }, ['已选择 ', h('a', {//     style: {//       fontWeight: 600//     }//   }, this.selectedRows.length)])// );// // 构建 列统计// this.needTotalList.map(item => {//   d.push(h('span', {//       style: {//         marginRight: '12px'//       }//     },//     [//       `${ item.title }总计 `,//       h('a', {//         style: {//           fontWeight: 600//         }//       }, `${ !item.customRender ? item.total : item.customRender(item.total) }`)//     ]))// });// // 构建 清空选择// d.push(h('a', {//   style: {//     marginLeft: '24px'//   },//   on: {//     click: _vm.onClearSelected//   }// }, '清空'))//   if(this.deleteShow){//   // 构建 清空选择//   d.push(h('a', {//     style: {//       marginLeft: '24px',//       color: '#DC564A'//     },//     on: {//       click: _vm.onDeleteSelected//     }//   }, '删除'))// }return d},renderAlert(h) {return h('span', {slot: 'message'}, this.renderMsg(h))},},render(h) {const _vm = thislet props = {},localKeys = Object.keys(this.$data);Object.keys(T.props).forEach(k => {let localKey = `local${k.substring(0,1).toUpperCase()}${k.substring(1)}`;if (localKeys.includes(localKey)) {return props[k] = _vm[localKey];}return props[k] = _vm[k];})// 显示信息提示if (this.showAlertInfo) {props.rowSelection = {selectedRowKeys: this.selectedRowKeys,onChange: (selectedRowKeys, selectedRows) => {_vm.updateSelect(selectedRowKeys, selectedRows)_vm.$emit('onSelect', { selectedRowKeys: selectedRowKeys, selectedRows: selectedRows })}};return h('div', {}, [h("a-table", {tag: "component",attrs: props,on: {change: _vm.loadData},scopedSlots: this.$scopedSlots}, this.$slots.default)]);}return h("a-table", {tag: "component",attrs: props,on: {change: _vm.loadData},scopedSlots: this.$scopedSlots}, this.$slots.default);},
};

考虑前面有没有单选框 有的话加

 :showAlertInfo="true"
 <s-tableref="tableAssets"size="default":columns="columns4":data="loadDataListAssets":showAlertInfo="true"@onSelect="onChangeAssetsList"></s-table>//方法loadDataListAssets: (parameter) => {return listAssets(Object.assign(parameter, this.listAssetsParam)).then((res) => {var mm = { data: [] };mm.size = res.data.size;mm.current = res.data.current;mm.totalCount = res.data.total;mm.totalPage = res.data.pages;mm.data = res.data.records;return mm;});},// 选择资产资产查询列表-选择onChangeAssetsList(row) {this.AssetsListRow = row.selectedRows;console.log(row.selectedRows);},

9.vue2单选框配合确认框样式

效果图

代码

     <a-tableborderedrowKey="id":pagination="false":columns="columns":data-source="dataSource"><spanslot="ifNoOrderRecieve"slot-scope="text, record, index"class="flx-row-c-c"><div><a-popconfirmtitle="是否修改允许无订单订货?"ok-text="确定"cancel-text="取消"@confirm="confirmA(record, index)"@cancel="cancelA"><a-checkboxstyle="margin-left: 20px"v-model="dataSource[index].ifNoOrderRecieve"></a-checkbox></a-popconfirm></div></span><spanslot="ifOrderExceedApply"slot-scope="text, record, index"class="flx-row-c-c"><div><a-popconfirmtitle="是否订单数量超过申请数量?"ok-text="确定"cancel-text="取消"@confirm="confirmB(record, index)"@cancel="cancelB"><a-checkboxstyle="margin-left: 20px"v-model="dataSource[index].ifOrderExceedApply"></a-checkbox></a-popconfirm></div> </span></a-table>
  confirmA(record, index) {let self = this;self.dataSource[index].ifNoOrderRecieve = !record.ifNoOrderRecieve;let data = {id: record.id ? record.id : null,organId: record.organId,ifNoOrderRecieve: self.dataSource[index].ifNoOrderRecieve ? "1" : "0",ifOrderExceedApply: record.ifOrderExceedApply ? "1" : "0",};organconfig(data).then((res) => {console.log(res);this.$message.success("修改成功");this.getList();});},cancelA() {},

10.下载导出模板

import { downloadFile } from "@/api/manage";
export function downloadFile(url, fileName, parameter,method) {return downFile(url, parameter,method).then((data) => {// if (!data || data.size === 0) {//   Vue.prototype['$message'].warning('文件下载失败')//   return// }if (typeof window.navigator.msSaveBlob !== "undefined") {window.navigator.msSaveBlob(new Blob([data]), fileName);} else {let url = window.URL.createObjectURL(new Blob([data]));let link = document.createElement("a");link.style.display = "none";link.href = url;link.setAttribute("download", fileName);document.body.appendChild(link);link.click();document.body.removeChild(link); //下载完成移除元素window.URL.revokeObjectURL(url); //释放掉blob对象}});
}//导出模板getExport() {downloadFile("/asset/entryrecord/exportTemplateXls","财务信息模板.xlsx",{},"post");},

 或者另一种方式

导入api

const warehousingExport = (fileName, params) => downloadFile("/asset/assetsinfo/export", fileName, params, "get"); // 导出资产列表
  <a-buttontype="primary"@click="getWarehousingExport"style="margin-left: 8px">导出资产</a-button>getWarehousingExport() {var mm = {};mm.id = this.selectedRows.map((item) => {return item.materialCode;});warehousingExport("资产列表", mm).then((res) => {// let execlName = "资产文件名称";// const buf = Buffer.from(res),//   blob = new Blob([buf], { type: "application/vnd.ms-excel" }),//   downloadElement = document.createElement('a'),//   href = window.URL.createObjectURL(blob); // 创建下载的链接// downloadElement.href = href;// downloadElement.download = `${execlName}.xls`; // 下载后文件名// document.body.appendChild(downloadElement);// downloadElement.click(); // 点击下载// window.URL.revokeObjectURL(href); // 释放掉blob对象});},

11.文件打印

导入api

const printAssetList = (fileName, params) => downloadFile("/asset/warehousing/printAssetList", fileName, params, "pdf"); // 打印资产标签列表
import {printAssetList,
} from "@/api/apis";
 <a-buttontype="primary"@click="clickAssetsPrint":loading="assetsPrintLoading"style="margin-left: 8px">资产打印</a-button>
assetsPrintLoading: false,// 打印资产clickAssetsPrint() {this.assetsPrintLoading = true;var mm = {};mm.id = this.selectedRows.map((item) => {return item.materialCode;});printAssetList("资产标签", mm).then((res) => {this.assetsPrintLoading = false;}).catch((err) => {this.assetsPrintLoading = false;});// this.$refs.barCode.transferData(this.selectedRows)},

12.样式

 <div class="sponeli"><span>维保到期前</span><a-input v-model="queryData.maintenanceExpire" /><span>天进行预警提醒</span></div><div class="sponeli"><span>租赁到期前</span><a-input v-model="queryData.rentExpire" /><span>天进行预警提醒</span></div><div class="sponeli"><span>闲置天数超过</span><a-input v-model="queryData.idleLimit" /><span>天进行预警提醒</span></div><div class="sponeli"><span>经营资产闲置率高于</span><a-input v-model="queryData.idleRateMaxLimit" /><span>进行预警提醒</span></div><div class="sponeli"><span>经营资产收租率低于</span><a-input v-model="queryData.rentRateMinLimit" /><span>进行预警提醒</span></div>

13.附件上传

  <a-form-itemlabel="附件:":labelCol="{ span: 2 }":wrapperCol="{ span: 21 }"><a-uploadname="file":multiple="true":action="HttpAction":headers="headers"@change="handleChange":fileList="fileList"><a-button> <a-icon type="upload" />上传</a-button></a-upload>
      HttpAction: `${process.env.VUE_APP_API_FATHER_URL}/upms/file/upload?fileType=image&dir=material/`, // 附件上传请求连接
 headers: {// 请求头部Authorization: Cookie.get("Authorization"),},
import Cookie from "js-cookie";
 // 文件上传handleChange(info) {if (info.file.status !== "uploading") {console.log(info.file, info.fileList);}if (info.file.status === "done") {// this.$message.success(`${info.file.name} file uploaded successfully`);console.log(info.file);} else if (info.file.status === "error") {this.$message.error(`${info.file.name} file upload failed.`);}let fileList = [...info.fileList];// fileList = fileList.slice(-1);fileList = fileList.map((file) => {if (file.response) {// Component will show file.url as linkfile.url = file.response.data;}return file;});this.fileList = fileList;},
fileList:[]

详情的时候

 setFile(record) {let row = record;this.fileList = [];if (row.fileUrl && row.fileName) {row.fileUrl.split(",").forEach((item, index) => {row.fileName.split(",").forEach((item2, index2) => {if (index == index2) {let imgUrl = {uid: randomLenNum(),status: "done",name: item2,response: {link: item,},url: item,};this.fileList.push(imgUrl);console.log(this.fileList);}});});}},

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

必应bing国内推广开户,全方位必应广告开户流程介绍!

在所有获客渠道中&#xff0c;搜索引擎广告成为企业扩大品牌影响力、精准触达目标客户的关键途径之一。作为全球领先的搜索引擎之一&#xff0c;必应&#xff08;Bing&#xff09;拥有庞大的用户群体和独特的市场优势&#xff0c;是企业不可忽视的营销阵地。云衔科技&#xff0…

vscode添加代办相关插件,提高开发效率

这里写目录标题 前言插件添加添加TODO Highlight安装TODO Highlight在项目中自定义需要高亮显示的关键字 TODO Tree安装TODO Tree插件 单行注释快捷键 前言 在前端开发中&#xff0c;我们经常会遇到一些未完成、有问题或需要修复的部分&#xff0c;但又暂时未完成或未确定如何处…

合约的值类型

基本数据类型&#xff1a;整数、枚举、布尔&#xff08;类似java的数据类型&#xff09;Address、Contract&#xff08;这两种是solidity特有的数据类型&#xff09;Fixed byte array&#xff08;定长字节数组&#xff09; Integer(int/uint) int/uint 以8位字节递增&#xf…

推荐ChatGPT4.0——数学建模

1.建模助手 2. 可直接上传文档分析 3.获取途径 现在商家有活动&#xff0c;仅仅需要19.9&#xff01;&#xff01;&#xff01;&#xff01; 现在有优惠&#xff1a; 推荐人写&#xff1a;love 周卡&#xff0c;半月卡&#xff0c;月卡优惠码是love&#xff0c; 会优惠10元…

表现层框架设计之表现层设计模式_1.MVC模式

1.MVC模式三个核心模块 MVC是一种目前广泛流行的软件设计模式。近年来&#xff0c;随着Java EE的成熟&#xff0c;MVC成为了Java EE平台上推荐的一种设计模式。MVC强制性地把一个应用的输入、处理、输出流程按照视图、控制、模型的方式进行分离&#xff0c;形成了控制器…

Github上传时报错The file path is empty的解决办法

问题截图 文件夹明明不是空的&#xff0c;却怎么都上传不上去。 解决方案&#xff1a; 打开隐藏文件的开关&#xff0c;删除原作者的.git文件 如图所示&#xff1a; 上传成功&#xff01;

全面掌握深度学习:从基础到前沿

引言&#xff1a;深入探索深度学习的世界 在人工智能&#xff08;AI&#xff09;的广阔领域中&#xff0c;深度学习已经成为最令人瞩目的技术之一。它不仅推动了科技的许多突破性进展&#xff0c;也正在改变我们的工作和生活方式。本博客旨在全面总结深度学习的关键知识点&…

Rust面试宝典第14题:旋转数组

题目 给定一个数组&#xff0c;将数组中的元素向右移动k个位置&#xff0c;其中k是非负数。要求如下&#xff1a; &#xff08;1&#xff09;尽可能想出更多的解决方案&#xff0c;至少有三种不同的方法可以解决这个问题。 &#xff08;2&#xff09;使用时间复杂度为O(n)和空间…

RAW转换和图像编辑工具:Capture One 23 Pro (win/mac)中文专业版

Capture One 23是一款功能强大的桌面版照片编辑软件&#xff0c;由丹麦PHASE ONE飞思数码公司开发。 以下是该软件的一些主要特点&#xff1a; 强大的RAW处理功能&#xff1a;Capture One 23支持多种品牌的相机和镜头&#xff0c;提供了丰富的RAW处理工具&#xff0c;包括曝光、…

安装ollama并部署大模型并测试

Ollama介绍 项目地址&#xff1a;ollama 官网地址&#xff1a; https://ollama.com 模型仓库&#xff1a;https://ollama.com/library API接口&#xff1a;api接口 Ollama 是一个基于 Go 语言开发的简单易用的本地大语言模型运行框架。可以将其类比为 docker&#xff08;同基…

【vue-3】动态属性绑定v-bind

1、文本动态绑定&#xff1a; <input type"text" v-bind:value"web.url"> 简写&#xff1a; <input type"text" :value"web.url"> 2、文字样式动态绑定 <b :class"{textColor:web.fontStatus}">vue学…

word页眉线如何置于文字上方

然后 敲黑板&#xff0c;点这里

【Java超详细的学习笔记】Java超详细的学习笔记,适合小白入门,Java语法学习,Java开发学习笔记,Java入门学习笔记

一&#xff0c;Java初学者学习笔记 Java超详细的学习笔记&#xff0c;点击我获取 1&#xff0c;Java基础语法 一个 Java 程序可以认为是一系列对象的集合&#xff0c;而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。 对象&#…

碳课堂|ISO 14067 产品碳足迹国际标准

为规范评估产品碳排放&#xff0c;国际标准化组织发布了《ISO14067&#xff1a;2018温室气体-产品碳足迹-量化要求及指南》&#xff0c;标准量化产品生命周期阶段&#xff08;包括从资源开采、原材料采购到产品的生产、使用和报废阶段&#xff09;的温室气体排放的通用标准。该…

功耗相关总结

文章目录 功耗相关的使用场景MCU中低功耗的应用RTOS中低功耗应用 功耗相关的使用场景 目前越来越多的嵌入式设备采用电池进行供电&#xff0c;而不是跟台式电脑一样&#xff0c;可以一直连接着电源。在电池供电的场景下&#xff0c;对功耗的要求很高&#xff0c;工程师们尽量希…

炫酷gdb

在VS里面调试很方便对吧&#xff1f;&#xff08;F5直接调试&#xff0c;F10逐过程调试--不进函数&#xff0c;F11逐语句调试--进函数&#xff0c;F9创建断点&#xff09;&#xff0c;那在Linux中怎么调试呢&#xff1f; 我们需要用到一个工具&#xff1a;gdb 我们知道VS中程…

从业务角度来看,DevOps 是什么?

如果您在我们的应用程序名称中看到“DevOps”&#xff0c;这意味着我们必须正确解释该术语&#xff0c;我们会这样做&#xff0c;但角度会有所不同。让我们从业务角度看看 DevOps 是什么。 通用名称 首先你应该知道&#xff0c;DevOps 没有明确的定义。是的。 大多数情况下&a…

安卓实现5个底部导航栏切换fragment

步骤&#xff0c;写 5 个 fragment 自定义的类5个布局文件&#xff1a; package com.xmkjsoft.xhgh.fragment;import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup;import androidx.annotation.NonNul…

win11安装docker运行Open-Webui 界面化展示 ollama大模型

1.OpenWeb UI运行需要docker 环境下载docker Get Started | Docker 2.需要命令提示符docker -v 查询是否安装成功&#xff1b; 查询docker详情docker version 3.github拉取open-webUi镜像Package open-webui GitHub 复制命令运行在命令提示符&#xff1b; 等待下载完成 4.到…

Web安全:企业如何抵御常见的网络攻击?

近年来随着人类社会向数字世界的加速发展&#xff0c;勒索软件攻击事件在全球范围内呈现快速上升的态势&#xff0c;几乎所有国家的政府、金融、教育、医疗、制造、交通、能源等行业均受到影响&#xff0c;可以说有互联网的地方就可能发生勒索软件攻击事件。 Web安全是一个大课…