Commit 385aef76 authored by 毛线's avatar 毛线

构建版本

parents
/* Automatically generated by './build/bin/build-entry.js' */
import CyTable from './packages/table/index.js';
import CyLayout from './packages/layout/index.js';
import CyUpload from './packages/form/upload/index.js';
const components = [
CyTable,
CyLayout,
CyUpload,
];
const install = function(Vue, opts = {}) {
components.forEach(component => {
Vue.component(component.name, component);
});
};
/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
version: '1.0.0',
install,
};
{
"name": "cy-admin-ui",
"version": "1.0.0",
"description": "菜芽软件管理端公共组件库",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@cy-dev.com:webpack/cy-admin-ui.git"
},
"keywords": [
"菜芽软件公共组件库"
],
"author": "毛线",
"license": "ISC"
}
import Upload from './src/upload-img-list';
/* istanbul ignore next */
Upload.install = function(Vue) {
Vue.component(Upload.name, Upload);
};
export default Upload;
<template>
<div>
文件上传
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {
},
}
</script>
<template>
<div class="upload-imags-list">
<div v-for="(item, index) in list" :key="index" class="avatar-uploader img">
<div class="img-box" >
<i v-if="edit" class="el-icon-close delete-icon" title="删除" @click.stop="list.splice(index, 1)"/>
<UploadImg
v-model="list[index]"
:multiple="false"
:show-del="false"
:tips="tips"
:source="source"
:size="size"
class="uploadImg"/>
</div>
</div>
<div v-if="list.length < limit && edit" class="avatar-uploader" >
<UploadImg
ref="upload"
:label="label"
:multiple="true"
:show="false"
:tips="tips"
:source="source"
:size="size"
class="uploadImg"
@on-success="(e) => handler().upload(e)"/>
</div>
</div>
</template>
<script>
import UploadImg from './upload-img'
export default{
name: 'CyUpload',
components: {
UploadImg,
},
props: {
label: {
type: String,
default: '上传',
},
limit: { // 图片上传数量限制,默认10
type: Number,
default: 1,
},
value: {
type: null,
default: null,
},
edit: { // 是否可编辑
type: Boolean,
default: true,
},
// 是否使用图片库组件
dialog: {
type: Boolean,
default: true,
},
// 图片列表数据结构,json,array,string
dataType: {
type: String,
default: 'string',
},
tips: {
type: String,
default: '',
},
source: { // 上传服务器
type: String,
default: 'local', // local:本站点,qiniu:七牛云,oss:阿里云,tencent:腾讯云
},
// 组件大小
size: {
type: Number,
default: 100,
},
},
data() {
return {
dialog_visible: false,
qiniuToken: '',
list: [], // 文件列表
index: '',
}
},
watch: {
value(value) {
this.list = this.init().data(value)
},
list(value) {
const data = this.init().value(value)
this.$emit('input', data)
},
},
created() {
this.list = this.init().data(this.value)
},
methods: {
init() {
return {
// 初始化返回数据
value: (list) => {
let value = ''
const { dataType } = this
switch(dataType) {
case 'string': // 字符串类型以逗号隔开
value = list.join(',')
break
case 'json':
value = JSON.stringify(list)
break
case 'array':
value = list
break
}
return value
},
// 初始化数据
data: (value) => {
let data = ''
const { dataType } = this
switch(dataType) {
case 'string': // 字符串类型以逗号隔开
data = value ? value.split(',') : []
break
case 'json':
data = value ? JSON.parse(value) : []
break
case 'array':
data = value
break
}
data = Array.isArray(data) ? data : []
return data
},
}
},
handler() {
return {
upload: (key) => {
this.list.push(key)
},
choiceImg: (index) => {
if (!this.edit) {
return
}
this.index = index
this.$refs.uploadImg.show()
},
confirm: (data) => {
const { index, limit } = this
let { list } = this
if (index === '') {
list = list.concat(data)
} else {
list.splice(index, 1, data)
}
this.list = list.slice(0, limit)
const value = this.init().value(this.list)
this.$emit('input', value)
},
}
},
},
}
</script>
<style lang="scss" scoped>
.upload-imags-list{
font-size: 0;
.avatar-uploader{
display: block;
display: inline-block;
margin-right: 5px;
margin-bottom: 5px;
float: left;
.img-box{
width: 100%;
height: 100%;
box-sizing: border-box;
border-radius: 4px;
position: relative;
.delete-icon{
position: absolute;
top: 0;
right: 0;
font-size: 16px;
background: red;
color: white;
border-radius: 4px;
z-index: 100;
cursor: pointer;
}
.img{
background-position: center;
background-size: contain;
background-repeat: no-repeat;
width: 100%;
height: 100%;
}
}
.avatar-uploader-icon{
box-sizing: border-box;
}
}
}
</style>
<template>
<div>
<el-upload :show-file-list="false" :on-success="(file) => handler().imageSuccess(file)" :action="uploadDomain" :data="{ token: qiniuToken, 'X-Access-Token': token }" :before-upload="init().beforeUpload" :multiple="multiple" :headers="headers" class="avatar-uploader" >
<div v-if="data && show" :style="style" class="avatar">
<i v-if="showDel" class="el-icon-close delete-icon" title="删除" @click.stop="handler().del()"/>
<div :style="`background-image:url(${src})`" class="img"/>
</div>
<i v-else :style="style" class="avatar el-icon-plus avatar-uploader-icon">
<span class="upload-label">{{ label }}</span>
</i>
</el-upload>
<span class="upload-tips">{{ tips }}</span>
</div>
</template>
<script>
import dayjs from 'dayjs'
import { mapState } from 'vuex'
import { getToken } from '@/utils/auth' // 验权
export default{
props: {
label: {
type: String,
default: '上传',
},
value: {
type: String,
default: '',
},
// 是否多选
multiple: {
type: Boolean,
default: false,
},
// 组件大小(px)
size: {
type: [String, Number],
default: 100,
},
// 图片大小限制(kb)
sizeLimit: {
type: Number,
default: 3000,
},
showDel: {
type: Boolean,
default: true,
},
// 上传图片后是否显示图
show: {
type: Boolean,
default: true,
},
tips: {
type: String,
default: '',
},
source: { // 上传服务器
type: String,
default: 'local', // local:本站点,qiniu:七牛云,oss:阿里云,tencent:腾讯云
},
},
data() {
return {
data: '',
qiniuToken: '',
imgDomain: '',
headers: {
Authorization: "Bearer " + getToken(),
},
}
},
computed: {
...mapState({
ossConfig: state => state.ossConfig,
appConfig: state => state.appConfig,
}),
uploadDomain() {
const { source } = this
let uploadDomain = ''
switch(source) {
case 'qiniu': // 七牛云
break
case 'oss': // 阿里云
break
case 'tencent': // 腾讯云
break
default: // 默认,本地上传接口
uploadDomain = process.env.VUE_APP_BASE_API + "/file/upload" // 上传的图片服务器地址
break
}
return uploadDomain
},
src() {
const { data, imgDomain } = this
const reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/
if (reg.test(data)) {
return data
}
return data ? imgDomain + data : ''
},
style() {
const style = {
height: `${this.size}px`,
width: `${this.size}px`,
lineHeight: `${this.size}px`,
}
return style
},
avatarStyle() {
const style = {
lineHeight: `${this.size}px`,
}
return style
},
OssClient() {
const { access_key, bucket, region_id, secret } = this.ossConfig
if (!access_key) {
return ''
}
const client = new OSS({
region: region_id,
// 阿里云账号AccessKey拥有所有API的访问权限,建议遵循阿里云安全最佳实践,创建并使用STS方式访问API。
accessKeyId: access_key,
accessKeySecret: secret,
// stsToken: '<Your securityToken(STS)>',
bucket,
})
return client
},
// 大小转换
sizeText() {
const { sizeLimit } = this
const text = sizeLimit > 1000 ? (sizeLimit / (1024)).toFixed(2) + 'm' : sizeLimit + 'kb'
return text
},
},
watch: {
value() {
this.data = this.value
},
data() {
this.$emit('input', this.data)
this.$emit('on-success', this.data)
},
},
created() {
this.data = this.value
this.init().token()
},
methods: {
init() {
return {
// 上传前置操作
beforeUpload: async(file) => {
const { sizeText, sizeLimit, } = this
if (file.size > (sizeLimit * 1000)) {
this.$alert(`图片大小不能超过${sizeText}`)
return
}
if (this.uploadDomain) {
return true
}
const { name } = file
let path = `${dayjs().format('YYYY/MM/DD')}/${dayjs().format('YYYYMMDDHHmmss')}${Math.ceil(Math.random() * 1000000 % 1000000)}`
console.log('path', path)
path = path.replace('(', '')
path = path.replace(')', '')
path = path.replace(' ', '')
this.putObject(path, file)
// try {
// // 获取七牛云token
// const res = await this.$request.post('/admin/getQiniuToken')
// this.qiniuToken = res.data.token
// return res.data.token
// } catch (err) {
// this.$message('请求出错')
// return false
// }
},
token: () => {
const { source } = this
let token = ''
switch (source) {
case 'local': // 本地点上传
token = getToken()
this.token = token
break
}
},
}
},
handler() {
return {
// 图片上传成功回调
imageSuccess: ({ data }) => {
const { url } = data
this.data = url
},
del: () => {
this.data = ''
this.$emit('delete')
},
}
},
/**
* key 文件吗
* data 文件
*/
async putObject(key, data) {
try {
console.log('file', data)
console.log('OssClient', this.OssClient)
const { OssClient } = this
// object-key可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当前Bucket或Bucket下的指定目录。
const result = await OssClient.put(key, data)
const { name } = result
this.data = name
this.$emit('on-confirm', this.data)
} catch (e) {
console.log('error', e)
}
}
},
}
</script>
<style lang="scss" scoped>
.avatar-uploader{
display: block;
margin-bottom: 2px;
margin-right: 2px;
position: relative;
line-height: 0;
.avatar-uploader-icon{
width: 100%;
height: 100%;
font-size: 16px;
}
.avatar{
width: 100%;
height: 100%;
border: 1px solid rgb(241, 241, 241);
box-sizing: border-box;
&.avatar-uploader-icon{
}
.delete-icon{
position: absolute;
top: 0;
right: 0;
font-size: 16px;
background: red;
color: white;
border-radius: 4px;
cursor: pointer;
}
.img{
background-position: center;
background-size: contain;
background-repeat: no-repeat;
width: 100%;
height: 100%;
}
.upload-label{
font-size: 14px;
}
.upload-tips{
display: block;
font-size: 12px;
}
}
}
</style>
import Layout from './src/layout';
/* istanbul ignore next */
Layout.install = function(Vue) {
Vue.component(Layout.name, Layout);
};
export default Layout;
<template>
<div class="drag" @mousedown="(event) => move(event)"/>
</template>
<script>
export default {
props: {
lockX: { // 锁定横向拖动
type: Boolean,
default: false,
},
lockY: { // 锁定纵向拖动
type: Boolean,
default: false,
},
minX: {
type: Number,
default: 0,
},
minY: {
type: Number,
default: 0,
},
},
data() {
return {}
},
directives: {
// 指令名称
darg: { // 拖拽
inserted(el, binding, vnode) {
// 指令中第一个参数是当前使用指令的DOM
console.log(el);
console.log(arguments);
// 对DOM进行操作
// el.style.width = '200px';
// el.style.height = '200px';
// el.style.background = '#000';
let odiv = el; //获取当前元素
odiv.onmousedown = (e) => {
//算出鼠标相对元素的位置
let disX = e.clientX - odiv.offsetLeft;
let disY = e.clientY - odiv.offsetTop;
document.onmousemove = (e)=>{
//用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
let left = e.clientX - disX;
let top = e.clientY - disY;
//绑定元素位置到positionX和positionY上面
this.positionX = top;
this.positionY = left;
//移动当前元素
odiv.style.left = left + 'px';
// odiv.style.top = top + 'px';
};
document.onmouseup = (e) => {
document.onmousemove = null;
document.onmouseup = null;
}
};
}
}
},
methods: {
move(event, data) {
const { minX, minY } = this
const odiv = event.target // 获取目标元素
// 算出鼠标相对元素的位置
const disX = event.clientX - odiv.offsetLeft;
const disY = event.clientY - odiv.offsetTop;
let left = ''
let top = ''
document.onmousemove = (e) => { // 鼠标按下并移动的事件
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
left = e.clientX - disX
top = e.clientY - disY
// 绑定元素位置到/>和positionY上面
if (left < minX) {
left = minX
}
if (top < minY) {
top = minY
}
// if (left * 1 + this.data.w * 1 >= this.boxWidth * 1) {
// left = this.boxWidth * 1 * 1 - this.data.w * 1
// }
// if (top * 1 + this.data.h * 1 >= this.boxHeight * 1) {
// top = this.boxHeight * 1 - this.data.h * 1
// }
// data.x = left
// data.y = top
// 移动当前元素
!this.lockX && (odiv.style.left = `${left}px`)
!this.lockY && (odiv.style.top = `${top}px`)
};
document.onmouseup = (e) => {
document.onmousemove = null;
document.onmouseup = null;
if (left !== '' && top !== '') {
this.$emit('on-drag', { x: left, y: top })
}
// document.onmousedown = null;
};
},
},
}
</script>
<style lang="scss" scoped>
.drag{
}
</style>
<template>
<el-row :gutter="10" class="mb8">
<el-col v-for="(item, index) in buttonGroup" :key="index" :span="1.5">
<slot v-if="item.type == 'slot'" :name="item.slotName" :data="item" :index="index"/>
<el-button
v-else
:type="item.attr.type"
:plain="item.attr.plain"
:icon="item.attr.icon"
:size="size"
:disabled="init().disabled(item)"
@click="handler().clickButton(item)"
v-hasPermi="item.hasPermi"
>{{ item.label }}</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="$emit('on-search')"></right-toolbar>
</el-row>
</template>
<script>
export default {
props: {
props: {
type: Array,
default: () => {
return []
},
},
// 选中的数据
selection: {
type: Array,
default: () => {
return []
},
},
},
watch: {
showSearch() {
this.$emit('on-show-search', this.showSearch)
},
},
computed: {
buttonGroup() {
const buttonGroup = this.props.length ? this.props : this.init().getDefaultButtonGroup()
this.init().buttonGroup(buttonGroup)
return buttonGroup
},
},
data() {
return {
size: 'mini',
showSearch: true,
}
},
methods: {
init() {
return {
// button: ({ type = 'btn', label = '', hasPermi = [''], attr = '' }) => {
// return {
// }
// },
// 初始化按钮组
buttonGroup: (buttonGroup) => {
buttonGroup.forEach(button => {
this.init().button(button)
})
},
// 初始化默认按钮相关参数
button: (button) => {
const { type } = button
let attr = {}
switch(type) {
case 'add': // 添加按钮
button.label = button.label ?? '新增'
button.hasPermi = button.hasPermi ?? ['']
button.click = button.click ?? (() => {
this.$emit('on-create')
})
attr = button.attr ?? {}
attr.type = attr.type ?? 'primary'
attr.plain = attr.plain ?? true
attr.icon = attr.icon ?? 'el-icon-plus'
button.attr = { ...attr }
break
case 'edit': // 编辑按钮
button.label = button.label ?? '修改'
button.hasPermi = button.hasPermi ?? ['']
button.disabledFlag = 'single'
button.click = button.click ?? (() => {
this.$emit('on-update')
})
attr = button.attr ?? {}
attr.type = attr.type ?? 'success'
attr.plain = attr.plain ?? true
attr.icon = attr.icon ?? 'el-icon-edit'
button.attr = { ...attr }
break
case 'delete': // 删除按钮
button.label = button.label ?? '删除'
button.hasPermi = button.hasPermi ?? ['']
button.disabledFlag = 'multiple'
button.click = button.click ?? (() => {
this.$emit('on-delete')
})
attr = button.attr ?? {}
attr.type = attr.type ?? 'danger'
attr.plain = attr.plain ?? true
attr.icon = attr.icon ?? 'el-icon-delete'
button.attr = { ...attr }
break
case 'export': // 导出按钮
button.label = button.label ?? '导出'
button.hasPermi = button.hasPermi ?? ['']
button.click = button.click ?? (() => {
this.$emit('on-export')
})
attr = button.attr ?? {}
attr.type = attr.type ?? 'warning'
attr.plain = attr.plain ?? true
attr.icon = attr.icon ?? 'el-icon-download'
button.attr = { ...attr }
break
default:
button.type = button.type ?? ''
button.label = button.label ?? ''
button.hasPermi = button.hasPermi ?? ['']
attr = button.attr ?? {}
attr.type = attr.type ?? 'primary'
attr.plain = attr.plain ?? true
attr.icon = attr.icon ?? ''
button.attr = { ...attr }
break
}
return button
},
// 默认显示的按钮类型
getDefaultButtonGroup: () => {
const buttonGroup = [
{
type: 'add',
},
{
type: 'edit',
},
{
type: 'delete',
},
{
type: 'export',
},
]
return buttonGroup
},
disabled: (button) => {
const { disabledFlag } = button
let disabled = false
switch(disabledFlag) {
case 'single':
disabled = this.selection.length !== 1
break
case 'multiple':
disabled = !this.selection.length
break
default:
break
}
return disabled
},
}
},
handler() {
return {
clickButton: (item) => {
const { click } = item
if (click) {
click()
}
},
}
}
},
}
</script>
\ No newline at end of file
<template>
<el-dialog :visible.sync="dialogVisible" :title="title" :close-on-click-modal="false" :width="width" append-to-body>
<el-form v-loading="loading" ref="form" :rules="rules" :model="form" :label-width="labelWidth" :label-suffix="formAttr.labelSuffix" >
<el-row :gutter="20">
<el-col :span="span" v-for="(item, index) in fieldList.filter(i => handler().showField(i))" :key="index">
<el-form-item :label="item.label" :prop="item.field">
<el-select
v-if="item.type === 'select'"
v-model="form[item.field]"
class="input"
:placeholder="item.attr.placeholder"
>
<el-option v-for="(option, optionIndex) in item.options" :key="optionIndex" :label="option.label" :value="option.value"/>
</el-select>
<el-radio-group
v-else-if="item.type === 'radio'"
v-model="form[item.field]">
<el-radio v-for="(option, optionIndex) in item.options" :key="optionIndex" :label="option.value">{{ option.label }}</el-radio>
</el-radio-group>
<div v-else-if="handler().uploadType(item)" style="display: inline-block;">
<cy-upload
:ref="form[item.field]"
:type="item.type"
:limit="(item.upload && item.upload.limit) || 1"
:size="(item.upload && item.upload.size) || 100"
:dataType="(item.upload && item.upload.dataType) || 'string'"
v-model="form[item.field]" />
</div>
<el-date-picker
v-else-if="item.type === 'date'"
v-model="form[item.field]"
:placeholder="item.placeholder"
value-format="yyyy-MM-dd"
class="input"
type="date"/>
<slot v-else-if="item.type == 'slot'" :name="item.slotName" :field="item" :form="form" :index="index"/>
<el-input
v-else
v-model="form[item.field]"
class="input"
:type="item.attr.type"
:maxlength="item.attr.maxlength"
:minlength="item.attr.minlength"
:show-word-limit="item.attr.showWordLimit"
:clearable="item.attr.clearable"
:disabled="item.attr.disabled"
:prefix-icon="item.attr.prefixIcon"
:suffix-icon="item.attr.suffixIcon"
:rows="item.attr.rows"
:autosize="item.attr.autosize"
:autocomplete="item.attr.autocomplete"
:readonly="item.attr.readonly"
:step="item.attr.step"
:placeholder="item.attr.placeholder"
@change="item.change"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="dialogVisible = false">返回</el-button>
<el-button :loading="saveLoading" size="small" type="primary" @click="handler().save('form')">保存</el-button>
</div>
</el-dialog>
</template>
<script>
import request from '@/utils/request'
import { getDicts } from '@/api/system/dict/data'
export default {
props: {
primaryKey: {
type: String,
default: 'id',
},
props: { // table相关参数
type: Object,
default: () => {},
},
api: { // 请求
type: Object,
default: () => {},
},
},
data() {
return {
dialogVisible: false, // 控制对话框的显示和隐藏
form: { // 表单数据存储
},
loading: false, // 控制表格的加载状态
saveLoading: false, // 保存状态
}
},
computed: {
title() { // 判断id是否存在来得到title
const { title } = this.props
return this.id ? (this.update.title || title || '编辑') : (this.create.title || title || '添加')
},
// 主键
id() {
const { primaryKey } = this
return this.form[primaryKey]
},
width() {
return this.props.width || '900px'
},
labelWidth() {
const { fieldList, formAttr, } = this
let maxLabelLength = 0
if (!fieldList) {
return 0
}
fieldList.forEach(item => {
const labelLength = formAttr.labelSuffix?.length || 0 + item.label.length
maxLabelLength = maxLabelLength > labelLength ? maxLabelLength : labelLength
})
let width = maxLabelLength * 16
width = width < 90 ? 90 : width
width = width > 280 / this.columns ? '' : width
const labelWidth = this.props.labelWidth || width + 'px'
return labelWidth
},
columns() {
return this.props.columns || 1
},
span() {
return 24 / this.columns // 默认一列
},
rules() {
const rules = {}
const { fieldList } = this
if (!fieldList) {
return []
}
fieldList.forEach(item => {
const { field, rule } = item
if (rule) {
rule.forEach(item => {
const validator = item.validator
if (!validator) {
return
}
item.validator = (rule, value, callback, obj, msg) => {
validator(rule, value, callback, obj, msg, this.form) // 给验证函数多返回一个当前form对象
}
})
}
rule && (rules[field] = rule)
})
return rules
},
fieldList() {
const { fieldList } = this.props
return fieldList
},
detail() {
let { detail: apiData, base } = this.api
apiData = apiData ?? {
api: `${base}/detail`,
method: 'get',
}
apiData.method = apiData.method || 'get'
return apiData
},
create() {
let { create: apiData, base } = this.api
apiData = apiData ?? {
api: `${base}/add`,
method: 'post',
}
apiData.method = apiData.method || 'post'
return apiData
},
update() {
let { update: apiData, base } = this.api
apiData = apiData ?? {
api: `${base}/edit`,
method: 'post',
}
apiData.method = apiData.method || 'post'
return apiData
},
formAttr() {
return this.props.form || {}
},
},
created() {
this.init().form({})
},
methods: {
show({ form }) { // 组件之间传递参数的函数
const { primaryKey } = this
this.init().form(form)
this.dialogVisible = true // 打开dialog对话框
if (form[primaryKey]) {
this.network().getData() // 刷新数据
}
},
init() {
return {
// 初始化表单数据
form: (data) => {
const { fieldList } = this
let form = {}
if (!fieldList) {
return
}
fieldList.forEach(item => {
const { field, type, } = item
let { value, placeholder, attr, dict, } = item
attr = attr || {}
if (!placeholder) {
switch (type) {
case 'select': case 'radio':
if (dict) {
const options = []
getDicts(dict).then(({ data }) => {
data.forEach(dict => {
const option = {
label: dict.dictLabel,
value: dict.dictCode,
}
options.push(option)
})
item.options = options
})
}
case 'date':
placeholder = '请选择...'
break
default:
attr.type = attr.type || 'text'
placeholder = '请输入...'
break
}
}
value = value || ''
attr.placeholder = placeholder
item.attr = attr
item.change = item.change || (() => {})
form[field] = value
})
// 如果配置参数设置了编辑时候清空某个表单字段,则将字段的值清空
Object.keys(data).forEach(key => {
const field = fieldList.filter(i => i.field == key)[0]
if (field) {
const { clear, } = field
if (clear === true) {
data[key] = ''
}
}
})
if (data) {
form = {
...form,
...data,
}
}
this.form = form
this.$nextTick(() => {
// 清除表单验证
this.$refs['form']?.clearValidate()
})
},
}
},
network() {
return {
// 获取表单数据
getData: () => {
const { detail, primaryKey, id, } = this
const { api, method } = detail
if (!api) {
return
}
const callback = ({ data }) => {
// 请求成功并返回数据
this.loading = false // 关闭表单加载状态
if (this.id) { // id存在 把数据存储到当前页面
const { form } = data
this.form = form
}
}
const params = {
}
params[primaryKey] = id
this.loading = true // 打开表单加载状态
switch(typeof api) {
case 'function':
this.loading = true
api(params).then((response) => callback(response, this))
break
case 'string':
switch(method) {
case 'get':
request({
url: api,
params,
method: 'get',
}).then((response) => callback(response, this))
break
case 'post':
request({
url: api,
data: params,
method: 'post',
}).then((response) => callback(response, this))
break
}
break
}
},
// 提交保存
save: ({ callback, api, params, method }) => {
const { form } = this
params = {
...params,
...form,
}
this.$refs['form'].validate((valid) => { // 进行提交表单的验证
if (valid) { // 如果表单存在
this.saveLoading = true // 打开表单加载状态
const apiCallback = (response) => {
// 请求成功并返回数据
const { msg, } = response
this.saveLoading = false // 关闭表单加载状态
this.$emit('reload') // 触发父组件中的自定义函数
this.$modal.msgSuccess(msg)
this.dialogVisible = false // 关闭Dialog 对话框
callback && callback(response)
}
switch(typeof api) {
case 'function':
this.saveLoading = true
api(params).then((response) => apiCallback(response, this))
break
case 'string':
switch(method) {
case 'get':
request({
url: api,
params,
method: 'get',
}).then((response) => apiCallback(response, this))
break
case 'post':
request({
url: api,
data: params,
method: 'post',
}).then((response) => apiCallback(response, this))
break
}
break
}
} else {
return false // 表单不存在,终止运行
}
})
},
}
},
handler() {
return {
// 新增或者修改按钮
save: (formName) => {
this.$refs[formName].validate((valid) => { // 进行提交表单的验证
if (valid) { // 如果表单存在
const { create, update } = this
let apiData = {}
if (this.id) {
apiData = update
} else {
apiData = create
}
this.network().save(apiData)
} else {
return false // 表单不存在,终止运行
}
})
},
showField: (field) => {
const { show } = field
if (show === undefined) {
return true
}
if (typeof show == 'function') {
return show(this.form)
} else {
return show
}
},
// 上传组件类型
uploadType: (item) => {
return ['image', 'file', 'video', 'audio'].includes(item.type)
},
}
},
}
}
</script>
<style lang="scss" scoped>
.input{
width: 100%;
}
</style>
<template>
<el-form :model="params" ref="queryForm" :inline="true" v-show="props.showSearch !== false" label-suffix=":">
<el-form-item v-for="(item, index) in formItem" :key="index" :label="item.label" :prop="item.field">
<slot v-if="item.type == 'slot'" :name="item.slotName" :data="item" :index="index"/>
<el-select
v-else-if="item.type == 'select'"
v-model="params[item.field]"
:placeholder="item.placeholder === null ? '请输入...' : item.placeholder "
:multiple="item.multiple"
clearable
@change="item.change"
@keyup.enter.native="() => handler().query()"
>
<el-option v-for="(item, index) in item.options" :key="index" :value="item.value" :label="item.label" />
</el-select>
<el-input
v-else
v-model="params[item.field]"
:placeholder="item.placeholder === null ? '请输入...' : item.placeholder "
clearable
@change="item.change"
@keyup.enter.native="() => handler().query()"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="() => handler().query()">搜索</el-button>
<el-button icon="el-icon-refresh" @click="() => handler().reset()">重置</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { getDicts } from '@/api/system/dict/data'
export default {
props: {
props: {
type: Object,
default: () => {
return {}
},
},
},
dicts: [],
data() {
return {
params: {},
}
},
watch: {
props() {
this.init().params(this.props)
},
},
computed: {
formItem() {
const { formItem } = this.props
formItem.forEach(item => {
item.change = item.change || (() => {})
})
return formItem
},
},
created() {
this.init().params(this.props)
},
methods: {
init() {
return {
// 初始化参数
params: (props) => {
const params = {}
const { formItem } = props
formItem.forEach(item => {
const { field, value, } = item
params[field] = value
if (item.dict) {
const options = []
getDicts(item.dict).then(({ data }) => {
data.forEach(dict => {
const option = {
label: dict.dictLabel,
value: dict.dictCode,
}
options.push(option)
})
item.options = options
})
}
})
this.params = params
},
}
},
handler() {
return {
// 搜索
query: () => {
this.$emit('on-query', this.params)
},
// 重置
reset: () => {
this.resetForm('form')
this.$emit('on-query', this.params)
},
}
},
},
}
</script>
\ No newline at end of file
<template>
<cy-table v-loading="loading" :row-key="primaryKey" :list="data" :columns="columns" :height="height" @selectRow="(selection) => handler().selectionChange(selection)">
<template v-for="(column, index) in columns.filter(i => i.type == 'slot')" #[column.slotName]="{ data, $index }">
<slot :name="column.slotName" :data="data" :index="$index"/>
</template>
</cy-table>
</template>
<script>
import request from '@/utils/request'
export default {
props: {
primaryKey: {
type: String,
default: 'id',
},
listApi: {
type: null,
default: null,
},
props: {
type: Object,
default: () => {
return {
}
}
},
params: {
type: Object,
default: () => {
return {
}
}
},
},
computed: {
columns() {
return this.props.columns
},
height() {
return this.props.height ?? '100%'
},
},
data() {
return {
loading: false,
data: [],
total: 0,
}
},
created() {
this.network().getData()
},
methods: {
network() {
return {
getData: () => {
const { params, props, listApi } = this
let { api, method, callback, } = listApi
method = method ? method : 'post'
if (!callback) {
callback = (response) => {
this.data = response.rows
this.total = response.total
this.$set(this.props, 'total', response.total)
// this.loading = false
this.$nextTick(() => {
this.loading = false
})
}
}
switch(typeof api) {
case 'function':
this.loading = true
api(params).then((response) => callback(response, this))
break
case 'string':
switch(method) {
case 'get':
request({
url: api,
params,
method: 'get',
}).then((response) => callback(response, this))
break
case 'post':
request({
url: api,
data: params,
method: 'post',
}).then((response) => callback(response, this))
break
}
break
}
},
}
},
handler() {
return {
selectionChange: (selection) => {
this.$emit('selectRow', selection)
},
}
},
},
}
</script>
<template>
<div :style="{ padding }" class="app-main">
<el-card
:body-style="bodyStyle"
class="app-layout"
shadow="never">
<div v-if="$slots.header || queryForm" class="header">
<template v-if="queryForm">
<!-- 查询条件相关组件 -->
<LqQueryForm v-if="showSearch" ref="queryForm" :props="queryForm" @on-query="(params) => getTableData(params)">
<template v-for="item in queryForm.formItem.filter(i => i.type == 'slot')" #[item.slotName]="{ data, $index }">
<slot :name="item.slotName" :data="data" :index="$index"/>
</template>
</LqQueryForm>
<!-- 操作按钮相关组件 -->
<LqButtonGroup
ref="buttonGroup"
:props="buttonGroup"
:selection="selection"
@on-show-search="(e) => {showSearch = e}"
@on-search="getTableData"
@on-create="$refs.form.show({ form: {} })"
@on-update="$refs.form.show({ form: selection[0] })"
@on-delete="handler().remove()"
@on-export="handler().export()">
<template v-for="item in buttonGroup.filter(i => i.type == 'slot')" #[item.slotName]="{ data, $index }">
<slot :name="item.slotName" :data="data" :index="$index"/>
</template>
</LqButtonGroup>
</template>
<slot v-else name="header"/>
</div>
<div ref="content" class="content">
<!-- 左侧区域 -->
<div v-if="$slots.left" class="left" :style="{ width: showLeftWidth }">
<!-- 自定义内容插槽 -->
<slot name="left"/>
</div>
<Drag v-if="$slots.left" class="darg" :min-x="200" lock-y @on-drag="(e) => handler().onDrag(e)"></Drag>
<!-- 内容区域 -->
<div class="content">
<!-- 自定义table组件 -->
<LqLayoutTable ref="table" v-if="table.show" :primary-key="primaryKey" :list-api="api.list" :props="table" :params="tableParams" @selectRow="(e) => {$emit('selectRow', e); selection = e}">
<template v-for="column in table.columns.filter(i => i.type == 'slot')" #[column.slotName]="{ data, $index }">
<slot :name="column.slotName" :data="data" :index="$index"/>
</template>
</LqLayoutTable>
<!-- 自定义内容插槽 -->
<slot v-else name="content"/>
</div>
</div>
<div v-if="$slots.footer || table.show" class="footer">
<div class="pagation">
<!-- 分页组件 -->
<pagination
v-if="table.show"
v-show="props.table.total > 0"
:total="props.table.total || 0"
:page.sync="pageParams.pageNum"
:limit.sync="pageParams.pageSize"
@pagination="$refs.table.network().getData()"
/>
<!-- 自定义底部插槽 -->
<slot v-else name="footer"/>
</div>
</div>
</el-card>
<LqForm v-if="formData.fieldList" ref="form" :primary-key="primaryKey" :api="api" :props="formData" @reload="getTableData">
<template v-for="item in formData.fieldList.filter(i => i.type == 'slot')" #[item.slotName]="scope">
<slot :name="item.slotName" :field="scope.field" :form="scope.form" :index="scope.$index"/>
</template>
</LqForm>
</div>
</template>
<script>
import request from '@/utils/request'
import LqLayoutTable from './layout-table'
import LqQueryForm from './layout-query-form'
import LqButtonGroup from './layout-button-group'
import LqForm from './layout-form'
import Drag from './drag.vue'
export default {
name: 'CyLayout',
components: {
Drag,
LqLayoutTable,
LqQueryForm,
LqButtonGroup,
LqForm,
},
props: {
total: {
type: Number,
default: 0,
},
padding: {
type: String,
default: '10px',
},
props: {
type: Object,
default: () => {
return {}
},
// 配置demo
demo: () => {
return {
// curd api配置
api: {
base: '', // 基础api路径,若不配置create、update、detail、list、remove、export,layout组件内的table,form等curd操作基于,会根据base的内容以及后端的curd风格规范,自动使用对应的api进行相关请求
create: { // 新增数据api配置
api: '', // 接口api方法或者api路径
method: '', // 如果api是路径,那么可以指定请求方法,默认是post
params: '', // 附加参数
callback: (res) => {
console.log('自定义回调', res)
},
},
update: { // 编辑数据api配置
api: '', // 接口api方法或者api路径
method: '', // 如果api是路径,那么可以指定请求方法,默认是post
params: '', // 附加参数
callback: (res) => {
console.log('自定义回调', res)
},
},
detail: { // 获取详情api配置,若不希望编辑页面重新请求详情接口可以设置为空对象
api: '', // 接口api方法或者api路径
method: '', // 如果api是路径,那么可以指定请求方法,默认是post
params: '', // 附加参数
callback: (res) => {
console.log('自定义回调', res)
},
},
list: { // 获取列表api配置
api: '', // 接口api方法或者api路径
method: '', // 如果api是路径,那么可以指定请求方法,默认是post
params: '', // 附加参数
callback: (res) => {
console.log('自定义回调', res)
},
},
remove: { // 删除api配置
api: '', // 接口api方法或者api路径
method: '', // 如果api是路径,那么可以指定请求方法,默认是post
params: '', // 附加参数
callback: (res) => {
console.log('自定义回调', res)
},
},
export: { // 导出api配置
api: '', // 接口api方法或者api路径
method: '', // 如果api是路径,那么可以指定请求方法,默认是post
params: '', // 附加参数
callback: (res) => {
console.log('自定义回调', res)
},
},
},
primaryKey: 'id', // 主键
// 默认请求参数参数数据结构
params: {},
// 表格内容相关配置
table: {
// 表格字段,数据结构{label: 表头文案, prop:字段key, type:类型,可选[selection, slot, text],默认为text, slotName:type为slot时需要指定slotName作为插槽的名称, width:列宽, minWidth:最小列宽, showOverflowTooltip:内容超出列宽时是否显示气泡提示, }
columns: [ // table表头和对应字段配置,必填
{
label: '', // 表头文案
prop: '',
type: 'selection', // 类型,可选[selection, slot, text],默认为text
},
{
label: '头像', // 表头文案
prop: 'avatar', // 字段key
type: 'slot', // 插槽类型
slotName: 'tableAvatar', // type为slot时需要指定slotName作为插槽的名称
miniWidth: '200px', // 最小列宽
},
{
label: '员工编号', // 表头文案
prop: 'userName', // 字段key
width: '200px', // 列宽
showOverflowTooltip: true, // 内容超出列宽时是否显示气泡提示
},
],
show: false, // 是否使用内置table,非必填
height: '100%', // 表格高度,非必填,默认会根据窗口高度撑满table
},
// 搜索参数表单配置,数据结构如下
queryForm: {
labelSuffix: ':',
width: '200px',
size: 'small', // 表单大小
showSearch: false, // 是否显示搜索框
formItem: [
{
label: '', // 标题
field: '', // 字段名称
value: '', // 默认值
type: '', // 类型,input,select,cascader,date,datetimerange,slot
slotName: '', // 插槽名称,若tpe为slot,需要设置slotName。
placeholder: '请输入...', // 提示
multiple: false, // type为select时,是否多选
change: null, // on-change回调函数
}
]
},
// 按钮组配置,配置需要显示的按钮组。若不设置或设置为空数组,默认显示添加(add)、编辑(edit)、删除(remove)、导出(export)按钮,
// 若只需要显示某些按钮,就只设置对应按钮的类型
buttonGroup: [
{
type: 'add', // 功能类型,内置类型为add,edit,delete,export,slot这四个类型会赋予默认的attr,和点击回调,若类型为slot,则表示此按钮使用自定义插槽
slotName: '', // 自定义插槽名称,type为slot时必须设置此内容
label: '新增', // 按钮文字
disabledFlag: '', // 禁用类型,可选值为multiple、single、空字符串,若为multiple:不选择任何table内容时禁用,若为single:非单选时禁用,若为其他:任何情况下不禁用
click: () => {}, // 自定义回调函数,类型为add,edit,delete,export,这四个类型有自带的回调函数,若设置此参数,回调函数会被重写
attr: { // 按钮属性,目前可以设置type,plain,icon,内容参考element-ui文档
type: 'primary ',
plain: false,
icon: 'el-icon-plus',
},
},
],
// 表单相关配置
formData: {
title: '用户信息', // 弹窗标题,非必填,若未填写create.title,和update.title,则以此字段为准
width: '900px', // 弹窗宽度,非必填,默认900px
columns: 2, // field按照多少列展示,非必填,默认一行只展示一列
form: { // 表单attr配置
labelSuffix: ':', // 表单label后缀
},
fieldList: [ // 字段相关配置
{
label: '密码', // 字段名称,必填
field: 'password', // 字段名称,必填
type: 'input', // 组件类型,非必填,默认input
value: '', // 默认值,非必填
attr: { // 组件属性,非必填,同element表单组件的属性
type: 'password',
},
clear: false, // 编辑的时候是否清空该字段,非必填,默认false
show: false, // 是否显示,可以传入函数或者布尔值
rule: [ // 校验规则,非必填
{ required: true, message: '请输入密码', trigger: 'blur' },
{ required: true, trigger: 'blur', validator: (rule, value, callback, obj, msg, form) => { // 验证规则会多返回一个form对象
if (!value) {
callback(new Error('请输入密码'))
} else {
callback()
}
}},
],
},
{
label: '图片类型', // 字段名称,必填
field: 'avatar', // 字段名称,必填
type: 'image', // 组件类型,非必填,默认input,上传类型包括['image', 'file', 'video', 'audio'],file,video,audio还在开发中
upload: { // 上传组件参数设置
limit: 1, // 若type为image,limit标识图片上传数量
size: 100, // 组件大小,单位px
dataType: 'string', // 若type为image, dataType设置绑定value的数据类型,可选值为['string', 'json', 'array'],其中string类型为半角逗号隔开多个图片如XXX,XXX,XXX
},
value: '', // 默认值,非必填
},
{
label: '自定义插槽', // 字段名称,必填
field: 'slotDemoField', // 字段名称,必填
type: 'slot', // 自定义插槽类型
slotName: 'formSlotDemo', // type为slot时,必须设置slotName
value: '', // 默认值,非必填
},
],
},
}
},
},
},
data() {
const bodyStyle = {
padding: '20px',
display: 'flex',
height: '100%',
'box-sizing': 'border-box',
'flex-direction': 'column',
}
return {
leftWidth: '300px',
bodyStyle,
pageParams: {
pageNum: 1,
pageSize: 20,
},
selection: [], // 当前选中的数据
showSearch: true, // 是否显示搜索框
params: {},
}
},
computed: {
primaryKey() {
return this.props.primaryKey || 'id'
},
showLeftWidth() {
return this.leftWidth * 1 + 2 + 'px'
},
table() {
return this.props.table ?? {}
},
tableColumns() {
return this.table.columns ?? []
},
tableData() {
return this.table.columns ?? []
},
tableParams() {
const { pageParams, params, props, } = this
const { params: propsParams } = props
return {
...pageParams,
...params,
...propsParams,
}
},
// 搜索参数
queryForm() {
return this.props.queryForm || null
},
// 搜索参数
buttonGroup() {
return this.props.buttonGroup || []
},
formData() {
return this.props.formData || {}
},
api() {
return this.props.api || {}
},
},
watch: {
total() {
this.$nextTick(() => {
this.init().tableSize()
})
},
},
mounted() {
this.init().tableSize()
window.onresize = () => {
this.init().tableSize()
}
},
methods: {
init() {
return {
tableSize: () => {
if (!this.$refs.content) {
return
}
const heightStyle = this.$refs.content.offsetHeight - 20
this.$emit('table-height', heightStyle)
},
}
},
edit({ form }) {
this.$refs.form.show({ form })
},
getTableData(params) {
if (params) {
this.props.params = {
...this.props.params,
...params,
}
}
this.$nextTick(() => {
this.$refs.table.network().getData()
})
},
network() {
return {
remove: (ids) => {
const { primaryKey } = this
this.$refs.table.loading = true
const { remove, base } = this.api
const params = {}
if (remove) {
let { api, method, callback } = remove
method = method ? method : 'post'
if (!callback) {
callback = (response) => {
this.getTableData();
this.$modal.msgSuccess("删除成功");
this.$nextTick(() => {
this.$refs.table.loading = false
})
}
}
switch(typeof api) {
case 'function':
api(ids).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
break
case 'string':
switch(method) {
case 'get':
request({
url: api,
params: ids,
method: 'get',
}).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
break
case 'post':
request({
url: api,
data: ids,
method: 'post',
}).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
break
}
break
}
} else {
params[primaryKey] = ids
request({
api: `${base}/remove`,
params,
}).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
}
},
export: (ids) => {
const { primaryKey } = this
this.$refs.table.loading = true
const { remove, base } = this.api
const params = {}
if (remove) {
const { api } = remove
let { method, callback } = remove
method = method || 'get'
if (!callback) {
callback = (response) => {
this.$refs.table.loading = false
this.$modal.msgSuccess('导出成功');
this.$nextTick(() => {
})
}
}
switch (typeof api) {
case 'function':
api(ids).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
break
case 'string':
switch (method) {
case 'get':
request({
url: api,
params: ids,
method: 'get',
}).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
break
case 'post':
request({
url: api,
data: ids,
method: 'post',
}).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
break
}
break
}
} else {
params[primaryKey] = ids
request({
url: `${base}/export`,
params,
}).then((response) => {
callback(response, this)
}).catch(() => {
this.$refs.table.loading = false
})
}
},
}
},
handler() {
return {
onDrag: (data) => {
const { x, y } = data
this.leftWidth = x
},
selectionChange: (e) => {
this.$emit('selectRow', e)
},
/** 删除按钮操作 */
remove: () => {
const { selection, primaryKey, } = this
const ids = selection.map(i => i[primaryKey])
this.$modal.confirm(`是否确认删除${primaryKey}为"` + ids.join(',') + '"的数据项?').then(() => {
this.network().remove(ids)
})
},
/** 导出按钮操作 */
export: () => {
const { selection, primaryKey, } = this
const ids = selection.map(i => i[primaryKey])
this.network().export(ids)
},
}
},
},
}
</script>
<style lang="scss" scoped>
$border-color: #e6ebf5;
.app-main {
padding: 10px;
background-color: #f1f1f1;
position: absolute;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
max-height: 100%;
padding: 10px;
box-sizing: border-box;
height: 100%;
background-color: rgba(240, 242, 245, 1);
.app-layout{
height: 100%;
display: flex;
flex-direction: column;
background-color: white;
.content{
flex: 1;
overflow: auto;
display: flex;
position: relative;
.left{
width: 300px;
height: 100%;
overflow: auto;
display: flex;
flex-direction: column;
border-right: 1px solid $border-color;
overflow: auto;
}
.darg{
position:absolute;
z-index: 1000;
left: 298px;
height: 100%;
width: 3px;
cursor: e-resize;
user-select: none;
&:hover,&:active{
background-color: $border-color;
}
}
.content{
flex: 1;
padding: 10px;
overflow: auto;
}
}
.footer{
::v-deep .pagination-container{
margin-top: 0;
padding-bottom: 0 !important;
}
}
}
}
</style>
import Table from './src/main';
/* istanbul ignore next */
Table.install = function(Vue) {
Vue.component(Table.name, Table);
};
export default Table;
<template>
<el-table
ref="table"
:data="tableData"
:height="height"
:max-height="maxHeight"
:row-class-name="(row, rowIndex) => handler().rowclass(row, rowIndex)"
:tree-props="{children: 'children'}"
:row-key="rowKey"
default-expand-all
@select="(select, row) => handler().select(select, row)"
@row-click="(row, column, event) => handler().rowClick(row, column, event)"
@selection-change="(value) => handler().selectionChange(value)">
<template v-for="item in tableColumns">
<template v-if="!(item.show === 0 || item.show === false)">
<el-table-column
v-if="!item.header && item.type === 'slot'"
:key="item.key"
:prop="item.prop"
:label="item.label"
:width="item.width ? item.width : ''"
:min-width="item.minWidth ? item.minWidth : ''"
:align="item.align"
:show-overflow-tooltip="(showOverflowTooltip || item['show-overflow-tooltip']) && item['show-overflow-tooltip'] !== false">
<!-- 作用域 -->
<template slot-scope="{ row, $index }">
<slot :name="item.slotName" :data="row" :index="$index"/>
</template>
</el-table-column>
<el-table-column
v-else-if="item.header && item.type === 'slot'"
:key="item.key"
:prop="item.prop"
:label="item.label"
:width="item.width ? item.width : ''"
:min-width="item.minWidth ? item.minWidth : ''"
:align="item.align"
:render-header="(h, {column}) => handler().renderHeader(h,{column},item)"
:show-overflow-tooltip="(showOverflowTooltip || item['show-overflow-tooltip']) && item['show-overflow-tooltip'] !== false">
<!-- 作用域 -->
<template slot-scope="{ row, $index }">
<slot :name="item.slotName" :data="row" :index="$index"/>
</template>
</el-table-column>
<el-table-column
v-else-if="item.type==='selection'"
:key="item.key"
:prop="item.prop"
:width="'55px'"
:label="item.label"
:align="'center'"
type="selection"/>
<el-table-column
v-else
:key="item.key"
:prop="item.prop"
:label="item.label"
:width="item.width"
:align="item.align"
:min-width="item.minWidth ? item.minWidth : ''"
:show-overflow-tooltip="(showOverflowTooltip || item['show-overflow-tooltip']) && item['show-overflow-tooltip'] !== false">
<template slot-scope="{ row }">
<span>{{ row[item.prop] !== '' || row[item.prop] !== null ? row[item.prop] : '/' }}</span>
</template>
</el-table-column>
</template>
</template>
</el-table>
</template>
<script>
export default {
name: 'CyTable',
props: {
rowKey: {
type: String,
default: 'id',
},
data: { // 表头和表格数据
type: Object,
default() {
return {}
},
},
columns: {
type: Array,
default: () => {
return []
},
},
list: {
type: Array,
default: () => {
return []
},
},
height: {
type: null,
default: null,
},
maxHeight: {
type: null,
default: null,
},
showOverflowTooltip: {
type: Boolean,
default: true,
},
},
data() {
return {
init: true,
selectData: [], // 选中的数据
}
},
computed: {
tableColumns() {
return this.columns.length ? this.columns : this.data.columns
},
tableData() {
const tableData = this.list.length ? this.list : this.data.tableList
return tableData
},
tableHeight() {
const height = this.height.replace('px', '')
return height
},
},
watch: {
data(val) {
},
height() {
},
},
mounted() {
},
methods: {
// 设置选中的数据
setSelectRows(rows = []) {
const { rowKey } = this
const ids = rows.map(item => item[rowKey])
const { tableData } = this
if (!tableData) {
return
}
this.init = false
tableData.forEach((row, index) => {
if (ids.includes(row[rowKey])) {
this.$refs.table.toggleRowSelection(row)
}
})
this.init = true
},
handler() {
return {
// 复选框
select: (select, row) => {
if (this.radio) {
this.$refs.table.clearSelection()
this.$nextTick(() => {
this.$refs.table.toggleRowSelection(row)
})
}
},
// 行点击回调
rowClick: (row, column, event) => {
if (this.radio) {
this.$refs.table.clearSelection()
}
this.$refs.table.toggleRowSelection(row)
},
selectionChange: (select) => {
this.selectData = select
if (this.init) {
this.$emit('selectRow', this.selectData)
this.$emit('select-row', this.selectData)
}
},
rowclass: ({ row, rowIndex }) => {
if (row.time) {
return 'deleteFlag'
} else {
return ''
}
},
// 自定义表头--提示
renderHeader: (h, { column }, item) => {
return (
<div>{column.label}
<el-tooltip class='item' effect={'dark'} content={item.text} placement={'top'}>
<i class='el-icon-warning-outline'>
</i>
</el-tooltip>
</div>
)
},
}
}
}
}
</script>
<style lang="scss" scoped>
.el-table th.el-table__cell > .cell{
padding-left: 14px;
padding-right: 14px;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment