avue属性使用及详细介绍
<template>
<basic-container>
<avue-crud
表格配置属性
:option="option"
表格等待框的控制,加载loading
:table-loading="loading"
搜索的变量(需要sync修饰符)
:search.sync="search"
是否显示设置
:visible.sync="changeInfo"
表格数据列表
:data="data"
表格分页配置选项(需要sync修饰符)
:page.sync="page"
按钮权限控制
:permission="permissionList"
打开前的回调function(file,column)
:before-open="beforeOpen"
数据模型, 用来存取页面值的
v-model="form"
在普通的DOM元素上使用,引用指向的就是DOM元素;
ref="crud"
表格点击运行方法, onclick方法定义
@cell-click="pageto"
修改数据后点击确定触发该事件
@row-update="rowUpdate"
新增数据后点击确定触发该事件
@row-save="rowSave"
行数据删除时触发该事件
@row-del="rowDel"
单击行运行的方法
@row-click="handleRowClick"
搜索栏变化事件
@search-change="searchChange"
清空搜索栏变化事件
@search-reset="searchReset"
选择框变化变化事件
@selection-change="selectionChange"
点击页码会调用current-change方法回调当前页数,返回当前第几页
@current-change="currentChange"
点击每页多少条会调size-change方法回调
@size-change="sizeChange"
点击刷新按钮触发该事件
@refresh-change="refreshChange"
初始化页面数据的方法
@on-load="onLoad"
>
<!-- 左侧按钮---自定义 -->
<template
slot="menuLeft"
slot-scope="{row,index}"
>
<el-button
icon="el-icon-delete"
size="small"
type="text"
@click="$refs.crud.rowDel(row,index)"
>删除</el-button>
</template>
<!-- 右侧按钮---自定义 -->
<template slot="menuRight">
<el-button
type="primary"
icon="el-icon-edit"
circle
size="small"
></el-button>
</template>
<!-- 表格内--自定义 -->
<template
slot="menu"
slot-scope="{row,index}"
>
<el-button
icon="el-icon-delete"
size="small"
type="text"
@click="$refs.crud.rowDel(row,index)"
>删除</el-button>
</template>
<!-- 自定义标头: xxHeader-->
<template
slot="productNameHeader"
slot-scope="{column}"
>
<el-popover
placement="top-start"
title=""
trigger="hover"
width="220"
>
<div>产品名称唯一,不允许重复</div>
<span
slot="reference"
style="cursor: pointer;"
>产品名称<i class="el-icon-warning table-msg"></i></span>
</el-popover>
</template>
<!-- 自定义---搜索 xxSearch-->
<template
slot="productNameSearch"
slot-scope="{row,size}"
>
<el-autocomplete
v-model="search.productName"
:debounce=0
:fetch-suggestions="querySearchAsync"
class="inline-input"
placeholder="请输入"
popper-class="search-autocpmplete"
@select="handleSelectSearch"
></el-autocomplete>
</template>
<!-- 下方的rodio -->
<template
slot="productStatus"
slot-scope="{row}"
>
<span
v-if="row.productStatus==1"
class="txt-green"
>· 启用</span>
<span
v-if="row.productStatus==2"
class="txt-gray"
>· 禁用</span>
</template>
<template
slot="ctwingProductKey"
slot-scope="{row}"
>
<avue-text-ellipsis
:key="row.ctwingProductKey"
:height="50"
:text="row.ctwingProductKey"
:width="170"
placement="top"
use-tooltip
>
<small slot="more">...</small>
</avue-text-ellipsis>
</template>
<template
slot="ctwingProductIdHeader"
slot-scope="{row}"
>
<el-popover
placement="top-start"
title=""
trigger="hover"
width="220"
>
<div style="line-height:23px;font-size:13px;">产品ID是从电信平台获取的,需要手动维护</div>
<span
slot="reference"
style="cursor: pointer;"
>产品ID<br />(Ctwing)<i
class="el-icon-warning table-msg"
style="vertical-align: text-top;margin-top: -20px;"
></i></span>
</el-popover>
</template>
<!-- 自定义新增、编辑弹窗的新组件 -->
<template
slot="ruluXianForm"
slot-scope="{row}"
>
<el-divider></el-divider>
</template>
</avue-crud>
<!-- 上传导入弹窗-->
<el-dialog
title="批量导入"
append-to-body
:visible.sync="excelBox"
width="555px"
>
<avue-form
:option="excelOption"
v-model="excelForm"
:upload-after="uploadAfter"
></avue-form>
</el-dialog>
<!-- 自定义新增弹窗 -->
</basic-container>
</template>
<script>
import { add, getDetail, getList, getListProductAll, remove, update } from "@/api/centre/product";
import { getProtocolList } from "@/api/centre/protocol";
import website from '@/config/website';
import { getToken } from '@/util/auth';
import { downloadXls } from "@/util/util";
import func from '@/util/func'
export default {
data() {
return {
dialogType: '', // 弹窗类型
// 上传
excelBox: false,
excelForm: {},
excelOption: {
submitBtn: false,
emptyBtn: false,
column: [
{
label: '模板上传',
prop: 'excelFile',
type: 'upload',
drag: true,
loadText: '模板上传中,请稍等',
span: 24,
propsHttp: {
res: 'data',
},
tip: '请上传 .xls,.xlsx 标准格式文件',
action: '/api/combustiblegasDevice/import',
},
],
},
// 数据相关
data: [], // 表格数据
search: {},
form: {},
query: {},
loading: true, // 加载状态
page: {
pageSize: 10,
currentPage: 1,
total: 0
},
option: {
indexFixed: false, // 表格错位问题
title: '', // 表格标题
size: 'medium', // 组件的尺寸, medium/small/mini
height: 'auto', // 表格高度
align: 'center', // 对齐方式left center right
stripe: true, // 条纹
emptyText: "暂无数据哦~", // 数据为空的提示
calcHeight: 30, // 表格高度差(主要用于减去其他部分让表格高度自适应)
tip: false, // 提示信息
searchShow: true, // 首次加载是否显示搜索
searchIcon: true, // 按钮是否折叠
searchMenuSpan: 4, // 搜索按钮长度
searchSpan: 6, // 搜索框长度, 最大长度24
border: true, // 表格边框是否显示
index: true, // 是否显示序号
selection: true, // 全选框显示
reserveSelection: true, // 在数据更新之后保留之前选中的数据;
// 按钮系列
viewBtn: true, // 是否显示查看按钮
viewBtnText: '', // 表格查看按钮文案 string - 查看
viewBtnIcon: '', // 表格查看按钮图标
addBtn: false, // 是否显示新增按钮
addBtnText: '', // 表格新增按钮文案
addBtnIcon: '', // 表格新增按钮图标
editBtn: false, // 是否显示编辑按钮
editBtnText: '', // 表格编辑按钮文案 string - 修改
editBtnIcon: '', // 表格编辑按钮图标
delBtn: false, // 是否显示删除按钮
delBtnText: '', // 表格删除按钮文案
delBtnIcon: '', // 表格删除按钮图标
excelBtn: false, // 表格导出按钮是否显示
dialogMenuPosition: 'right', // 弹窗框按钮的位置,left/center/right
dialogTop: 45, // 弹窗顶部的距离 number - 25
dialogType: 'dialog', // 弹窗方式,dialog/drawer
dialogDirection: '', // 弹窗打开方向, rtl/ltr/ttb/tbb
dialogWidth: '55%', // 弹窗宽度
dialogClickModal: false, // 弹窗是否可以通过点击modal关闭
dialogFullscreen: false, // 弹窗是否为全屏
dialogDrag: false, // 弹窗是否可以拖拽
addTitle: '', // 新增弹窗标题
editTit: '', // 编辑弹窗标题
viewTitle: '', // 查看弹窗标题
labelWidth: 120, // 表单前面的标题长度
refreshBtn: false, // 表格右上角,刷新按钮
columnBtn: false, // 表格右上角,列表按钮
searchBtn: false, // 表格右上角,搜索按钮,搜索条件展开折叠
menu: true, // 是否显示操作栏
defaultExpandAll: true, // 树默认展开
column: [
{
label: "产品名称",
prop: "productName",
search: true, // 搜索
headerslot: true, // 表头---自定义
search: true, // 是否可搜索
fixed: true, // 列是否固定在左侧或者右侧,true 表示固定在左侧
hide: true, // 列表中是否展示
display: false, // 弹出"表单"是否显示--------新增、编辑等表单字段的显示和隐藏
maxlength: 30, //字数限制
showWordLimit: true, // 展示字数0/500
viewDisplay: true, // 表单查看时项是否禁止
addDisplay: false, // 表单新增时项是否禁止,可以用this, this.productPlatform == 1 ? true : false,
editDisplay: false, // 表单编辑时项是否禁止
dataType: 'number', // 数据的类型:string/number
span: 6, // 一共24列
rules: [{
required: true,
message: "请输入产品名称",
trigger: "blur"
}]
},
// 上传系列
{
label: "产品图标",
prop: "productIco",
type: 'upload',
span: 24,
drag: true, // 拖拽排序
listType: 'picture-img', // 配置上传的类型: picture-card:多张,picture-img:一张,附件上传:picture
multiple: true, // 是否多选上传
accept: 'image/png, image/jpeg', // 上传的类型
limit: 2, // 最多传几张
dataType: 'object', // 数据的类型:string/object
fileType: 'img', // 文件的类型:img/video/audio
// 如果接口需要传参
data: {
a: 1
},
// 头部设置
headers: {
b: 1
},
action: '/api/blade-resource/oss/endpoint/put-file',
propsHttp: {
name: 'name', //图片的名称
url: 'link', // 路径地址
res: 'data', // 返回数据层级结构
home: '', // 相对路径的主路径
},
fileText: '我是上传按钮',
loadText: '上传等待文案',
tip: '只能上传jpg/png用户头像,且不超过500kb',
// 图片水印
canvasOption: {
text: 'avue',
ratio: 0.1
},
// 图片裁剪
cropperOption: {
autoCropWidth: 100,
autoCropHeight: 100,
fixed: true,
fixedNumber: [100, 100],
},
rules: [{
required: true,
message: "请选择产品图标",
trigger: "change"
}],
change: () => {
if (['add', 'edit'].includes(this.dialogType))
this.$refs.crud.validateField('productIco') // 校验
}
},
// tree树形
{
label: "供应商分类",
prop: "classifyName",
addDisplay: false,
editDisplay: false,
viewDisplay: true,
span: 16,
row: true,
},
{
label: "供应商分类",
prop: "classifyId",
type: 'tree', // slect, tree
filterable: true, // 当类型为select的时候可搜索
search: true, // 搜索
multiple: true, // 是否多选
accordion: true, // 是否每次只打开一个同级树节点展开
parent: false, // 父级不可以选择
checkStrictly: true, // 可以选择任何一个节点
hide: true, // 列表隐藏
dicQuery: '', // 数据字典接口url携带请求参数
dicHeaders: '', // 数据字典接口url携带头部参数
dicMethod: '', // 数据字典接口请求方式
dicData: [], // 数据
dicUrl: "/api/productSupplier/productSupplier/page?size=500",
props: {
value: 'xx',
label: 'xx',
children: 'xx'
},
// 改变dicUrl数据结构
dicFormatter: (res) => { // 数据字典接口url返回数据格式化方法
let data = res.data.records
let anzData = []
if (data) {
data.forEach(items => {
anzData.push({
value: items.id,
label: items.supplierShort,
})
})
}
return anzData; //返回字典的层级结构
},
// 值改变的时候
change: (val) => {
if (['add', 'edit'].includes(this.dialogType)) {
this.$refs.crud.validateField('supplierId')
if (this.form.classifyId && val.value) {
this.getProtocolSeletItem(this.form.classifyId, val.value)
}
}
},
// tree时候触发
nodeClick: (data, node, nodeComp) => {
this.form.menuPath = data.path;
console.log(node, nodeComp, 'data===', data)
},
rules: [{
required: true,
message: "请选择供应商分类",
trigger: "change"
}],
},
// 懒加载--三级联动
{
label: '级联',
prop: 'cascader',
type: "cascader",
props: {
label: 'name',
value: 'code'
},
lazy: true,
lazyLoad(node, resolve) {
let stop_level = 2;
let level = node.level;
let data = node.data || {}
let code = data.code;
let list = [];
let callback = () => {
resolve((list || []).map(ele => {
return Object.assign(ele, {
leaf: level >= stop_level
})
}));
}
if (level == 0) {
axios.get(`${baseUrl}/getProvince`).then(res => {
list = res.data;
callback()
})
} else if (level == 1) {
axios.get(`${baseUrl}/getCity/${code}`).then(res => {
list = res.data;
callback()
})
} else if (level == 2) {
axios.get(`${baseUrl}/getArea/${code}`).then(res => {
list = res.data;
callback()
})
} else {
callback()
}
}
},
//
{
label: "状态",
prop: "productStatus",
width: 90,
type: "radio", // radio,checkbox
slot: true, // 上边自定义
value: 1, // 默认值
dicData: [
{
label: '启用',
value: 1
},
{
label: '停用',
value: 2
}
],
// 通过radio控制哪些展示哪些隐藏
control: (val, form) => {
if (val === 1) {
return {
ctwingProductKey: { // 参数prop
display: true,
editDisabled: true
},
ctwingProductId: {
display: true,
editDisabled: true
},
communicationMode: {
display: false,
editDisabled: false
}
}
} else if (val === 2) {
return {
ctwingProductKey: {
display: false
},
ctwingProductId: {
display: false
},
communicationMode: {
display: true,
}
}
}
},
rules: [{
required: true,
message: "请选择",
trigger: "blur"
}]
},
// 弹窗里------自定义
{
label: '',
labelWidth: 0,
prop: 'ruluXian',
formslot: true, // 自定义新增、编辑弹窗 上边用ruluXianForm关联
hide: true,
span: 24,
viewDisplay: false,
},
{
label: "创建时间",
prop: "createTime",
type: 'date', // date:年月日(yyyy-MM-dd),datetime:年月日时分秒(yyyy-MM-dd HH:mm:ss),daterange:年月日范围(yyyy-MM-dd),datetimerange:年月日时分秒范围(yyyy-MM-dd HH:mm:ss)
search: true,
searchValue: '2023-12-12', // 搜索框默认日期 日期搜索范围:['2023-12-12','2023-12-15']
searchRange: true, //控制搜索时是否是日期范围默认为false是单独的一天
searchClearable: true, // 搜索项清除
value: '2023-12-14', // 弹窗里的默认日期, 日期搜索范围:['2023-12-12','2023-12-15']
popperClass: 'popperClass', // popperClass属性配置样式的class名字
format: 'yyyy年MM月dd日', // 使用format指定输入框的格式;yyyy年MM月dd日 HH时mm分ss秒
valueFormat: 'yyyy-MM-dd', // 使用valueFormat指定绑定值的格式。yyyy-MM-dd HH:mm:ss
startPlaceholder: '时间日期开始范围自定义',
endPlaceholder: '时间日期结束范围自定义',
pickerOptions: {
disabledDate(time) {
//配置什么时间不能被选中
return time.getTime() < Date.now(); //当前日期之前的日期不能被选
},
},
},
{
label: "备注",
prop: "remark",
type: "textarea",
rows: 5,
overHidden: true, // 溢出隐藏
minRows: 3, // 最大行数
maxRows: 5 // 最小行数
},
]
},
data: [],
};
},
watch: {
xx: {
handler(val, oldVal) {//回调函数。即监听到变化时应该执行的函数
this.nextTick(() => {
//当数据到来的时候, DOM 更新循环结束之后,立即执行函数
})
},
deep: true, //深度监听
immediate: true //确认是否以当前的初始值执行handler的函数
},
data: {
handler() {
// watch中使用this.$refs.tableRef.doLayout(, 要放在this.$nextTick中才会有作用
// 因为数据从无到有,dom也一样从无到有,所以要等待render之后才能获取到啊
this.$nextTick(() => {
this.$refs.crud.doLayout() // 初始化表格,防止表格错位
})
},
deep: true,
}
},
// 解决AVue表格错位问题
activated () {
this.$nextTick(() => {
this.$refs.crud.doLayout()
})
},
computed: {
...mapGetters(["permission"]),
// 按钮可以后端控制
permissionList() {
return {
addBtn: this.vaildData(this.permission.post_add, false),
viewBtn: this.vaildData(this.permission.post_view, false),
delBtn: this.vaildData(this.permission.post_delete, false),
editBtn: this.vaildData(this.permission.post_edit, false)
};
},
ids() {
let ids = [];
this.selectionList.forEach(ele => {
ids.push(ele.id);
});
return ids.join(",");
}
},
methods: {
// 时间格式化
formatDate(originVal) {
const dt = new Date(originVal);
const y = dt.getFullYear();
const m = (dt.getMonth() + 1 + "").padStart(2, "0");
const d = (dt.getDate() + "").padStart(2, "0");
const hh = (dt.getHours() + "").padStart(2, "0");
const mm = (dt.getMinutes() + "").padStart(2, "0");
const ss = (dt.getSeconds() + "").padStart(2, "0");
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
},
// 更新数据
async getProtocolSeletItem(a, b) {
let obj = {
"classifyId": a,
"supplierId": b
}
const { data } = await getProtocolList(obj)
let list = data.data
// 方法一: 当字典数据需要前端转换时 获取请假人id 通过接口 添加字典数据
personnel(we).then((res) => {
this.option.column.forEach((item) => {
if (item.prop == "userId") {
item.dicData = res.data.data.records;
}
});
})
// 方法二:column的参数值
const column = this.findObject(this.option.column, "parentId");
column.disabled = true;//设置为禁用此字段
column.value = '1'; //设置parentId字段的value值
column.dicData = res.data.data; // 给数据赋值
console.log("column属性:", column);
setTimeout(() => {
// 方法三:
const form = this.$refs.crud.$refs.dialogForm.$refs.tableForm; // 找到最深一级的参数
form.updateDic('protocolId', list); // 更新column的数据
}, 10);
},
//获取输入框弹出下拉列表数据
querySearchAsync(queryString, cb) {
let param = {
productName: queryString,
};
getListProductAll(param).then(res => {
let data = res.data.data.records;
if (data && data.length > 0) {
let reuslts = data.map(item => {
return {
value: item.productName,
...item
};
});
cb(reuslts);
}
var showSuggestion = document.getElementsByClassName("search-autocpmplete")[0]
if (data.length > 0) {
showSuggestion.style.display = 'block';
} else {
showSuggestion.style.display = 'none';
}
})
.catch(error => {
});
},
// 导入数据相关
handleImport() {
this.excelBox = true
this.excelForm.excelFile = []
},
uploadAfter(res, done, loading, column) {
window.console.log(column)
this.excelBox = false
this.excelForm.excelFile = []
this.refreshChange()
done()
},
// 导出
handleExport() {
const account = func.toStr(this.search.account);
const realName = func.toStr(this.search.realName);
this.$confirm("是否导出用户数据?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
NProgress.start();
exportBlob(`/api/blade-user/export-user?${this.website.tokenHeader}=${getToken()}&account=${account}&realName=${realName}`).then(res => {
downloadXls(res.data, `用户数据表${dateNow()}.xlsx`);
NProgress.done();
})
});
},
// 新增
rowSave(row, done, loading) {
add(row).then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
done();
}, error => {
window.console.log(error);
loading();
});
},
// 编辑
rowUpdate(row, index, done, loading) {
update(row).then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
done();
}, error => {
window.console.log(error);
loading();
});
},
// 删除
rowDel(row) {
this.$confirm("确定删除本条数据么?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(row.id);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
});
},
// 新增/查看/编辑之前的操作
beforeOpen(done, type) {
this.dialogType = type;
console.log('this.dialogType', this.dialogType)
if (["edit", "view", 'add'].includes(type)) {
getDetail(this.form.id).then(async res => {
this.form = res.data.data;
if (type === "view") {
const res = await this.getProtocolSeletItem(this.form.classifyId, this.form.supplierId)
setTimeout(() => {
const form = this.$refs.crud.$refs.dialogForm.$refs.tableForm;
form.updateDic('protocolId', res.data.data); // 改变数据
}, 10);
}
});
}
done();
},
// 清空搜索回调方法
searchReset() {
this.query = {};
this.onLoad(this.page);
},
// 点击搜索后触发该事件(由于page分页信息和search搜索信息是sync修饰符,可以直接通过this.page和this.search拿到)
searchChange(params, done) {
this.query = params;
this.page.currentPage = 1;
this.onLoad(this.page, params);
done();
},
// 点击刷新按钮触发该事件(由于page分页信息和search搜索信息是sync修饰符,可以直接通过this.page和this.search拿到)
refreshChange() {
this.onLoad(this.page, this.query);
},
// 点击页码会调用current-change方法回调当前页数,返回当前第几页
currentChange(currentPage) {
this.page.currentPage = currentPage;
},
// 点击每页多少条会调size-change方法回调
sizeChange(pageSize) {
this.page.pageSize = pageSize;
},
// 请求数据
onLoad(page, params = {}) {
this.loading = true;
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
const data = res.data.data;
this.page.total = data.total;
this.data = data.records;
this.loading = false;
});
}
}
};
</script>