This commit is contained in:
Jerry
2020-04-12 09:32:34 +08:00
parent be4a132ddf
commit c2a5f9d394
305 changed files with 33137 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
<template>
<div class="date-range">
<!--<year-range-panel />-->
<el-select v-model="dateType" :size="size" style="max-width: 100px; min-width: 100px; margin-right: 10px;" v-if="!hideTypeOnlyOne || validTypeList.length > 1">
<el-option v-for="type in validTypeList" :key="type.value" :value="type.value" :label="type.label" />
</el-select>
<el-date-picker style="flex-grow: 1;" v-model="currentDates" :size="size" :placeholder="placeholder" :type="innerDateType"
:disabled="disabled" :format="innerDateFormat" :readonly="readonly" :editable="editable"
:clearable="clearable" :start-placeholder="startPlaceholder" :end-placeholder="endPlaceholder"
:align="align" :range-separator="rangeSeparator" :value-format="valueFormat"
:prefix-icon="prefixIcon" :clear-icon="clearIcon" @change="onValueChange"></el-date-picker>
</div>
</template>
<script>
import { formatDate, parseDate } from 'element-ui/src/utils/date-util';
const allTypeList = [{
value: 'day',
label: '自然日'
}, {
value: 'month',
label: '自然月'
}, {
value: 'year',
label: '自然年'
}];
export default {
name: 'DateRange',
props: {
/**
* 绑定的数据
*/
value: {
type: [Array],
default: () => {
return []
}
},
/**
* 默认显示的数据选择方式如果不存在与allowTypes中则显示allowTypes中的第一个
*/
defaultDateType: {
type: String,
default: 'day'
},
/**
* 组件大小medium / small / mini
*/
size: {
type: String
},
/**
* 数据选择方式只有一个的时候是否隐藏数据选择方式下拉
*/
hideTypeOnlyOne: {
type: Boolean,
default: true
},
/**
* 允许的数据选择方式day, month, year
* 默认值['day', 'month', 'year']
*/
allowTypes: {
type: Array,
default: () => {
return allTypeList.map((item) => {
return item.value;
});
}
},
/**
* 是否范围选择
*/
isRange: {
type: Boolean,
default: true
},
/**
* 输出字符串的format
*/
outputFormat: {
type: String,
default: 'yyyy-MM-dd HH:mm:ss'
},
/**
* 非范围选择时的占位内容
*/
placeholder: String,
/**
* 范围选择时开始日期的占位内容
*/
startPlaceholder: String,
/**
* 范围选择时结束日期的占位内容
*/
endPlaceholder: String,
/**
* 完全只读
*/
readonly: Boolean,
/**
* 禁用
*/
disabled: Boolean,
/**
* 文本框可输入
*/
editable: {
type: Boolean,
default: true
},
/**
* 是否显示清除按钮
*/
clearable: {
type: Boolean,
default: true
},
/**
* 对齐方式left, center, right
*/
align: {
type: String,
default: 'left'
},
/**
* 选择范围时的分隔符
*/
rangeSeparator: {
type: String,
default: '-'
},
/**
* 可选,绑定值的格式。不指定则绑定值为 Date 对象
*/
valueFormat: {
type: String,
default: 'yyyy-MM-dd'
},
/**
* 自定义头部图标的类名
*/
prefixIcon: {
type: String,
default: 'el-icon-date'
},
/**
* 自定义清空图标的类名
*/
clearIcon: {
type: String,
default: 'el-icon-circle-close'
}
},
data () {
return {
dateType: this.defaultDateType,
currentDates: undefined
}
},
methods: {
onValueChange (values) {
this.$nextTick(() => {
this.emitChange();
});
},
emitChange () {
let outputDate = [];
if (this.currentDates != null) {
if (!this.isRange) {
outputDate[0] = new Date(this.currentDates);
outputDate[1] = new Date(this.currentDates);
} else {
if (Array.isArray(this.currentDates) && this.currentDates.length === 2) {
outputDate[0] = new Date(this.currentDates[0]);
outputDate[1] = new Date(this.currentDates[1]);
}
}
if (outputDate[0] != null && outputDate[1] != null) {
outputDate[0].setHours(0, 0, 0, 0);
outputDate[1].setHours(0, 0, 0, 0);
switch (this.dateType) {
case 'day':
outputDate[1].setDate(outputDate[1].getDate() + 1);
break;
case 'month':
outputDate[1].setDate(1);
outputDate[0].setDate(1);
outputDate[1].setMonth(outputDate[1].getMonth() + 1);
break;
case 'year':
outputDate[1].setMonth(0);
outputDate[1].setDate(1);
outputDate[0].setMonth(0);
outputDate[0].setDate(1);
outputDate[1].setFullYear(outputDate[1].getFullYear() + 1);
break;
}
outputDate[1] = new Date(outputDate[1].getTime() - 1);
outputDate[0] = formatDate(outputDate[0], this.outputFormat);
outputDate[1] = formatDate(outputDate[1], this.outputFormat);
}
}
this.$emit('input', outputDate);
this.$emit('change', outputDate);
},
getCurrentStatsDateType () {
return this.dateType;
}
},
computed: {
validTypeList () {
return allTypeList.filter((item) => {
return this.allowTypes.indexOf(item.value) !== -1;
});
},
/**
* el-date-picker使用的type
*/
innerDateType () {
switch (this.dateType) {
case 'day': return this.isRange ? 'daterange' : 'date';
case 'month': return this.isRange ? 'monthrange' : 'month';
case 'year': return this.isRange ? 'monthrange' : 'year';
default: return this.isRange ? 'daterange' : 'date';
}
},
/**
* el-date-picker使用的format
*/
innerDateFormat () {
switch (this.dateType) {
case 'day': return 'yyyy-MM-dd';
case 'month': return 'yyyy-MM';
case 'year': return 'yyyy';
default: return 'yyyy-MM-dd';
}
}
},
watch: {
value: {
handler: function (newValue, oldValue) {
if (newValue == null || newValue.length < 2) {
this.currentDates = this.isRange ? [] : undefined;
} else {
if (this.currentDates == null) this.currentDates = [];
if (this.isRange) {
this.currentDates = [
parseDate(newValue[0], this.valueFormat),
parseDate(newValue[1], this.valueFormat)
];
} else {
this.currentDates = parseDate(newValue[0], this.valueFormat);
}
}
},
immediate: true,
deep: true
},
dateType: {
handler: function (newValue, oldValue) {
if (this.allowTypes.indexOf(this.dateType) === -1) {
this.dateType = this.allowTypes[0] || 'day';
}
this.emitChange();
},
immediate: true
},
defaultDateType: {
handler: function (newValue, oldValue) {
if (this.allowTypes.indexOf(newValue) !== -1) {
this.dateType = newValue;
} else {
this.dateType = this.allowTypes[0];
}
}
},
isRange: {
handler: function (newValue, oldValue) {
let temp;
if (newValue) {
temp = [this.currentDates, this.currentDates];
} else {
temp = this.currentDates[0];
}
this.currentDates = temp;
}
}
}
}
</script>
<style scoped>
.date-range {
display: flex;
justify-content: start;
}
</style>

View File

@@ -0,0 +1,77 @@
import $ from 'jquery';
import Vue from 'vue';
import router from '@/router';
import store from '@/store';
window.jQuery = $;
const layer = require('layui-layer');
class Dialog {
/**
* 关闭弹窗
* @param {*} index 要关闭的弹窗的index
*/
static close (index) {
layer.close(index);
}
/**
* 关闭所有弹窗
*/
static closeAll () {
layer.closeAll();
}
/**
* 打开弹窗
* @param {*} title 弹窗标题
* @param {*} component 弹窗内容的组件
* @param {*} options 弹窗设置详情请见layui官网
* @param {*} params 弹窗组件参数
*/
static show (title, component, options, params) {
return new Promise((resolve, reject) => {
let layerOptions = {
title: title,
type: 1,
skin: 'layer-dialog',
resize: false,
offset: 'auto',
zIndex: 1000,
index: 0,
contentDom: null
};
layerOptions = {...layerOptions, ...options};
layerOptions.end = () => {
if (layerOptions.contentDom) document.body.removeChild(layerOptions.contentDom);
}
let observer = {
cancel: function (isSuccess = false) {
layer.close(this.index);
if (isSuccess) {
resolve();
} else {
reject();
}
},
index: -1
}
layerOptions.cancel = () => {
reject();
}
let dom = document.createElement('div');
document.body.appendChild(dom);
let Content = Vue.extend(component);
let vueObj = new Content({router: router, store: store, propsData: params});
vueObj.observer = observer;
vueObj.$mount(dom);
layerOptions.contentDom = vueObj.$el;
layerOptions.content = $(layerOptions.contentDom);
observer.index = layer.open(layerOptions);
});
}
}
Vue.prototype.$dialog = Dialog;
export default Dialog;

View File

@@ -0,0 +1,134 @@
<template>
<el-row class="flex-box" type="flex" :justify="rowJustify">
<slot />
<div v-for="item in tempDomCount" :key="item" :style="{width: tempDomWidth}" />
<el-row type="flex" :justify="operatorPosition" :style="getMenuBoxStyle">
<slot name="operator" />
</el-row>
</el-row>
</template>
<script>
import $ from 'jquery';
export default {
name: 'FilterBox',
props: {
/**
* 每一个过滤项宽度(包含标题和输入框宽度总和)
*/
itemWidth: {
type: Number,
required: true
},
/**
* 每一项下间距
*/
marginBottom: {
type: String,
default: '18px'
},
/**
* 按钮块最小宽度默认350当每一行剩余空间大于此值按钮块将不会折行
*/
minMenuWidth: {
type: Number,
default: 350
},
/**
* 按钮位置默认为end可选值为start/end/center/space-around/space-between
*/
operatorPosition: {
type: String,
default: 'end'
}
},
data () {
return {
tempDomCount: 0,
tempDomWidth: undefined,
operatorWidth: undefined,
oldFilterItemCount: 0,
oldHasOperator: false,
oldWidth: 0,
rowJustify: 'space-between'
}
},
computed: {
getMenuBoxStyle () {
return {
'width': this.operatorWidth,
'margin-bottom': this.marginBottom,
'flex-grow': this.operatorWidth ? undefined : '1'
}
}
},
methods: {
onUpdate () {
setTimeout(() => {
let filterItemCount = Array.isArray(this.$slots.default) ? this.$slots.default.filter(item => item.context).length : 0;
let hasOperator = Array.isArray(this.$slots.operator) && this.$slots.operator.length > 0;
let width = $(this.$el).width();
if (filterItemCount === this.oldFilterItemCount && hasOperator === this.oldHasOperator && width === this.oldWidth) {
return;
}
let lineCount = this.itemWidth > 0 ? parseInt(width / this.itemWidth) : 1;
lineCount = Math.max(1, lineCount);
let residueCount = filterItemCount % lineCount;
this.tempDomCount = 0;
this.tempDomWidth = undefined;
this.rowJustify = 'space-between';
let tempCount = residueCount === 0 ? 0 : (lineCount - residueCount);
if (hasOperator) {
let residueWidth = width - ((lineCount - residueCount) * this.itemWidth) - 20;
// 判断剩余的空间是否够放下操作按钮
if (residueWidth >= this.minMenuWidth && residueCount === 0) {
this.rowJustify = 'start';
this.operatorWidth = undefined;
} else {
// 剩余空位数大于1需要占位dom
if (tempCount >= 1) {
if (residueWidth >= this.minMenuWidth) {
this.tempDomCount = tempCount - 1;
this.tempDomWidth = this.tempDomCount > 0 ? (20 / this.tempDomCount) + 'px' : undefined;
this.operatorWidth = this.tempDomCount > 0 ? (((tempCount * this.itemWidth) - 20) + 'px') : (this.itemWidth + 'px');
} else {
this.tempDomCount = tempCount;
this.tempDomWidth = (residueWidth / this.tempDomCount) + 'px';
this.operatorWidth = '100%';
}
} else {
this.operatorWidth = '100%';
}
}
} else {
this.tempDomCount = tempCount;
this.tempDomWidth = this.itemWidth + 'px';
}
this.oldFilterItemCount = filterItemCount;
this.oldHasOperator = hasOperator;
this.oldWidth = width;
});
}
},
beforeUpdate () {
this.onUpdate();
},
mounted () {
setTimeout(() => {
this.onUpdate();
});
},
created () {
window.addEventListener('resize', this.onUpdate);
},
beforeDestroy () {
window.removeEventListener('resize', this.onUpdate);
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,44 @@
<template>
<div>
<svg t="1492500959545" @click="toggleClick" class="hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
<path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
p-id="1692"></path>
<path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
p-id="1693"></path>
<path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
p-id="1694"></path>
</svg>
</div>
</template>
<script>
export default {
name: 'hamburger',
props: {
isActive: {
type: Boolean,
default: false
},
toggleClick: {
type: Function,
default: null
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
cursor: pointer;
width: 20px;
height: 20px;
transform: rotate(90deg);
transform-origin: 50% 50%;
}
.hamburger.is-active {
transform: rotate(0deg);
}
</style>

View File

@@ -0,0 +1,280 @@
[
"el-icon-delete-solid",
"el-icon-delete",
"el-icon-s-tools",
"el-icon-setting",
"el-icon-user-solid",
"el-icon-user",
"el-icon-phone",
"el-icon-phone-outline",
"el-icon-more",
"el-icon-more-outline",
"el-icon-star-on",
"el-icon-star-off",
"el-icon-s-goods",
"el-icon-goods",
"el-icon-warning",
"el-icon-warning-outline",
"el-icon-question",
"el-icon-info",
"el-icon-remove",
"el-icon-circle-plus",
"el-icon-success",
"el-icon-error",
"el-icon-zoom-in",
"el-icon-zoom-out",
"el-icon-remove-outline",
"el-icon-circle-plus-outline",
"el-icon-circle-check",
"el-icon-circle-close",
"el-icon-s-help",
"el-icon-help",
"el-icon-minus",
"el-icon-plus",
"el-icon-check",
"el-icon-close",
"el-icon-picture",
"el-icon-picture-outline",
"el-icon-picture-outline-round",
"el-icon-upload",
"el-icon-upload2",
"el-icon-download",
"el-icon-camera-solid",
"el-icon-camera",
"el-icon-video-camera-solid",
"el-icon-video-camera",
"el-icon-message-solid",
"el-icon-bell",
"el-icon-s-cooperation",
"el-icon-s-order",
"el-icon-s-platform",
"el-icon-s-fold",
"el-icon-s-unfold",
"el-icon-s-operation",
"el-icon-s-promotion",
"el-icon-s-home",
"el-icon-s-release",
"el-icon-s-ticket",
"el-icon-s-management",
"el-icon-s-open",
"el-icon-s-shop",
"el-icon-s-marketing",
"el-icon-s-flag",
"el-icon-s-comment",
"el-icon-s-finance",
"el-icon-s-claim",
"el-icon-s-custom",
"el-icon-s-opportunity",
"el-icon-s-data",
"el-icon-s-check",
"el-icon-s-grid",
"el-icon-menu",
"el-icon-share",
"el-icon-d-caret",
"el-icon-caret-left",
"el-icon-caret-right",
"el-icon-caret-bottom",
"el-icon-caret-top",
"el-icon-bottom-left",
"el-icon-bottom-right",
"el-icon-back",
"el-icon-right",
"el-icon-bottom",
"el-icon-top",
"el-icon-top-left",
"el-icon-top-right",
"el-icon-arrow-left",
"el-icon-arrow-right",
"el-icon-arrow-down",
"el-icon-arrow-up",
"el-icon-d-arrow-left",
"el-icon-d-arrow-right",
"el-icon-video-pause",
"el-icon-video-play",
"el-icon-refresh",
"el-icon-refresh-right",
"el-icon-refresh-left",
"el-icon-finished",
"el-icon-sort",
"el-icon-sort-up",
"el-icon-sort-down",
"el-icon-rank",
"el-icon-loading",
"el-icon-view",
"el-icon-c-scale-to-original",
"el-icon-date",
"el-icon-edit",
"el-icon-edit-outline",
"el-icon-folder",
"el-icon-folder-opened",
"el-icon-folder-add",
"el-icon-folder-remove",
"el-icon-folder-delete",
"el-icon-folder-checked",
"el-icon-tickets",
"el-icon-document-remove",
"el-icon-document-delete",
"el-icon-document-copy",
"el-icon-document-checked",
"el-icon-document",
"el-icon-document-add",
"el-icon-printer",
"el-icon-paperclip",
"el-icon-takeaway-box",
"el-icon-search",
"el-icon-monitor",
"el-icon-attract",
"el-icon-mobile",
"el-icon-scissors",
"el-icon-umbrella",
"el-icon-headset",
"el-icon-brush",
"el-icon-mouse",
"el-icon-coordinate",
"el-icon-magic-stick",
"el-icon-reading",
"el-icon-data-line",
"el-icon-data-board",
"el-icon-pie-chart",
"el-icon-data-analysis",
"el-icon-collection-tag",
"el-icon-film",
"el-icon-suitcase",
"el-icon-suitcase-1",
"el-icon-receiving",
"el-icon-collection",
"el-icon-files",
"el-icon-notebook-1",
"el-icon-notebook-2",
"el-icon-toilet-paper",
"el-icon-office-building",
"el-icon-school",
"el-icon-table-lamp",
"el-icon-house",
"el-icon-no-smoking",
"el-icon-smoking",
"el-icon-shopping-cart-full",
"el-icon-shopping-cart-1",
"el-icon-shopping-cart-2",
"el-icon-shopping-bag-1",
"el-icon-shopping-bag-2",
"el-icon-sold-out",
"el-icon-sell",
"el-icon-present",
"el-icon-box",
"el-icon-bank-card",
"el-icon-money",
"el-icon-coin",
"el-icon-wallet",
"el-icon-discount",
"el-icon-price-tag",
"el-icon-news",
"el-icon-guide",
"el-icon-male",
"el-icon-female",
"el-icon-thumb",
"el-icon-cpu",
"el-icon-link",
"el-icon-connection",
"el-icon-open",
"el-icon-turn-off",
"el-icon-set-up",
"el-icon-chat-round",
"el-icon-chat-line-round",
"el-icon-chat-square",
"el-icon-chat-dot-round",
"el-icon-chat-dot-square",
"el-icon-chat-line-square",
"el-icon-message",
"el-icon-postcard",
"el-icon-position",
"el-icon-turn-off-microphone",
"el-icon-microphone",
"el-icon-close-notification",
"el-icon-bangzhu",
"el-icon-time",
"el-icon-odometer",
"el-icon-crop",
"el-icon-aim",
"el-icon-switch-button",
"el-icon-full-screen",
"el-icon-copy-document",
"el-icon-mic",
"el-icon-stopwatch",
"el-icon-medal-1",
"el-icon-medal",
"el-icon-trophy",
"el-icon-trophy-1",
"el-icon-first-aid-kit",
"el-icon-discover",
"el-icon-place",
"el-icon-location",
"el-icon-location-outline",
"el-icon-location-information",
"el-icon-add-location",
"el-icon-delete-location",
"el-icon-map-location",
"el-icon-alarm-clock",
"el-icon-timer",
"el-icon-watch-1",
"el-icon-watch",
"el-icon-lock",
"el-icon-unlock",
"el-icon-key",
"el-icon-service",
"el-icon-mobile-phone",
"el-icon-bicycle",
"el-icon-truck",
"el-icon-ship",
"el-icon-basketball",
"el-icon-football",
"el-icon-soccer",
"el-icon-baseball",
"el-icon-wind-power",
"el-icon-light-rain",
"el-icon-lightning",
"el-icon-heavy-rain",
"el-icon-sunrise",
"el-icon-sunrise-1",
"el-icon-sunset",
"el-icon-sunny",
"el-icon-cloudy",
"el-icon-partly-cloudy",
"el-icon-cloudy-and-sunny",
"el-icon-moon",
"el-icon-moon-night",
"el-icon-dish",
"el-icon-dish-1",
"el-icon-food",
"el-icon-chicken",
"el-icon-fork-spoon",
"el-icon-knife-fork",
"el-icon-burger",
"el-icon-tableware",
"el-icon-sugar",
"el-icon-dessert",
"el-icon-ice-cream",
"el-icon-hot-water",
"el-icon-water-cup",
"el-icon-coffee-cup",
"el-icon-cold-drink",
"el-icon-goblet",
"el-icon-goblet-full",
"el-icon-goblet-square",
"el-icon-goblet-square-full",
"el-icon-refrigerator",
"el-icon-grape",
"el-icon-watermelon",
"el-icon-cherry",
"el-icon-apple",
"el-icon-pear",
"el-icon-orange",
"el-icon-coffee",
"el-icon-ice-tea",
"el-icon-ice-drink",
"el-icon-milk-tea",
"el-icon-potato-strips",
"el-icon-lollipop",
"el-icon-ice-cream-square",
"el-icon-ice-cream-round"
]

View File

@@ -0,0 +1,105 @@
<template>
<el-popover width="510" v-model="showDropdown" @show="onDropdownShow">
<div class="icon-select-dropdown">
<el-row type="flex" style="flex-wrap: wrap">
<el-col :span="3" v-for="icon in getIconList" :key="icon" class="icon-item"
:class="{active: (value === icon)}" @click.native="onIconClick(icon)">
<i :class="icon" />
</el-col>
</el-row>
<el-row type="flex" justify="space-between">
<el-button type="text" @click="onClearClick" style="margin-left: 10px;">清空</el-button>
<el-pagination
:current-page.sync="currentPage"
:page-size="pageSize"
layout="prev, pager, next"
:total="getIconCount">
</el-pagination>
</el-row>
</div>
<div slot="reference" class="icon-select"
:style="{width: height + 'px', height: height + 'px', 'line-height': height + 'px', 'font-size': height * 0.5 + 'px'}">
<i :class="value" />
</div>
</el-popover>
</template>
<script>
import iconList from './icon.json';
export default {
props: {
/**
* 绑定字段
*/
value: String,
/**
* 组件高度单位px
*/
height: {
type: Number,
default: 45
}
},
data () {
return {
showDropdown: false,
currentPage: 1,
pageSize: 32
}
},
methods: {
onIconClick (icon) {
this.$emit('input', icon);
this.showDropdown = false;
},
onClearClick () {
this.$emit('input');
this.showDropdown = false;
},
onDropdownShow () {
this.currentPage = 1
let pos = iconList.indexOf(this.value);
if (pos >= 0) {
this.currentPage += Math.floor(pos / this.pageSize);
}
}
},
computed: {
getIconCount () {
return iconList.length;
},
getIconList () {
let beginPos = (this.currentPage - 1) * this.pageSize;
let endPos = beginPos + this.pageSize;
return iconList.slice(beginPos, endPos);
}
}
}
</script>
<style scoped>
.icon-select {
text-align: center;
color: #5F6266;
border: 1px solid #DCDFE6;
border-radius: 4px;
cursor: pointer;
}
.icon-item {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 20px;
color: #5F6266;
border-radius: 3px;
border: 1px solid #DCDFE6;
margin: 10px;
cursor: pointer;
}
.active {
color: #EF5E1C;
}
</style>

View File

@@ -0,0 +1,226 @@
<template>
<div class="el-input el-date-editor el-range-editor el-input__inner el-input-number-range"
:class="
[
inputSize ? 'el-range-editor--' + inputSize : '',
focused ? 'is-active' : '',
{
'is-disabled': inputDisabled,
'el-input--prefix': prefixIcon
}
]"
@mouseenter="showClose = true"
@mouseleave="showClose = false">
<div class="el-input__icon el-range__icon" :class="prefixIcon">
<slot name="prepend"></slot>
</div>
<input
autocomplete="off"
:placeholder="startPlaceholder"
:value="userInput && userInput[0]"
:disabled="inputDisabled"
:readonly="readonly"
:name="name && name[0]"
@input="handleStartInput"
@change="handleStartChange"
@focus="focused = true"
@blur="focused = false"
class="el-range-input">
<slot name="range-separator">
<span class="el-range-separator">{{ rangeSeparator }}</span>
</slot>
<input
autocomplete="off"
:placeholder="endPlaceholder"
:value="userInput && userInput[1]"
:disabled="inputDisabled"
:readonly="readonly"
:name="name && name[1]"
@input="handleEndInput"
@change="handleEndChange"
@focus="focused = true"
@blur="focused = false"
class="el-range-input">
<i class="el-input__icon el-range__close-icon"
:class="[showClear ? 'el-icon-circle-close' : '']"
@click="handleClickClear">
</i>
</div>
</template>
<script>
import emitter from 'element-ui/src/mixins/emitter';
function isNumber (val) {
var regPos = /^\d+(\.\d+)?$/; // 非负浮点数
var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; // 负浮点数
if (regPos.test(val) || regNeg.test(val)) {
return true;
} else {
return false;
}
}
export default {
name: 'InputNumberRange',
componentName: 'InputNumberRange',
mixins: [emitter],
props: {
/**
* 绑定字段
*/
value: {
type: Array,
default: function () {
return [];
}
},
/**
* 组件大小medium / small / mini
*/
size: String,
/**
* 禁用
*/
disabled: Boolean,
/**
* 完全只读
*/
readonly: Boolean,
/**
* 是否显示清除按钮
*/
clearable: {
type: Boolean,
default: false
},
/**
* 自定义头部图标的类名
*/
prefixIcon: String,
/**
* 范围选择时最小值的占位内容
*/
startPlaceholder: String,
/**
* 范围选择时最大值的占位内容
*/
endPlaceholder: String,
/**
* 原生属性
*/
name: {
default: ''
},
/**
* 选择范围时的分隔符
*/
rangeSeparator: {
type: String,
default: '-'
},
validateEvent: {
type: Boolean,
default: true
}
},
data () {
return {
hovering: false,
focused: false,
userInput: this.value,
showClose: false
};
},
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
computed: {
_elFormItemSize () {
return (this.elFormItem || {}).elFormItemSize;
},
inputSize () {
let temp = this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
return temp;
},
inputDisabled () {
return this.disabled || (this.elForm || {}).disabled;
},
showClear () {
let temp = this.clearable && !this.inputDisabled && !this.readonly && this.showClose &&
this.userInput != null && Array.isArray(this.userInput) && this.userInput.length > 0 &&
(this.userInput[0] != null || this.userInput[1] != null);
return temp;
}
},
methods: {
handleStartInput (event) {
if (this.userInput) {
this.userInput = [event.target.value, this.userInput[1]];
} else {
this.userInput = [event.target.value, null];
}
},
handleEndInput (event) {
if (this.userInput) {
this.userInput = [this.userInput[0], event.target.value];
} else {
this.userInput = [null, event.target.value];
}
},
handleStartChange (event) {
let value = this.userInput && this.userInput[0];
value = isNumber(value) ? value : null;
value = value ? Number.parseFloat(value) : null;
if (this.userInput) {
this.userInput[0] = value;
} else {
this.userInput = [value, null];
}
event.srcElement.value = value;
this.emitInput(this.userInput);
},
handleEndChange (event) {
let value = this.userInput && this.userInput[1];
value = isNumber(value) ? value : null;
value = value ? Number.parseFloat(value) : null;
if (this.userInput) {
this.userInput[1] = value;
} else {
this.userInput = [null, value];
}
event.srcElement.value = value;
this.emitInput(this.userInput);
},
handleClickClear () {
this.userInput = undefined;
this.emitInput(this.userInput);
},
valueEquals (val, oldVal) {
return JSON.stringify(val) === JSON.stringify(oldVal);
},
emitInput (values) {
this.$emit('input', values);
this.$emit('change', values);
}
},
watch: {
value: {
handler: function (val, oldVal) {
if (!this.valueEquals(val, oldVal) && this.validateEvent) {
this.dispatch('ElFormItem', 'el.form.change', val);
}
},
deep: true
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,44 @@
<template>
<el-progress v-bind="$attrs" :percentage="getPercentage" />
</template>
<script>
export default {
name: 'Progress',
props: {
/**
* 组件最小值
*/
min: {
type: Number,
default: 0
},
/**
* 组件最大值
*/
max: {
type: Number,
default: 100
},
/**
* 组件当前值
*/
value: {
type: Number,
default: 0
}
},
computed: {
getPercentage () {
let value = Math.min(this.max, Math.max(this.min, this.value));
value = value - this.min;
if ((this.max - this.min) === 0) {
value = 0;
} else {
value = ((value * 100) / (this.max - this.min));
}
return Number.isInteger(value) ? value : parseInt(value);
}
}
}
</script>

View File

@@ -0,0 +1,129 @@
<template>
<div class="uditor-class" ref="editor"></div>
</template>
<script>
import WEditor from 'wangeditor';
const defaultConfigs = {
uploadImgServer: undefined,
uploadFileName: 'imageFile',
uploadImgMaxSize: 1 * 1024 * 1024,
uploadImgShowBase64: true,
uploadImgMaxLength: 5,
uploadImgParams: undefined,
uploadImgParamsWithUrl: true,
withCredentials: true,
uploadImgTimeout: 5000,
uploadImgHeaders: undefined,
uploadImgHooks: undefined,
zIndex: 0,
lang: undefined,
pasteFilterStyle: true,
pasteIgnoreImg: false,
onchangeTimeout: 10,
menus: [
// 标题
'head',
// 粗体
'bold',
// 字号
'fontSize',
// 字体
'fontName',
// 斜体
'italic',
// 下划线
'underline',
// 删除线
'strikeThrough',
// 文字颜色
'foreColor',
// 背景颜色
'backColor',
// 插入链接
'link',
// 列表
'list',
// 对齐方式
'justify',
// 引用
'quote',
// 插入图片
'image',
// 撤销
'undo',
// 重复
'redo'
]
}
export default {
props: {
/**
* 绑定字段
*/
value: {
type: String
},
/**
* 配置项详情请参考wangEditor文档
*/
config: {
type: Object,
default: () => {
return defaultConfigs;
}
}
},
data () {
return {
editor: null
}
},
computed: {
getConfigs () {
return {...this.config, ...defaultConfigs};
}
},
mounted () {
this.editor = new WEditor(this.$refs.editor);
this.editor.customConfig = {...this.getConfigs};
this.editor.customConfig.pasteTextHandle = (content) => {
// content 即粘贴过来的内容html 或 纯文本),可进行自定义处理然后返回
return content;
}
this.editor.customConfig.linkImgCallback = (url) => {
console.log(url) // url 即插入图片的地址
}
this.editor.customConfig.linkCheck = (text, link) => {
return true // 返回 true 表示校验成功
// return '验证失败' // 返回字符串,即校验失败的提示信息
}
this.editor.customConfig.linkImgCheck = (src) => {
return true // 返回 true 表示校验成功
// return '验证失败' // 返回字符串,即校验失败的提示信息
}
// 失去焦点后更新数据
this.editor.customConfig.onblur = (html) => {
console.log(html)
this.$emit('input', html);
}
this.editor.create();
this.editor.txt.html(this.value);
},
watch: {
value: {
handler (newValue) {
if (this.editor) this.editor.txt.html(this.value);
},
immediate: true
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,119 @@
<template>
<el-table-column v-bind="$attrs">
<template slot-scope="scope">
<orange-progress :stroke-width="strokeWidth" :type="type" :text-inside="textInside" :status="status" :color="color"
:width="width" :show-text="showText" :min="getMinValue(scope.row)" :max="getMaxValue(scope.row)"
:value="getValue(scope.row)" />
</template>
</el-table-column>
</template>
<script>
import Progress from '@/components/Progress/index.vue';
export default {
name: 'TableProgressColumn',
components: {
'orange-progress': Progress
},
props: {
/**
* 固定值最小值
*/
min: {
type: Number,
default: 0
},
/**
* 固定值最大值
*/
max: {
type: Number,
default: 100
},
/**
* 固定值当前值
*/
value: {
type: Number,
default: 0
},
/**
* 表格最小值字段名
*/
minColumn: {
type: String
},
/**
* 表格最大值字段名
*/
maxColumn: {
type: String
},
/**
* 表格当前值字段名
*/
valueColumn: {
type: String
},
/**
* 进度条的宽度,单位 px
*/
strokeWidth: {
type: Number,
default: 16
},
/**
* 进度条类型line/circle/dashboard
*/
type: {
type: String,
default: 'line'
},
/**
* 进度条显示文字内置在进度条内(只在 type=line 时可用)
*/
textInside: {
type: Boolean,
default: true
},
/**
* 进度条当前状态(success/exception/warning)
*/
status: {
type: String
},
/**
* 进度条背景色(会覆盖 status 状态颜色)
*/
color: {
type: [String, Function, Array]
},
/**
* 环形进度条画布宽度(只在 type 为 circle 或 dashboard 时可用)
*/
width: {
type: Number,
default: 126
},
/**
* 是否显示进度条文字内容
*/
showText: {
type: Boolean,
default: true
}
},
methods: {
getValue (row) {
return this.valueColumn ? row[this.valueColumn] : this.value;
},
getMinValue (row) {
return this.minColumn ? row[this.minColumn] : this.min;
},
getMaxValue (row) {
return this.maxColumn ? row[this.maxColumn] : this.max;
}
}
}
</script>

View File

@@ -0,0 +1,300 @@
<template>
<el-popover ref="popover" placement="bottom-start" trigger="click" popper-class="tree-select-popover"
:width="width" @show="onShowPopover">
<el-scrollbar :style="{'height': this.height, 'min-width': this.width}" ref="scrollbar">
<el-tree ref="dropdownTree" :props="getTreeProps" :highlightCurrent="highlightCurrent" :nodeKey="getDataProps.value"
:defaultExpandAll="defaultExpandAll" :expandOnClickNode="expandOnClickNode" :checkOnClickNode="checkOnClickNode"
:autoExpandParent="autoExpandParent" :defaultExpandedKeys="defaultExpandedKeys" :showCheckbox="showCheckbox"
:checkStrictly="checkStrictly" :defaultCheckedKeys="defaultCheckedKeys" :currentNodeKey="getCurrentNodeKey"
:accordion="accordion" :indent="indent" :iconClass="iconClass" :load="loadChildrenNodes" lazy :show-checkbox="multiple"
@node-click="onTreeNodeClick" @check="onTreeNodeCheck">
<span :style="getNodeStyle(data)" slot-scope="{ node, data }">{{data[getDataProps.label]}}</span>
</el-tree>
</el-scrollbar>
<el-select slot="reference" v-model="selectKeys" :multiple="multiple" :disabled="false" :size="size"
:clearable="clearable" :collapseTags="collapseTags" :placeholder="placeholder" popper-class="select-tree-popper"
@clear="onClear" @remove-tag="onClear">
<el-option v-for="item in selectNodes" :key="item[getDataProps.value]"
:value="item[getDataProps.value]" :label="item[getDataProps.label]" />
</el-select>
</el-popover>
</template>
<script>
import { findTreeNode } from '@/utils';
export default {
name: 'TreeSelect',
props: {
value: {
type: [String, Number]
},
multiple: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
size: {
type: String
},
height: {
type: String,
default: '200px'
},
width: {
type: String,
default: '300px'
},
activeColor: {
type: String,
default: '#EF5E1C'
},
clearable: {
type: Boolean,
default: false
},
collapseTags: {
type: Boolean,
default: true
},
placeholder: {
type: String
},
loading: {
type: Boolean,
default: false
},
loadingText: {
type: String,
default: '加载中'
},
// 树属性
data: {
type: Array
},
props: {
type: Object,
default: () => {
return {
label: 'label',
value: 'value',
parentKey: 'parentId',
children: 'children',
disabled: 'disabled'
}
}
},
defaultExpandAll: {
type: Boolean,
default: false
},
expandOnClickNode: {
type: Boolean,
default: true
},
checkOnClickNode: {
type: Boolean,
default: false
},
autoExpandParent: {
type: Boolean,
default: true
},
defaultExpandedKeys: {
type: Array
},
checkStrictly: {
type: Boolean,
default: true
},
currentNodeKey: {
type: [String, Number]
},
accordion: {
type: Boolean,
default: false
},
indent: {
type: Number,
default: 16
},
iconClass: {
type: String
}
},
data () {
return {
rootNode: undefined,
rootResolve: undefined,
allTreeNode: [],
selectNodes: [],
scrollTop: 0,
selectKeys: undefined
}
},
methods: {
onShowPopover () {
setTimeout(() => {
this.$refs.scrollbar.wrap.scrollTop = this.scrollTop;
// this.$refs.scrollbar.update();
}, 20);
if (!this.multiple) {
this.$refs.dropdownTree.setCurrentKey(this.value);
}
},
onClear () {
this.$nextTick(() => {
this.$emit('input', this.selectKeys);
});
},
onTreeNodeClick (data, node) {
this.$refs.popover.showPopper = false;
if (!this.multiple) {
this.scrollTop = this.$refs.scrollbar.wrap.scrollTop;
this.$emit('input', data[this.getDataProps.value]);
this.$emit('change', data[this.getDataProps.value]);
}
},
onTreeNodeCheck (data, {checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys}) {
this.scrollTop = this.$refs.scrollbar.wrap.scrollTop
this.$emit('input', checkedKeys);
this.$emit('change', checkedKeys);
},
parseNode (node) {
if (Array.isArray(node) && node.length > 0) {
node.forEach((item) => {
item['__node_is_leaf__'] = !(Array.isArray(item[this.getDataProps.children]) && item[this.getDataProps.children].length > 0);
});
return node;
} else {
return [];
}
},
loadChildrenNodes (node, resolve) {
if (node.level === 0) {
this.rootNode = node;
this.rootResolve = resolve;
return resolve(this.parseNode(this.allTreeNode));
} else {
return resolve(this.parseNode(node.data[this.getDataProps.children]));
}
},
getNodeStyle (data) {
if (!this.multiple && (this.selectNodes[0] || {})[this.getDataProps.value] === data[this.getDataProps.value]) {
return {
color: this.activeColor,
'font-weight': 700
}
}
}
},
computed: {
showCheckbox () {
return this.multiple;
},
getCurrentNodeKey () {
if (!this.multiple && Array.isArray(this.selectNodes) && this.selectNodes.length > 0) {
return this.selectNodes[0][this.getDataProps.value];
} else {
return null;
}
},
highlightCurrent () {
return this.multiple;
},
defaultCheckedKeys () {
return this.multiple ? this.selectNodes : undefined
},
getDataProps () {
return {
label: this.props.label || 'label',
value: this.props.value || 'value',
parentKey: this.props.parentKey || 'parentId',
children: this.props.children || 'children',
disabled: this.props.disabled || 'disabled'
}
},
getTreeProps () {
return {
label: this.getDataProps.label,
children: '__children_list__',
disabled: this.getDataProps.disabled,
isLeaf: '__node_is_leaf__'
};
}
},
watch: {
data: {
handler (newValue, oldValue) {
this.allTreeNode = newValue;
if (this.rootNode != null && this.rootResolve != null) {
this.rootNode.childNodes = [];
this.loadChildrenNodes(this.rootNode, this.rootResolve);
}
this.selectNodes = [];
if (this.multiple) {
if (Array.isArray(this.value)) {
this.value.forEach((item) => {
let data = findTreeNode(this.allTreeNode, item, this.getDataProps.value, this.getDataProps.children);
if (data) this.selectNodes.push(data);
});
}
} else {
let data = findTreeNode(this.allTreeNode, this.value, this.getDataProps.value, this.getDataProps.children);
if (data) this.selectNodes.push(data);
}
},
immediate: true
},
value: {
handler (newValue) {
this.selectNodes = [];
if (Array.isArray(newValue)) {
newValue.forEach((item) => {
let data = findTreeNode(this.allTreeNode, item, this.getDataProps.value, this.getDataProps.children);
if (data) this.selectNodes.push(data);
});
this.selectKeys = newValue;
} else {
let data = findTreeNode(this.allTreeNode, newValue, this.getDataProps.value, this.getDataProps.children);
if (data) this.selectNodes.push(data);
this.selectKeys = newValue;
}
if (this.$refs.dropdownTree) {
this.multiple ? this.$refs.dropdownTree.setCheckedKeys(newValue) : this.$refs.dropdownTree.setCurrentKey(newValue);
}
},
immediate: true
}
}
}
</script>
<style>
.select-tree-popper {
display: none;
}
.tree-select-popover {
padding: 6px 0px;
}
.tree-select-popover .popper__arrow {
left: 35px!important;
}
.tree-select-popover .el-tree .el-tree-node__content {
height: 34px;
line-height: 34px;
}
/*
.tree-select-popover .el-tree .el-tree-node.is-current .el-tree-node__content {
color: #fdb95c;
font-weight: 700;
}
*/
.current-node {
color: #EF5E1C;
font-weight: 700;
}
</style>