Merge pull request 'liunan' (#10) from liunan into master
Reviewed-on: #10
This commit is contained in:
commit
0859519fea
|
@ -1,14 +1,15 @@
|
|||
{
|
||||
"name": "ag-element-ui",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"version": "0.1.20",
|
||||
"main": "packages/index.js",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lib": "vue-cli-service build --target lib --dest lib packages/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.8.3"
|
||||
"core-js": "^3.8.3",
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
|
@ -19,9 +20,9 @@
|
|||
"element-ui": "^2.15.14",
|
||||
"sass": "^1.32.7",
|
||||
"sass-loader": "^12.0.0",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue": "^2.6.14",
|
||||
"vue-router": "^3.5.1",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"browserslist": [
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import agColorPicker from './src'
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agColorPicker.install = function (Vue) {
|
||||
Vue.component(agColorPicker.name, agColorPicker)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agColorPicker
|
|
@ -0,0 +1,317 @@
|
|||
const hsv2hsl = function(hue, sat, val) {
|
||||
return [
|
||||
hue,
|
||||
(sat * val / ((hue = (2 - sat) * val) < 1 ? hue : 2 - hue)) || 0,
|
||||
hue / 2
|
||||
];
|
||||
};
|
||||
|
||||
// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
|
||||
// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
|
||||
const isOnePointZero = function(n) {
|
||||
return typeof n === 'string' && n.indexOf('.') !== -1 && parseFloat(n) === 1;
|
||||
};
|
||||
|
||||
const isPercentage = function(n) {
|
||||
return typeof n === 'string' && n.indexOf('%') !== -1;
|
||||
};
|
||||
|
||||
// Take input from [0, n] and return it as [0, 1]
|
||||
const bound01 = function(value, max) {
|
||||
if (isOnePointZero(value)) value = '100%';
|
||||
|
||||
const processPercent = isPercentage(value);
|
||||
value = Math.min(max, Math.max(0, parseFloat(value)));
|
||||
|
||||
// Automatically convert percentage into number
|
||||
if (processPercent) {
|
||||
value = parseInt(value * max, 10) / 100;
|
||||
}
|
||||
|
||||
// Handle floating point rounding errors
|
||||
if ((Math.abs(value - max) < 0.000001)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Convert into [0, 1] range if it isn't already
|
||||
return (value % max) / parseFloat(max);
|
||||
};
|
||||
|
||||
const INT_HEX_MAP = { 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F' };
|
||||
|
||||
const toHex = function({ r, g, b }) {
|
||||
const hexOne = function(value) {
|
||||
value = Math.min(Math.round(value), 255);
|
||||
const high = Math.floor(value / 16);
|
||||
const low = value % 16;
|
||||
return '' + (INT_HEX_MAP[high] || high) + (INT_HEX_MAP[low] || low);
|
||||
};
|
||||
|
||||
if (isNaN(r) || isNaN(g) || isNaN(b)) return '';
|
||||
|
||||
return '#' + hexOne(r) + hexOne(g) + hexOne(b);
|
||||
};
|
||||
|
||||
const HEX_INT_MAP = { A: 10, B: 11, C: 12, D: 13, E: 14, F: 15 };
|
||||
|
||||
const parseHexChannel = function(hex) {
|
||||
if (hex.length === 2) {
|
||||
return (HEX_INT_MAP[hex[0].toUpperCase()] || +hex[0]) * 16 + (HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1]);
|
||||
}
|
||||
|
||||
return HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1];
|
||||
};
|
||||
|
||||
const hsl2hsv = function(hue, sat, light) {
|
||||
sat = sat / 100;
|
||||
light = light / 100;
|
||||
let smin = sat;
|
||||
const lmin = Math.max(light, 0.01);
|
||||
let sv;
|
||||
let v;
|
||||
|
||||
light *= 2;
|
||||
sat *= (light <= 1) ? light : 2 - light;
|
||||
smin *= lmin <= 1 ? lmin : 2 - lmin;
|
||||
v = (light + sat) / 2;
|
||||
sv = light === 0 ? (2 * smin) / (lmin + smin) : (2 * sat) / (light + sat);
|
||||
|
||||
return {
|
||||
h: hue,
|
||||
s: sv * 100,
|
||||
v: v * 100
|
||||
};
|
||||
};
|
||||
|
||||
// `rgbToHsv`
|
||||
// Converts an RGB color value to HSV
|
||||
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
|
||||
// *Returns:* { h, s, v } in [0,1]
|
||||
const rgb2hsv = function(r, g, b) {
|
||||
r = bound01(r, 255);
|
||||
g = bound01(g, 255);
|
||||
b = bound01(b, 255);
|
||||
|
||||
const max = Math.max(r, g, b);
|
||||
const min = Math.min(r, g, b);
|
||||
let h, s;
|
||||
let v = max;
|
||||
|
||||
const d = max - min;
|
||||
s = max === 0 ? 0 : d / max;
|
||||
|
||||
if (max === min) {
|
||||
h = 0; // achromatic
|
||||
} else {
|
||||
switch (max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
break;
|
||||
case g:
|
||||
h = (b - r) / d + 2;
|
||||
break;
|
||||
case b:
|
||||
h = (r - g) / d + 4;
|
||||
break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return { h: h * 360, s: s * 100, v: v * 100 };
|
||||
};
|
||||
|
||||
// `hsvToRgb`
|
||||
// Converts an HSV color value to RGB.
|
||||
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
|
||||
// *Returns:* { r, g, b } in the set [0, 255]
|
||||
const hsv2rgb = function(h, s, v) {
|
||||
h = bound01(h, 360) * 6;
|
||||
s = bound01(s, 100);
|
||||
v = bound01(v, 100);
|
||||
|
||||
const i = Math.floor(h);
|
||||
const f = h - i;
|
||||
const p = v * (1 - s);
|
||||
const q = v * (1 - f * s);
|
||||
const t = v * (1 - (1 - f) * s);
|
||||
const mod = i % 6;
|
||||
const r = [v, q, p, p, t, v][mod];
|
||||
const g = [t, v, v, q, p, p][mod];
|
||||
const b = [p, p, t, v, v, q][mod];
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255)
|
||||
};
|
||||
};
|
||||
|
||||
export default class Color {
|
||||
constructor(options) {
|
||||
this._hue = 0;
|
||||
this._saturation = 100;
|
||||
this._value = 100;
|
||||
this._alpha = 100;
|
||||
|
||||
this.enableAlpha = false;
|
||||
this.format = 'hex';
|
||||
this.value = '';
|
||||
|
||||
options = options || {};
|
||||
|
||||
for (let option in options) {
|
||||
if (options.hasOwnProperty(option)) {
|
||||
this[option] = options[option];
|
||||
}
|
||||
}
|
||||
|
||||
this.doOnChange();
|
||||
}
|
||||
|
||||
set(prop, value) {
|
||||
if (arguments.length === 1 && typeof prop === 'object') {
|
||||
for (let p in prop) {
|
||||
if (prop.hasOwnProperty(p)) {
|
||||
this.set(p, prop[p]);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this['_' + prop] = value;
|
||||
this.doOnChange();
|
||||
}
|
||||
|
||||
get(prop) {
|
||||
return this['_' + prop];
|
||||
}
|
||||
|
||||
toRgb() {
|
||||
return hsv2rgb(this._hue, this._saturation, this._value);
|
||||
}
|
||||
|
||||
fromString(value) {
|
||||
if (!value) {
|
||||
this._hue = 0;
|
||||
this._saturation = 100;
|
||||
this._value = 100;
|
||||
|
||||
this.doOnChange();
|
||||
return;
|
||||
}
|
||||
|
||||
const fromHSV = (h, s, v) => {
|
||||
this._hue = Math.max(0, Math.min(360, h));
|
||||
this._saturation = Math.max(0, Math.min(100, s));
|
||||
this._value = Math.max(0, Math.min(100, v));
|
||||
|
||||
this.doOnChange();
|
||||
};
|
||||
|
||||
if (value.indexOf('hsl') !== -1) {
|
||||
const parts = value.replace(/hsla|hsl|\(|\)/gm, '')
|
||||
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
|
||||
|
||||
if (parts.length === 4) {
|
||||
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
|
||||
} else if (parts.length === 3) {
|
||||
this._alpha = 100;
|
||||
}
|
||||
if (parts.length >= 3) {
|
||||
const { h, s, v } = hsl2hsv(parts[0], parts[1], parts[2]);
|
||||
fromHSV(h, s, v);
|
||||
}
|
||||
} else if (value.indexOf('hsv') !== -1) {
|
||||
const parts = value.replace(/hsva|hsv|\(|\)/gm, '')
|
||||
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
|
||||
|
||||
if (parts.length === 4) {
|
||||
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
|
||||
} else if (parts.length === 3) {
|
||||
this._alpha = 100;
|
||||
}
|
||||
if (parts.length >= 3) {
|
||||
fromHSV(parts[0], parts[1], parts[2]);
|
||||
}
|
||||
} else if (value.indexOf('rgb') !== -1) {
|
||||
const parts = value.replace(/rgba|rgb|\(|\)/gm, '')
|
||||
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
|
||||
|
||||
if (parts.length === 4) {
|
||||
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
|
||||
} else if (parts.length === 3) {
|
||||
this._alpha = 100;
|
||||
}
|
||||
if (parts.length >= 3) {
|
||||
const { h, s, v } = rgb2hsv(parts[0], parts[1], parts[2]);
|
||||
fromHSV(h, s, v);
|
||||
}
|
||||
} else if (value.indexOf('#') !== -1) {
|
||||
const hex = value.replace('#', '').trim();
|
||||
if (!/^(?:[0-9a-fA-F]{3}){1,2}|[0-9a-fA-F]{8}$/.test(hex)) return;
|
||||
let r, g, b;
|
||||
|
||||
if (hex.length === 3) {
|
||||
r = parseHexChannel(hex[0] + hex[0]);
|
||||
g = parseHexChannel(hex[1] + hex[1]);
|
||||
b = parseHexChannel(hex[2] + hex[2]);
|
||||
} else if (hex.length === 6 || hex.length === 8) {
|
||||
r = parseHexChannel(hex.substring(0, 2));
|
||||
g = parseHexChannel(hex.substring(2, 4));
|
||||
b = parseHexChannel(hex.substring(4, 6));
|
||||
}
|
||||
|
||||
if (hex.length === 8) {
|
||||
this._alpha = Math.floor(parseHexChannel(hex.substring(6)) / 255 * 100);
|
||||
} else if (hex.length === 3 || hex.length === 6) {
|
||||
this._alpha = 100;
|
||||
}
|
||||
|
||||
const { h, s, v } = rgb2hsv(r, g, b);
|
||||
fromHSV(h, s, v);
|
||||
}
|
||||
}
|
||||
|
||||
compare(color) {
|
||||
return Math.abs(color._hue - this._hue) < 2 &&
|
||||
Math.abs(color._saturation - this._saturation) < 1 &&
|
||||
Math.abs(color._value - this._value) < 1 &&
|
||||
Math.abs(color._alpha - this._alpha) < 1;
|
||||
}
|
||||
|
||||
doOnChange() {
|
||||
const { _hue, _saturation, _value, _alpha, format } = this;
|
||||
|
||||
if (this.enableAlpha) {
|
||||
switch (format) {
|
||||
case 'hsl':
|
||||
const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
|
||||
this.value = `hsla(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%, ${ _alpha / 100})`;
|
||||
break;
|
||||
case 'hsv':
|
||||
this.value = `hsva(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%, ${ _alpha / 100})`;
|
||||
break;
|
||||
default:
|
||||
const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
|
||||
this.value = `rgba(${r}, ${g}, ${b}, ${ _alpha / 100 })`;
|
||||
}
|
||||
} else {
|
||||
switch (format) {
|
||||
case 'hsl':
|
||||
const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
|
||||
this.value = `hsl(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%)`;
|
||||
break;
|
||||
case 'hsv':
|
||||
this.value = `hsv(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%)`;
|
||||
break;
|
||||
case 'rgb':
|
||||
const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
|
||||
this.value = `rgb(${r}, ${g}, ${b})`;
|
||||
break;
|
||||
default:
|
||||
this.value = toHex(hsv2rgb(_hue, _saturation, _value));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,132 @@
|
|||
<template>
|
||||
<div class="el-color-alpha-slider" :class="{ 'is-vertical': vertical }">
|
||||
<div class="el-color-alpha-slider__bar"
|
||||
@click="handleClick"
|
||||
ref="bar"
|
||||
:style="{
|
||||
background: background
|
||||
}">
|
||||
</div>
|
||||
<div class="el-color-alpha-slider__thumb"
|
||||
ref="thumb"
|
||||
:style="{
|
||||
left: thumbLeft + 'px',
|
||||
top: thumbTop + 'px'
|
||||
}">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from '../draggable';
|
||||
|
||||
export default {
|
||||
name: 'el-color-alpha-slider',
|
||||
|
||||
props: {
|
||||
color: {
|
||||
required: true
|
||||
},
|
||||
vertical: Boolean
|
||||
},
|
||||
|
||||
watch: {
|
||||
'color._alpha'() {
|
||||
this.update();
|
||||
},
|
||||
|
||||
'color.value'() {
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleClick(event) {
|
||||
const thumb = this.$refs.thumb;
|
||||
const target = event.target;
|
||||
|
||||
if (target !== thumb) {
|
||||
this.handleDrag(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleDrag(event) {
|
||||
const rect = this.$el.getBoundingClientRect();
|
||||
const { thumb } = this.$refs;
|
||||
|
||||
if (!this.vertical) {
|
||||
let left = event.clientX - rect.left;
|
||||
left = Math.max(thumb.offsetWidth / 2, left);
|
||||
left = Math.min(left, rect.width - thumb.offsetWidth / 2);
|
||||
|
||||
this.color.set('alpha', Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 100));
|
||||
} else {
|
||||
let top = event.clientY - rect.top;
|
||||
top = Math.max(thumb.offsetHeight / 2, top);
|
||||
top = Math.min(top, rect.height - thumb.offsetHeight / 2);
|
||||
|
||||
this.color.set('alpha', Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 100));
|
||||
}
|
||||
},
|
||||
|
||||
getThumbLeft() {
|
||||
if (this.vertical) return 0;
|
||||
const el = this.$el;
|
||||
const alpha = this.color._alpha;
|
||||
|
||||
if (!el) return 0;
|
||||
const thumb = this.$refs.thumb;
|
||||
return Math.round(alpha * (el.offsetWidth - thumb.offsetWidth / 2) / 100);
|
||||
},
|
||||
|
||||
getThumbTop() {
|
||||
if (!this.vertical) return 0;
|
||||
const el = this.$el;
|
||||
const alpha = this.color._alpha;
|
||||
|
||||
if (!el) return 0;
|
||||
const thumb = this.$refs.thumb;
|
||||
return Math.round(alpha * (el.offsetHeight - thumb.offsetHeight / 2) / 100);
|
||||
},
|
||||
|
||||
getBackground() {
|
||||
if (this.color && this.color.value) {
|
||||
const { r, g, b } = this.color.toRgb();
|
||||
return `linear-gradient(to right, rgba(${r}, ${g}, ${b}, 0) 0%, rgba(${r}, ${g}, ${b}, 1) 100%)`;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
update() {
|
||||
this.thumbLeft = this.getThumbLeft();
|
||||
this.thumbTop = this.getThumbTop();
|
||||
this.background = this.getBackground();
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
thumbLeft: 0,
|
||||
thumbTop: 0,
|
||||
background: null
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const { bar, thumb } = this.$refs;
|
||||
|
||||
const dragConfig = {
|
||||
drag: (event) => {
|
||||
this.handleDrag(event);
|
||||
},
|
||||
end: (event) => {
|
||||
this.handleDrag(event);
|
||||
}
|
||||
};
|
||||
|
||||
draggable(bar, dragConfig);
|
||||
draggable(thumb, dragConfig);
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,123 @@
|
|||
<template>
|
||||
<div class="el-color-hue-slider" :class="{ 'is-vertical': vertical }">
|
||||
<div class="el-color-hue-slider__bar" @click="handleClick" ref="bar"></div>
|
||||
<div class="el-color-hue-slider__thumb"
|
||||
:style="{
|
||||
left: thumbLeft + 'px',
|
||||
top: thumbTop + 'px'
|
||||
}"
|
||||
ref="thumb">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from '../draggable';
|
||||
|
||||
export default {
|
||||
name: 'el-color-hue-slider',
|
||||
|
||||
props: {
|
||||
color: {
|
||||
required: true
|
||||
},
|
||||
|
||||
vertical: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
thumbLeft: 0,
|
||||
thumbTop: 0
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
hueValue() {
|
||||
const hue = this.color.get('hue');
|
||||
return hue;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
hueValue() {
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleClick(event) {
|
||||
const thumb = this.$refs.thumb;
|
||||
const target = event.target;
|
||||
|
||||
if (target !== thumb) {
|
||||
this.handleDrag(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleDrag(event) {
|
||||
const rect = this.$el.getBoundingClientRect();
|
||||
const { thumb } = this.$refs;
|
||||
let hue;
|
||||
|
||||
if (!this.vertical) {
|
||||
let left = event.clientX - rect.left;
|
||||
left = Math.min(left, rect.width - thumb.offsetWidth / 2);
|
||||
left = Math.max(thumb.offsetWidth / 2, left);
|
||||
|
||||
hue = Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 360);
|
||||
} else {
|
||||
let top = event.clientY - rect.top;
|
||||
top = Math.min(top, rect.height - thumb.offsetHeight / 2);
|
||||
top = Math.max(thumb.offsetHeight / 2, top);
|
||||
|
||||
hue = Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 360);
|
||||
}
|
||||
|
||||
this.color.set('hue', hue);
|
||||
},
|
||||
|
||||
getThumbLeft() {
|
||||
if (this.vertical) return 0;
|
||||
const el = this.$el;
|
||||
const hue = this.color.get('hue');
|
||||
|
||||
if (!el) return 0;
|
||||
const thumb = this.$refs.thumb;
|
||||
return Math.round(hue * (el.offsetWidth - thumb.offsetWidth / 2) / 360);
|
||||
},
|
||||
|
||||
getThumbTop() {
|
||||
if (!this.vertical) return 0;
|
||||
const el = this.$el;
|
||||
const hue = this.color.get('hue');
|
||||
|
||||
if (!el) return 0;
|
||||
const thumb = this.$refs.thumb;
|
||||
return Math.round(hue * (el.offsetHeight - thumb.offsetHeight / 2) / 360);
|
||||
},
|
||||
|
||||
update() {
|
||||
this.thumbLeft = this.getThumbLeft();
|
||||
this.thumbTop = this.getThumbTop();
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const { bar, thumb } = this.$refs;
|
||||
|
||||
const dragConfig = {
|
||||
drag: (event) => {
|
||||
this.handleDrag(event);
|
||||
},
|
||||
end: (event) => {
|
||||
this.handleDrag(event);
|
||||
}
|
||||
};
|
||||
|
||||
draggable(bar, dragConfig);
|
||||
draggable(thumb, dragConfig);
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,128 @@
|
|||
<template>
|
||||
<transition name="el-zoom-in-top" @after-leave="doDestroy">
|
||||
<div
|
||||
class="el-color-dropdown"
|
||||
v-show="showPopper">
|
||||
<div class="el-color-dropdown__main-wrapper">
|
||||
<hue-slider ref="hue" :color="color" vertical style="float: right;"></hue-slider>
|
||||
<sv-panel ref="sl" :color="color"></sv-panel>
|
||||
</div>
|
||||
<alpha-slider v-if="showAlpha" ref="alpha" :color="color"></alpha-slider>
|
||||
<predefine v-if="predefine" :color="color" :colors="predefine"></predefine>
|
||||
<div class="el-color-dropdown__btns">
|
||||
<span class="el-color-dropdown__value">
|
||||
<el-input
|
||||
v-model="customInput"
|
||||
@keyup.native.enter="handleConfirm"
|
||||
@blur="handleConfirm"
|
||||
:validate-event="false"
|
||||
size="mini">
|
||||
</el-input>
|
||||
</span>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
class="el-color-dropdown__link-btn"
|
||||
@click="$emit('eyedropper')">
|
||||
<i class="el-icon-magic-stick"></i>
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
class="el-color-dropdown__link-btn"
|
||||
@click="$emit('clear')">
|
||||
{{ t('el.colorpicker.clear') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
size="mini"
|
||||
class="el-color-dropdown__btn"
|
||||
@click="confirmValue">
|
||||
{{ t('el.colorpicker.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SvPanel from './sv-panel';
|
||||
import HueSlider from './hue-slider';
|
||||
import AlphaSlider from './alpha-slider';
|
||||
import Predefine from './predefine';
|
||||
import Popper from 'element-ui/src/utils/vue-popper';
|
||||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import ElInput from 'element-ui/packages/input';
|
||||
import ElButton from 'element-ui/packages/button';
|
||||
|
||||
export default {
|
||||
name: 'el-color-picker-dropdown',
|
||||
|
||||
mixins: [Popper, Locale],
|
||||
|
||||
components: {
|
||||
SvPanel,
|
||||
HueSlider,
|
||||
AlphaSlider,
|
||||
ElInput,
|
||||
ElButton,
|
||||
Predefine
|
||||
},
|
||||
|
||||
props: {
|
||||
color: {
|
||||
required: true
|
||||
},
|
||||
showAlpha: Boolean,
|
||||
predefine: Array
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
customInput: ''
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentColor() {
|
||||
const parent = this.$parent;
|
||||
return !parent.value && !parent.showPanelColor ? '' : parent.color.value;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
confirmValue() {
|
||||
this.$emit('pick');
|
||||
},
|
||||
|
||||
handleConfirm() {
|
||||
this.color.fromString(this.customInput);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$parent.popperElm = this.popperElm = this.$el;
|
||||
this.referenceElm = this.$parent.$el;
|
||||
},
|
||||
|
||||
watch: {
|
||||
showPopper(val) {
|
||||
if (val === true) {
|
||||
this.$nextTick(() => {
|
||||
const { sl, hue, alpha } = this.$refs;
|
||||
sl && sl.update();
|
||||
hue && hue.update();
|
||||
alpha && alpha.update();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
currentColor: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
this.customInput = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<div class="el-color-predefine">
|
||||
<div class="el-color-predefine__colors">
|
||||
<div class="el-color-predefine__color-selector"
|
||||
:class="{selected: item.selected, 'is-alpha': item._alpha < 100}"
|
||||
v-for="(item, index) in rgbaColors"
|
||||
:key="colors[index]"
|
||||
@click="handleSelect(index)">
|
||||
<div :style="{'background-color': item.value}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Color from '../color';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
colors: { type: Array, required: true },
|
||||
color: { required: true }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rgbaColors: this.parseColors(this.colors, this.color)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSelect(index) {
|
||||
this.color.fromString(this.colors[index]);
|
||||
},
|
||||
parseColors(colors, color) {
|
||||
return colors.map(value => {
|
||||
const c = new Color();
|
||||
c.enableAlpha = true;
|
||||
c.format = 'rgba';
|
||||
c.fromString(value);
|
||||
c.selected = c.value === color.value;
|
||||
return c;
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$parent.currentColor'(val) {
|
||||
const color = new Color();
|
||||
color.fromString(val);
|
||||
|
||||
this.rgbaColors.forEach(item => {
|
||||
item.selected = color.compare(item);
|
||||
});
|
||||
},
|
||||
colors(newVal) {
|
||||
this.rgbaColors = this.parseColors(newVal, this.color);
|
||||
},
|
||||
color(newVal) {
|
||||
this.rgbaColors = this.parseColors(this.colors, newVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div class="el-color-svpanel"
|
||||
:style="{
|
||||
backgroundColor: background
|
||||
}">
|
||||
<div class="el-color-svpanel__white"></div>
|
||||
<div class="el-color-svpanel__black"></div>
|
||||
<div class="el-color-svpanel__cursor"
|
||||
:style="{
|
||||
top: cursorTop + 'px',
|
||||
left: cursorLeft + 'px'
|
||||
}">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from '../draggable';
|
||||
|
||||
export default {
|
||||
name: 'el-sl-panel',
|
||||
|
||||
props: {
|
||||
color: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
colorValue() {
|
||||
const hue = this.color.get('hue');
|
||||
const value = this.color.get('value');
|
||||
return { hue, value };
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
colorValue() {
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
update() {
|
||||
const saturation = this.color.get('saturation');
|
||||
const value = this.color.get('value');
|
||||
|
||||
const el = this.$el;
|
||||
let { clientWidth: width, clientHeight: height } = el;
|
||||
|
||||
this.cursorLeft = saturation * width / 100;
|
||||
this.cursorTop = (100 - value) * height / 100;
|
||||
|
||||
this.background = 'hsl(' + this.color.get('hue') + ', 100%, 50%)';
|
||||
},
|
||||
|
||||
handleDrag(event) {
|
||||
const el = this.$el;
|
||||
const rect = el.getBoundingClientRect();
|
||||
|
||||
let left = event.clientX - rect.left;
|
||||
let top = event.clientY - rect.top;
|
||||
left = Math.max(0, left);
|
||||
left = Math.min(left, rect.width);
|
||||
|
||||
top = Math.max(0, top);
|
||||
top = Math.min(top, rect.height);
|
||||
|
||||
this.cursorLeft = left;
|
||||
this.cursorTop = top;
|
||||
this.color.set({
|
||||
saturation: left / rect.width * 100,
|
||||
value: 100 - top / rect.height * 100
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
draggable(this.$el, {
|
||||
drag: (event) => {
|
||||
this.handleDrag(event);
|
||||
},
|
||||
end: (event) => {
|
||||
this.handleDrag(event);
|
||||
}
|
||||
});
|
||||
|
||||
this.update();
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
cursorTop: 0,
|
||||
cursorLeft: 0,
|
||||
background: 'hsl(0, 100%, 50%)'
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,36 @@
|
|||
import Vue from 'vue';
|
||||
let isDragging = false;
|
||||
|
||||
export default function(element, options) {
|
||||
if (Vue.prototype.$isServer) return;
|
||||
const moveFn = function(event) {
|
||||
if (options.drag) {
|
||||
options.drag(event);
|
||||
}
|
||||
};
|
||||
const upFn = function(event) {
|
||||
document.removeEventListener('mousemove', moveFn);
|
||||
document.removeEventListener('mouseup', upFn);
|
||||
document.onselectstart = null;
|
||||
document.ondragstart = null;
|
||||
|
||||
isDragging = false;
|
||||
|
||||
if (options.end) {
|
||||
options.end(event);
|
||||
}
|
||||
};
|
||||
element.addEventListener('mousedown', function(event) {
|
||||
if (isDragging) return;
|
||||
document.onselectstart = function() { return false; };
|
||||
document.ondragstart = function() { return false; };
|
||||
|
||||
document.addEventListener('mousemove', moveFn);
|
||||
document.addEventListener('mouseup', upFn);
|
||||
isDragging = true;
|
||||
|
||||
if (options.start) {
|
||||
options.start(event);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'el-color-picker',
|
||||
colorDisabled ? 'is-disabled' : '',
|
||||
colorSize ? `el-color-picker--${ colorSize }` : ''
|
||||
]"
|
||||
v-clickoutside="hide">
|
||||
<div class="el-color-picker__mask" v-if="colorDisabled"></div>
|
||||
<div class="el-color-picker__trigger" @click="handleTrigger">
|
||||
<span class="el-color-picker__color" :class="{ 'is-alpha': showAlpha }">
|
||||
<span class="el-color-picker__color-inner"
|
||||
:style="{
|
||||
backgroundColor: displayedColor
|
||||
}"></span>
|
||||
<span class="el-color-picker__empty el-icon-close" v-if="!value && !showPanelColor"></span>
|
||||
</span>
|
||||
<span class="el-color-picker__icon el-icon-arrow-down" v-show="value || showPanelColor"></span>
|
||||
</div>
|
||||
<picker-dropdown
|
||||
ref="dropdown"
|
||||
:class="['el-color-picker__panel', popperClass || '']"
|
||||
v-model="showPicker"
|
||||
@pick="confirmValue"
|
||||
@clear="clearValue"
|
||||
@eyedropper="eyedropper"
|
||||
:color="color"
|
||||
:show-alpha="showAlpha"
|
||||
:predefine="predefine">
|
||||
</picker-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Color from './color';
|
||||
import PickerDropdown from './components/picker-dropdown.vue';
|
||||
import Clickoutside from 'element-ui/src/utils/clickoutside';
|
||||
import Emitter from 'element-ui/src/mixins/emitter';
|
||||
|
||||
export default {
|
||||
name: 'AgColorPicker',
|
||||
|
||||
mixins: [Emitter],
|
||||
|
||||
props: {
|
||||
value: String,
|
||||
showAlpha: Boolean,
|
||||
colorFormat: String,
|
||||
disabled: Boolean,
|
||||
size: String,
|
||||
popperClass: String,
|
||||
predefine: Array
|
||||
},
|
||||
|
||||
inject: {
|
||||
elForm: {
|
||||
default: ''
|
||||
},
|
||||
elFormItem: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
|
||||
directives: { Clickoutside },
|
||||
|
||||
computed: {
|
||||
displayedColor() {
|
||||
if (!this.value && !this.showPanelColor) {
|
||||
return 'transparent';
|
||||
}
|
||||
|
||||
return this.displayedRgb(this.color, this.showAlpha);
|
||||
},
|
||||
|
||||
_elFormItemSize() {
|
||||
return (this.elFormItem || {}).elFormItemSize;
|
||||
},
|
||||
|
||||
colorSize() {
|
||||
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
|
||||
colorDisabled() {
|
||||
return this.disabled || (this.elForm || {}).disabled;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value(val) {
|
||||
if (!val) {
|
||||
this.showPanelColor = false;
|
||||
} else if (val && val !== this.color.value) {
|
||||
this.color.fromString(val);
|
||||
}
|
||||
},
|
||||
color: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.showPanelColor = true;
|
||||
}
|
||||
},
|
||||
displayedColor(val) {
|
||||
if (!this.showPicker) return;
|
||||
const currentValueColor = new Color({
|
||||
enableAlpha: this.showAlpha,
|
||||
format: this.colorFormat
|
||||
});
|
||||
currentValueColor.fromString(this.value);
|
||||
|
||||
const currentValueColorRgb = this.displayedRgb(currentValueColor, this.showAlpha);
|
||||
if (val !== currentValueColorRgb) {
|
||||
this.$emit('active-change', val);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleTrigger() {
|
||||
if (this.colorDisabled) return;
|
||||
this.showPicker = !this.showPicker;
|
||||
},
|
||||
confirmValue() {
|
||||
const value = this.color.value;
|
||||
this.$emit('input', value);
|
||||
this.$emit('change', value);
|
||||
this.dispatch('ElFormItem', 'el.form.change', value);
|
||||
this.showPicker = false;
|
||||
},
|
||||
clearValue() {
|
||||
this.$emit('input', null);
|
||||
this.$emit('change', null);
|
||||
if (this.value !== null) {
|
||||
this.dispatch('ElFormItem', 'el.form.change', null);
|
||||
}
|
||||
this.showPanelColor = false;
|
||||
this.showPicker = false;
|
||||
this.resetColor();
|
||||
},
|
||||
async eyedropper(){
|
||||
const dropper=new EyeDropper();
|
||||
try{
|
||||
const result=await dropper.open();
|
||||
const value = result.sRGBHex;
|
||||
this.$emit('input', value);
|
||||
this.$emit('change', value);
|
||||
this.dispatch('ElFormItem', 'el.form.change', value);
|
||||
}catch(e){
|
||||
}
|
||||
},
|
||||
hide() {
|
||||
this.showPicker = false;
|
||||
this.resetColor();
|
||||
},
|
||||
resetColor() {
|
||||
this.$nextTick(_ => {
|
||||
if (this.value) {
|
||||
this.color.fromString(this.value);
|
||||
} else {
|
||||
this.showPanelColor = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
displayedRgb(color, showAlpha) {
|
||||
if (!(color instanceof Color)) {
|
||||
throw Error('color should be instance of Color Class');
|
||||
}
|
||||
|
||||
const { r, g, b } = color.toRgb();
|
||||
return showAlpha
|
||||
? `rgba(${ r }, ${ g }, ${ b }, ${ color.get('alpha') / 100 })`
|
||||
: `rgb(${ r }, ${ g }, ${ b })`;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const value = this.value;
|
||||
if (value) {
|
||||
this.color.fromString(value);
|
||||
}
|
||||
this.popperElm = this.$refs.dropdown.$el;
|
||||
},
|
||||
|
||||
data() {
|
||||
const color = new Color({
|
||||
enableAlpha: this.showAlpha,
|
||||
format: this.colorFormat
|
||||
});
|
||||
|
||||
return {
|
||||
color,
|
||||
showPicker: false,
|
||||
showPanelColor: false
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
PickerDropdown
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -6,4 +6,4 @@ agDatePicker.install = function (Vue) {
|
|||
}
|
||||
|
||||
// 导出组件
|
||||
export default agDatePicker
|
||||
export default agDatePicker;
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
:style="{ width }"
|
||||
:prefix-icon="iconClass"
|
||||
clear-icon="ag-icon-clear"
|
||||
ref="datepickerref"
|
||||
v-model="dateArr"
|
||||
v-bind="attrs"
|
||||
v-on="Listeners"
|
||||
:size="$attrs.size||'small'"
|
||||
:value="value"
|
||||
:type="datetype"
|
||||
@mouseenter.native="mousetrue = true"
|
||||
@mouseleave.native="mousetrue = false"
|
||||
|
@ -13,13 +16,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* agDatePicker 时间选择器
|
||||
*/
|
||||
import isEmpty from "../../../src/utils/isEmpty";
|
||||
|
||||
export default {
|
||||
name: "agDatePicker",
|
||||
name: "AgDatePicker",
|
||||
props: {
|
||||
range:false,
|
||||
showTime:false,
|
||||
|
@ -28,7 +28,9 @@ export default {
|
|||
default: "date",
|
||||
},
|
||||
value: {
|
||||
default: null||[],
|
||||
default:()=>{
|
||||
return null||[]
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
@ -59,9 +61,9 @@ export default {
|
|||
let config = {};
|
||||
if (this.range) {
|
||||
config = {
|
||||
"start-placeholder": "开始日期",
|
||||
"end-placeholder": "结束日期",
|
||||
"range-separator": "-",
|
||||
"start-placeholder":this.$attrs.startPlaceholder||"开始日期",
|
||||
"end-placeholder":this.$attrs.endPlaceholder|| "结束日期",
|
||||
"range-separator":this.$attrs.rangeSeparator||"-",
|
||||
"picker-options": {
|
||||
disabledDate(time) {
|
||||
return (
|
||||
|
@ -130,7 +132,7 @@ export default {
|
|||
} else {
|
||||
config = {
|
||||
align: "right",
|
||||
placeholder: "选择日期",
|
||||
placeholder: this.$attrs.placeholder||"选择日期",
|
||||
"picker-options": {
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now();
|
||||
|
@ -179,33 +181,55 @@ export default {
|
|||
input: (value) => {
|
||||
if (this.range) {
|
||||
if (!isEmpty(value) && value.length === 2 && value[0] && value[1]) {
|
||||
this.$emit("change", [
|
||||
`${value[0]} 00:00:00`,
|
||||
`${value[1]} 23:59:59`,
|
||||
]);
|
||||
if(this.showTime){
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", value);
|
||||
}
|
||||
}else{
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", [
|
||||
`${value[0]} 00:00:00`,
|
||||
`${value[1]} 23:59:59`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
this.$emit("change", []);
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", []);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$emit("change", value);
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", value);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
iconClass() {
|
||||
|
||||
return this.mousetrue
|
||||
? "ag-icon-prefix-hide"
|
||||
: "ag-icon-prefix-show";
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (Array.isArray(this.value)&&this.range){
|
||||
this.dateArr = [this.value[0] || "", this.value[1] || ""];
|
||||
} else {
|
||||
this.dateArr = this.value;
|
||||
}
|
||||
for(const key in this.$refs.datepickerref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.datepickerref[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (Array.isArray(newVal)&&this.range){
|
||||
|
||||
const [date1, date2] = newVal.slice(0, 2);
|
||||
this.dateArr = [date1 || "", date2 || ""];
|
||||
this.dateArr = [newVal[0] || "", newVal[1] || ""];
|
||||
} else {
|
||||
this.dateArr = newVal;
|
||||
}
|
||||
|
@ -217,7 +241,7 @@ export default {
|
|||
if(!newVal){
|
||||
return
|
||||
}
|
||||
let defaultWidth = this.range ?this.showTime?"330px":"170px" : this.showTime?"190px":"140px";
|
||||
let defaultWidth = this.range ?this.showTime?"330px":"200px" : this.showTime?"190px":"150px";
|
||||
this.width = defaultWidth;
|
||||
},
|
||||
immediate: true,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import agForm from './src'
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agForm.install = function (Vue) {
|
||||
Vue.component(agForm.name, agForm)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agForm;
|
|
@ -0,0 +1,191 @@
|
|||
<template>
|
||||
<el-form v-bind="$attrs" v-on="$listeners" :model="formValue" ref="formref">
|
||||
<ag-row>
|
||||
<ag-col v-for="item,index in data" :key="index" :span="item.span||24">
|
||||
<el-form-item v-bind="item" :prop="item.enName" >
|
||||
<slot :name="item.soltName" v-if="item.soltName" :row="item"/>
|
||||
<div class="contentbox" v-else>
|
||||
<ag-input v-model="formValue[item.enName]" type="textarea" v-bind="item" v-if="item.type=='ag-textarea'" size="small" clearable></ag-input>
|
||||
<ag-input v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-input'" size="small" clearable></ag-input>
|
||||
<ag-date-picker v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-date-picker'" size="small" clearable/>
|
||||
<ag-select v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-select'" size="small" clearable/>
|
||||
<el-radio-group v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-radio'&&formValue[item.enName]" size="small" clearable>
|
||||
<el-radio :label="it.value" v-for="it,index in item.options" :key="index">{{it.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-checkbox-group v-bind="item" v-if="item.type=='ag-checkbox'&&formValue[item.enName]" v-model="formValue[item.enName]" size="small" clearable>
|
||||
<el-checkbox v-for="it,index in item.options" :label="it.value" :key="index">{{it.label}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-input-number v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-input-number'" clearable></el-input-number>
|
||||
<el-cascader v-model="formValue[item.enName]" v-bind="item" size="small" v-if="item.type=='ag-cascader'" clearable :style="{width:'100%'}"></el-cascader>
|
||||
<el-switch
|
||||
v-model="formValue[item.enName]"
|
||||
v-bind="item" size="small" v-if="item.type=='ag-switch'&&formValue[item.enName]" >
|
||||
</el-switch>
|
||||
<el-slider v-model="formValue[item.enName]"
|
||||
v-bind="item" size="small" v-if="item.type=='ag-slider'"></el-slider>
|
||||
<el-time-select
|
||||
:style="{width:'100%'}"
|
||||
clearable
|
||||
v-model="formValue[item.enName]"
|
||||
v-bind="item" size="small"
|
||||
v-if="item.type=='ag-time-select'"
|
||||
:picker-options="item.options">
|
||||
</el-time-select>
|
||||
<ag-upload v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-upload'" clear isPre></ag-upload>
|
||||
<el-rate v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-rate'" size="small"></el-rate>
|
||||
<agColorPicker v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-color-picker'" size="small">
|
||||
</agColorPicker>
|
||||
<el-transfer :data="item.data" v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-transfer'" size="small"></el-transfer>
|
||||
<agNumberRange v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-numberRange'" size="small" clearable/>
|
||||
<ag-multion-input v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-multion-input'" size="small" clearable/>
|
||||
<agQuery v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-query'" size="small" clearable/>
|
||||
<ag-mution-checkbox :datas="item.datas" v-bind="item" :placeholder="item.placeholder" v-model="formValue[item.enName]" v-if="item.type=='ag-mution-checkbox'" size="small"> </ag-mution-checkbox>
|
||||
<ag-multion-date-picker v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-multion-datte-picker'" size="small"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</ag-col>
|
||||
</ag-row>
|
||||
<div class="footerbox" v-if="$listeners.onSubmit">
|
||||
<slot name="button" :value="formValue">
|
||||
<el-button @click="onSubmit" type="primary" size="small" class="submitbtn">
|
||||
{{submittitle||'提交'}}
|
||||
</el-button>
|
||||
</slot>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
|
||||
import agInput from './../../agInput/src/index.vue';
|
||||
import agDatePicker from './../../agDatePicker/src/index.vue';
|
||||
import agSelect from './../../agSelect/src/index.vue';
|
||||
import agRow from './../../agRow/src/index.vue';
|
||||
import agCol from './../../agCol/src/index.vue';
|
||||
import agUpload from './../../agUpload/src/index.vue';
|
||||
import agColorPicker from './../../agColorPicker/src/index.vue';
|
||||
import agNumberRange from './../../agNumberRange/src/index.vue';
|
||||
import agMultionInput from './../../agMultionInput/src/index.vue';
|
||||
import agQuery from './../../agQuery/src/index.vue';
|
||||
import agMultionDatePicker from '../../agMultionDatePicker';
|
||||
|
||||
|
||||
export default{
|
||||
name:"agForm",
|
||||
components:{
|
||||
agMultionDatePicker,
|
||||
agInput:agInput,
|
||||
agDatePicker,
|
||||
agSelect,
|
||||
agRow,
|
||||
agCol,
|
||||
agUpload:agUpload,
|
||||
agColorPicker,
|
||||
agNumberRange,
|
||||
agMultionInput,
|
||||
agQuery
|
||||
},
|
||||
props:{
|
||||
submittitle:{
|
||||
type:String,
|
||||
default:'提交'
|
||||
},
|
||||
data:{
|
||||
type:Array,
|
||||
default(){
|
||||
return []
|
||||
}
|
||||
},
|
||||
span:{
|
||||
type:Number,
|
||||
default:24
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
formValue:{
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.formValue=this.$attrs.value;
|
||||
setTimeout(()=>{
|
||||
this.$refs.formref.clearValidate();
|
||||
},1);
|
||||
if(this.$refs.formref){
|
||||
for(const key in this.$refs.formref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.formref[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
watch:{
|
||||
value(val){
|
||||
this.formValue = val;
|
||||
setTimeout(()=>{
|
||||
this.$refs.formref.clearValidate();
|
||||
},1);
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
onSubmit(){
|
||||
this.$emit('onSubmit',this.formValue)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footerbox{
|
||||
margin-top:12px;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
.submitbtn{
|
||||
width:200px;
|
||||
}
|
||||
}
|
||||
.el-form--inline{
|
||||
.el-form-item{
|
||||
display:flex;
|
||||
}
|
||||
.el-form-item__content{
|
||||
flex:1;
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
.contentbox{
|
||||
width:100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
.flexcenter{
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
::v-deep{
|
||||
.el-form--inline{
|
||||
.el-form-item{
|
||||
display:flex;
|
||||
}
|
||||
.el-form-item__content{
|
||||
display:flex;
|
||||
flex:1;
|
||||
width:100%;
|
||||
margin-left:0;
|
||||
}
|
||||
}
|
||||
.el-form-item{
|
||||
width:100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.el-form-item__content{
|
||||
flex:1;
|
||||
display:flex;
|
||||
width:100%;
|
||||
margin-left:0!important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,23 +1,17 @@
|
|||
<template>
|
||||
<el-input
|
||||
class="ag_input"
|
||||
size="small"
|
||||
:size="$attrs.size||'small'"
|
||||
ref="apinputref"
|
||||
:style="{ width }"
|
||||
v-on="Listeners"
|
||||
v-bind="attrs"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<slot name="append" slot="append" />
|
||||
<slot name="prefix" slot="prefix" />
|
||||
<slot name="suffix" slot="suffix" />
|
||||
<slot name="prepend" slot="prepend" />
|
||||
<slot v-for="(_,name) in $slots" :name="name" :slot="name"> </slot>
|
||||
</el-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* WInput
|
||||
* @desc 处理输入的输入框(转大写,不能有中文空格等)
|
||||
*/
|
||||
export default {
|
||||
name: "agInput",
|
||||
props: {
|
||||
|
@ -30,42 +24,15 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
attrs() {
|
||||
return {
|
||||
size: "small",
|
||||
clearable: true, // 默认清空
|
||||
...this.$attrs,
|
||||
};
|
||||
},
|
||||
// 所有父级事件
|
||||
Listeners() {
|
||||
return Object.assign(
|
||||
{},
|
||||
// 我们从父级添加所有的监听器
|
||||
this.$listeners,
|
||||
// 然后我们添加自定义监听器,
|
||||
// 或覆写一些监听器的行为
|
||||
{
|
||||
// 这里确保组件配合 `v-model` 的工作
|
||||
input: (value) => {
|
||||
this.$emit("change", this.toUpperCase ? value.toUpperCase() : value);
|
||||
},
|
||||
blur: (e) => {
|
||||
let value = e.target.value
|
||||
.trim()
|
||||
.replace(/\s/g, (match) =>
|
||||
match.charCodeAt(0) === 12288 ? String.fromCharCode(32) : match
|
||||
);
|
||||
|
||||
// 失去焦点自动首位去空格
|
||||
this.$emit("change", value);
|
||||
},
|
||||
mounted(){
|
||||
if(this.$refs.apinputref){
|
||||
for(const key in this.$refs.apinputref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.apinputref[key];
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import agMultifunctionSearch from './src'
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agMultifunctionSearch.install = function (Vue) {
|
||||
Vue.component(agMultifunctionSearch.name, agMultifunctionSearch)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agMultifunctionSearch
|
|
@ -1,252 +0,0 @@
|
|||
<template>
|
||||
<div class="ag-MultifunctionSearch">
|
||||
<ag-select
|
||||
slot="prepend"
|
||||
:clearable="false"
|
||||
placeholder="请选择"
|
||||
:value="value[0]"
|
||||
v-bind="config.select"
|
||||
@change="onSelect"
|
||||
class="ag_select_group"
|
||||
:style="{ width: `${swidth}px` }"
|
||||
>
|
||||
</ag-select>
|
||||
<ag-input
|
||||
v-if="!showExtra"
|
||||
class="ag_input_group"
|
||||
placeholder="请输入内容"
|
||||
:value="value[1]"
|
||||
:disabled="config.input.disabled||imeipopover"
|
||||
v-bind="config.input"
|
||||
@change="onInputChange"
|
||||
>
|
||||
</ag-input>
|
||||
<el-popover
|
||||
v-if="showExtra"
|
||||
placement="bottom"
|
||||
trigger="manual"
|
||||
ref="popover"
|
||||
popper-class="popperOptions"
|
||||
v-model="imeipopover"
|
||||
>
|
||||
<template slot="reference">
|
||||
<ag-input
|
||||
class="ag_input_group"
|
||||
placeholder="请输入内容"
|
||||
:value="value[1]"
|
||||
:disabled="config.input.disabled||imeipopover"
|
||||
v-bind="config.input"
|
||||
@change="onInputChange"
|
||||
>
|
||||
<template slot="suffix" v-if="showExtra">
|
||||
<i
|
||||
class="iconfont icon-icon-piliangcaozuo imeiicondefault"
|
||||
:class="imeipopover && 'imeiiconActive'"
|
||||
style="font-size: 12px;"
|
||||
@click.prevent="imeiiconClick"
|
||||
></i>
|
||||
</template>
|
||||
</ag-input>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="value[1]"
|
||||
type="textarea"
|
||||
:rows="12"
|
||||
placeholder="一行一项,最多支持200行"
|
||||
resize="none"
|
||||
border="none"
|
||||
class="textareainput"
|
||||
@input="onInputChange"
|
||||
/>
|
||||
<divider class="divider"></divider>
|
||||
<div class="btnbox">
|
||||
<div>
|
||||
<el-button size="mini" @click="imeiclose"
|
||||
>关闭</el-button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-button size="mini" @click="cleartext"
|
||||
>清空</el-button
|
||||
>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="primary"
|
||||
plain
|
||||
@click="search"
|
||||
>查询</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import agSelect from "../../agSelect/src/index.vue";
|
||||
import agInput from "../../agInput/src/index.vue";
|
||||
import {Divider} from "element-ui";
|
||||
|
||||
export default {
|
||||
name: "agMultifunctionSearch",
|
||||
components: {
|
||||
agSelect,
|
||||
agInput,
|
||||
Divider
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [null, null];
|
||||
},
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
showExtra: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
values: [null, null],
|
||||
swidth:90,
|
||||
selectvalue:"",
|
||||
imeipopover:false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
config() {
|
||||
const input = {
|
||||
...this.$attrs
|
||||
};
|
||||
const select = {
|
||||
...this.$attrs,
|
||||
options:this.options
|
||||
};
|
||||
return {
|
||||
input,
|
||||
select,
|
||||
};
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (!Array.isArray(newVal)) {
|
||||
throw new Error("请传入数组");
|
||||
}
|
||||
let newselectValue=newVal[0];
|
||||
const find=this.options.find((f)=>f.value==newselectValue);
|
||||
if(find){
|
||||
let fontwidth=this.getStringWidth(find?.label);
|
||||
this.swidth=fontwidth>165?165:fontwidth;
|
||||
}
|
||||
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSelect(value){
|
||||
this.$emit("change", [value, this.value[1]||""]);
|
||||
},
|
||||
onInputChange(value){
|
||||
this.$emit("change", [ this.value[0] ||"",value]);
|
||||
},
|
||||
getStringWidth(text) {
|
||||
let font = "13px";
|
||||
// 创建一个隐藏的元素
|
||||
let element = document.createElement('span');
|
||||
element.style.visibility = 'hidden';
|
||||
element.style.whiteSpace = 'nowrap';
|
||||
element.style.font = font; // 设置字体样式
|
||||
element.textContent = text;
|
||||
// 将元素添加到文档中
|
||||
document.body.appendChild(element);
|
||||
// 获取元素的宽度
|
||||
let width = element.offsetWidth;
|
||||
// 移除元素
|
||||
document.body.removeChild(element);
|
||||
return width+50;
|
||||
},
|
||||
imeiiconClick(){
|
||||
this.imeipopover=!this.imeipopover;
|
||||
},
|
||||
|
||||
imeiclose(){
|
||||
this.imeipopover=false;
|
||||
},
|
||||
cleartext(){
|
||||
this.value[1]="";
|
||||
this.$set(this.value,1,"");
|
||||
},
|
||||
search(){
|
||||
this.imeipopover=false;
|
||||
this.$emit("onSrarch", this.value);
|
||||
},
|
||||
getAfterAgo(attr, prefix) {
|
||||
const config = {};
|
||||
for (const key in attr) {
|
||||
if (attr.hasOwnProperty(key) && key.startsWith(prefix)) {
|
||||
const newKey = key.substring(prefix.length);
|
||||
config[newKey] = attr[key];
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.popperOptions {
|
||||
min-width: 200px !important;
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style scoped lang='scss'>
|
||||
.ag-MultifunctionSearch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.imeiicondefault {
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
background: #f0f2f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
.imeiiconActive {
|
||||
cursor: pointer;
|
||||
color: #409eff;
|
||||
background: #e9f1fc;
|
||||
}
|
||||
.divider {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btnbox {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
::v-deep{
|
||||
.el-textarea__inner{
|
||||
border:none;
|
||||
}
|
||||
.el-input__suffix-inner{
|
||||
height:100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,9 @@
|
|||
import agMultionDatePicker from './src';
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agMultionDatePicker.install = function (Vue) {
|
||||
Vue.component(agMultionDatePicker.name, agMultionDatePicker)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agMultionDatePicker;
|
|
@ -0,0 +1,238 @@
|
|||
<template>
|
||||
<div class="ag-MultifunctionSearch">
|
||||
<ag-select
|
||||
v-bind="$attrs"
|
||||
v-on="listeners"
|
||||
:options="$attrs.options||[]"
|
||||
:value="value&&value[0]"
|
||||
@change="onSelect"
|
||||
class="ag_select_group"
|
||||
:style="{ width: `${swidth}px` }"
|
||||
>
|
||||
</ag-select>
|
||||
|
||||
<ag-date-picker
|
||||
class="ag_input_group"
|
||||
:placeholder="$attrs.placeholder||'请选择时间'"
|
||||
:disabled="$attrs.disabled"
|
||||
v-bind="$attrs"
|
||||
v-on="listeners"
|
||||
:value="value[1]"
|
||||
@change="onInputChange"
|
||||
>
|
||||
</ag-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import agSelect from "../../agSelect/src/index.vue";
|
||||
import agDatePicker from "../../agDatePicker/src/index.vue";
|
||||
|
||||
export default {
|
||||
name: "agMultionDatePicker",
|
||||
components: {
|
||||
agSelect,
|
||||
agDatePicker,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: () => {
|
||||
return [null, []];
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
values: [null, []],
|
||||
swidth:100,
|
||||
inputValue:"",
|
||||
selectvalue:"",
|
||||
imeipopover:false,
|
||||
listeners:{}
|
||||
};
|
||||
},
|
||||
model: {
|
||||
prop: 'value', // 明确指定 prop 为 'value'
|
||||
event: 'change' // 自定义事件名,用于更新 value
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (!Array.isArray(newVal)) {
|
||||
throw new Error("请传入数组");
|
||||
}
|
||||
let newselectValue=newVal[0];
|
||||
const find=this.$attrs.options&&this.$attrs.options.find((f)=>f.value==newselectValue);
|
||||
if(find){
|
||||
let fontwidth=this.getStringWidth(find.label);
|
||||
this.swidth=fontwidth>165?165:fontwidth;
|
||||
}else{
|
||||
this.swidth=100;
|
||||
}
|
||||
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted(){
|
||||
let newlist=Object.assign({},this.$listeners);
|
||||
delete newlist.change;
|
||||
delete newlist.input;
|
||||
this.listeners=newlist;
|
||||
},
|
||||
methods: {
|
||||
onSelect(value){
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", [value, this.value[1]||[]]);
|
||||
}
|
||||
},
|
||||
onInputChange(val){
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", [this.value[0] ||"",val]);
|
||||
}
|
||||
},
|
||||
getStringWidth(text) {
|
||||
let font = "13px";
|
||||
// 创建一个隐藏的元素
|
||||
let element = document.createElement('span');
|
||||
element.style.visibility = 'hidden';
|
||||
element.style.whiteSpace = 'nowrap';
|
||||
element.style.font = font; // 设置字体样式
|
||||
element.textContent = text;
|
||||
// 将元素添加到文档中
|
||||
document.body.appendChild(element);
|
||||
// 获取元素的宽度
|
||||
let width = element.offsetWidth;
|
||||
// 移除元素
|
||||
document.body.removeChild(element);
|
||||
return width+50;
|
||||
},
|
||||
imeiiconClick(){
|
||||
this.imeipopover=!this.imeipopover;
|
||||
},
|
||||
|
||||
imeiclose(){
|
||||
this.imeipopover=false;
|
||||
},
|
||||
cleartext(){
|
||||
this.value[1]=[];
|
||||
this.$set(this.value,1,[]);
|
||||
},
|
||||
search(){
|
||||
this.imeipopover=false;
|
||||
if(this.$listeners.onSrarch){
|
||||
this.$emit("onSrarch", this.value);
|
||||
}
|
||||
|
||||
},
|
||||
getAfterAgo(attr, prefix) {
|
||||
const config = {};
|
||||
for (const key in attr) {
|
||||
if (attr.hasOwnProperty(key) && key.startsWith(prefix)) {
|
||||
const newKey = key.substring(prefix.length);
|
||||
config[newKey] = attr[key];
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.popperOptions {
|
||||
min-width: 200px !important;
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style scoped lang='scss'>
|
||||
.ag-MultifunctionSearch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.imeiicondefault {
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
background: #f0f2f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
.imeiiconActive {
|
||||
cursor: pointer;
|
||||
color: #409eff;
|
||||
background: #e9f1fc;
|
||||
}
|
||||
.divider {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btnbox {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
::v-deep{
|
||||
.ag_select_group{
|
||||
.el-input__inner{
|
||||
border:1px solid #e5e5e5;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
outline:none;
|
||||
&:focus{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-range-editor.is-active, .el-range-editor.is-active:hover, .el-select .el-input.is-focus .el-input__inner{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
.el-range-editor.el-input__inner{
|
||||
border:1px solid #e5e5e5;
|
||||
border-left:0px;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-left:none;
|
||||
outline:none;
|
||||
&:focus{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
.ag_input_group{
|
||||
.el-input__inner{
|
||||
border:1px solid #e5e5e5;
|
||||
border-left:0px;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-left:none;
|
||||
outline:none;
|
||||
&:focus{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-select{
|
||||
.el-input{
|
||||
&.is-focus{
|
||||
.el-input__inner{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
.el-input__inner{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-textarea__inner{
|
||||
border:none;
|
||||
}
|
||||
.el-input__suffix-inner{
|
||||
height:100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,9 @@
|
|||
import agMultionInput from './src'
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agMultionInput.install = function (Vue) {
|
||||
Vue.component(agMultionInput.name, agMultionInput)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agMultionInput
|
|
@ -0,0 +1,294 @@
|
|||
<template>
|
||||
<div class="ag-MultifunctionSearch">
|
||||
<ag-select
|
||||
v-bind="$attrs"
|
||||
v-on="listeners"
|
||||
:options="$attrs.options||[]"
|
||||
:value="value&&value[0]"
|
||||
@change="onSelect"
|
||||
class="ag_select_group"
|
||||
:style="{ width: `${swidth+20}px` }"
|
||||
>
|
||||
</ag-select>
|
||||
<ag-input
|
||||
v-if="!showExtra"
|
||||
class="ag_input_group"
|
||||
:placeholder="$attrs.placeholder||'请输入内容'"
|
||||
:disabled="$attrs.disabled||imeipopover"
|
||||
v-bind="$attrs"
|
||||
v-on="listeners"
|
||||
:value="value[1]"
|
||||
@input="onInputChange"
|
||||
|
||||
>
|
||||
<template slot="prefix" >
|
||||
|
||||
</template>
|
||||
</ag-input>
|
||||
<el-popover
|
||||
v-if="showExtra"
|
||||
placement="bottom"
|
||||
trigger="manual"
|
||||
ref="popover"
|
||||
popper-class="popperOptions"
|
||||
v-model="imeipopover"
|
||||
>
|
||||
<template slot="reference">
|
||||
<ag-input
|
||||
class="ag_input_group"
|
||||
:placeholder="$attrs.placeholder||'请输入内容'"
|
||||
:disabled="$attrs.disabled||imeipopover"
|
||||
v-bind="$attrs"
|
||||
v-on="listeners"
|
||||
:value="value&&value[1]"
|
||||
@input="onInputChange"
|
||||
>
|
||||
<template slot="suffix" v-if="showExtra">
|
||||
<i
|
||||
class="iconfont icon-icon-piliangcaozuo imeiicondefault"
|
||||
:class="imeipopover && 'imeiiconActive'"
|
||||
style="font-size: 12px;"
|
||||
@click.prevent="imeiiconClick"
|
||||
></i>
|
||||
</template>
|
||||
</ag-input>
|
||||
</template>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="12"
|
||||
:value="value&&value[1]"
|
||||
placeholder="一行一项,最多支持200行"
|
||||
resize="none"
|
||||
border="none"
|
||||
class="textareainput"
|
||||
@input="onInputChange"
|
||||
/>
|
||||
<divider class="divider"></divider>
|
||||
<div class="btnbox">
|
||||
<div>
|
||||
<el-button size="mini" @click="imeiclose"
|
||||
>关闭</el-button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-button size="mini" @click="cleartext"
|
||||
>清空</el-button
|
||||
>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="primary"
|
||||
plain
|
||||
@click="search"
|
||||
>查询</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import agSelect from "../../agSelect/src/index.vue";
|
||||
import agInput from "../../agInput/src/index.vue";
|
||||
import {Divider} from "element-ui";
|
||||
|
||||
export default {
|
||||
name: "agMultionInput",
|
||||
components: {
|
||||
agSelect,
|
||||
agInput,
|
||||
Divider
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [null, ''];
|
||||
},
|
||||
},
|
||||
showExtra: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
values: [null, ""],
|
||||
swidth:120,
|
||||
inputValue:"",
|
||||
selectvalue:"",
|
||||
imeipopover:false,
|
||||
listeners:{}
|
||||
};
|
||||
},
|
||||
model: {
|
||||
prop: 'value', // 明确指定 prop 为 'value'
|
||||
event: 'change' // 自定义事件名,用于更新 value
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (!Array.isArray(newVal)) {
|
||||
throw new Error("请传入数组");
|
||||
}
|
||||
let newselectValue=newVal[0];
|
||||
const find=newselectValue&&newselectValue!=""&&this.$attrs.options&&this.$attrs.options.find((f)=>f.value==newselectValue);
|
||||
if(find){
|
||||
let fontwidth=this.getStringWidth(find.label);
|
||||
this.swidth=fontwidth>165?165:fontwidth;
|
||||
}else{
|
||||
this.swidth=120;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted(){
|
||||
let newlist=Object.assign({},this.$listeners);
|
||||
delete newlist.change;
|
||||
delete newlist.input;
|
||||
this.listeners=newlist;
|
||||
},
|
||||
methods: {
|
||||
onSelect(value){
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", [value||"", this.value[1]||""]);
|
||||
}
|
||||
|
||||
},
|
||||
onInputChange(val){
|
||||
if(this.$listeners.change){
|
||||
this.$emit("change", [this.value[0]||"",val]);
|
||||
}
|
||||
},
|
||||
getStringWidth(text) {
|
||||
let font = "13px";
|
||||
// 创建一个隐藏的元素
|
||||
let element = document.createElement('span');
|
||||
element.style.visibility = 'hidden';
|
||||
element.style.whiteSpace = 'nowrap';
|
||||
element.style.font = font; // 设置字体样式
|
||||
element.textContent = text;
|
||||
// 将元素添加到文档中
|
||||
document.body.appendChild(element);
|
||||
// 获取元素的宽度
|
||||
let width = element.offsetWidth;
|
||||
// 移除元素
|
||||
document.body.removeChild(element);
|
||||
return width+50;
|
||||
},
|
||||
imeiiconClick(){
|
||||
this.imeipopover=!this.imeipopover;
|
||||
},
|
||||
|
||||
imeiclose(){
|
||||
this.imeipopover=false;
|
||||
},
|
||||
cleartext(){
|
||||
this.value[1]="";
|
||||
this.$set(this.value,1,"");
|
||||
},
|
||||
search(){
|
||||
this.imeipopover=false;
|
||||
if(this.$listeners.onSrarch){
|
||||
this.$emit("onSrarch", this.value);
|
||||
}
|
||||
|
||||
},
|
||||
getAfterAgo(attr, prefix) {
|
||||
const config = {};
|
||||
for (const key in attr) {
|
||||
if (attr.hasOwnProperty(key) && key.startsWith(prefix)) {
|
||||
const newKey = key.substring(prefix.length);
|
||||
config[newKey] = attr[key];
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.popperOptions {
|
||||
min-width: 200px !important;
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style scoped lang='scss'>
|
||||
.ag-MultifunctionSearch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.imeiicondefault {
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
background: #f0f2f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
.imeiiconActive {
|
||||
cursor: pointer;
|
||||
color: #409eff;
|
||||
background: #e9f1fc;
|
||||
}
|
||||
.divider {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btnbox {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
::v-deep{
|
||||
|
||||
.ag_select_group{
|
||||
.el-input__inner{
|
||||
border:1px solid #e5e5e5;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
outline:none;
|
||||
&:focus{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ag_input_group{
|
||||
.el-input__inner{
|
||||
border:1px solid #e5e5e5;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-left:none;
|
||||
outline:none;
|
||||
&:focus{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-select{
|
||||
.el-input{
|
||||
&.is-focus{
|
||||
.el-input__inner{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
.el-input__inner{
|
||||
border-color:#e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-textarea__inner{
|
||||
border:none;
|
||||
}
|
||||
.el-input__suffix-inner{
|
||||
height:100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,9 @@
|
|||
import agMutionCheckbox from './src';
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agMutionCheckbox.install = function (Vue) {
|
||||
Vue.component(agMutionCheckbox.name, agMutionCheckbox);
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agMutionCheckbox;
|
|
@ -0,0 +1,430 @@
|
|||
<template>
|
||||
<div class="ag-multion-checkbox">
|
||||
<el-dropdown
|
||||
size="small"
|
||||
trigger="click"
|
||||
ref="multioncheckref"
|
||||
@click.native="checkeddown"
|
||||
:class="{ 'el-dropdown_active': !down }"
|
||||
@visible-change="dropdownchange"
|
||||
>
|
||||
<span class="el-dropdown-link">
|
||||
<span>
|
||||
<span :class="{ color: checkedList.length }">{{ checkedList.length==0?placeholder||'请选择':dropdownvalue }}</span
|
||||
><span class="list-length" v-if="valuelength >= 1"
|
||||
>+ {{ valuelength }}</span
|
||||
></span
|
||||
><i
|
||||
v-if="dropdownvalue == ''"
|
||||
class="el-icon-arrow-up el-icon--right"
|
||||
:class="{ 'rotate-arrow': down }"
|
||||
></i>
|
||||
<i v-else class="el-icon-close el-icon--right" @click.stop.prevent="clear"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="seek"
|
||||
size="small"
|
||||
class="el_input"
|
||||
@input="inputblur"
|
||||
@keydown.enter.prevent="confirm()"
|
||||
>
|
||||
<i slot="prefix" class="el-input__icon el-icon-search"></i>
|
||||
</el-input>
|
||||
<div v-if="dataList && dataList.length" class="checkbox-group">
|
||||
<div v-if="dataList && dataList.length > 1" class="all-checked">
|
||||
<el-checkbox
|
||||
:indeterminate="isIndeterminate"
|
||||
v-model="checkAll"
|
||||
@change="handleCheckAllChange"
|
||||
>全选</el-checkbox
|
||||
>
|
||||
/
|
||||
<span class="invertstatus" @click="handleCheckAllChange(!checkAll)">反选</span>
|
||||
</div>
|
||||
<el-checkbox-group
|
||||
class="checked-list"
|
||||
:class="{ 'top-height': dataList && dataList.length <= 1 }"
|
||||
v-model="checkedList"
|
||||
@change="handleCheckedCitiesChange"
|
||||
>
|
||||
<div v-for="(el, id) in dataList" :key="id" class="setScore">
|
||||
<el-checkbox :label="el.value">{{ el.label }}</el-checkbox>
|
||||
<span @click="confirm(el, 'only')">仅筛选此项</span>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<div v-else class="nothing">暂无数据</div>
|
||||
<div class="btnbox">
|
||||
<div>
|
||||
<el-button size="mini" @click="cancel">取消</el-button>
|
||||
<el-button size="mini" type="primary" plain @click="confirm()"
|
||||
>确定</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { nextTick } from 'vue';
|
||||
export default {
|
||||
props: ["datas", "placeholder", "value"],
|
||||
name: "AgMutionCheckbox",
|
||||
data() {
|
||||
return {
|
||||
seek: "",
|
||||
dropdownvalue:"",
|
||||
valuelength: 0,
|
||||
down: true,
|
||||
checkAll: false,
|
||||
checkedList: [],
|
||||
dataList: [
|
||||
|
||||
], //渲染数据
|
||||
isIndeterminate: false,
|
||||
retract: false,
|
||||
olddatas:[
|
||||
],
|
||||
oldvalue:[]
|
||||
};
|
||||
},
|
||||
model: {
|
||||
prop: 'value', // 明确指定 prop 为 'value'
|
||||
event: 'onSearch' // 自定义事件名,用于更新 value
|
||||
},
|
||||
mounted() {
|
||||
if(this.datas&&Array.isArray(this.datas)){
|
||||
this.dataList = this.datas;
|
||||
this.olddatas=Object.assign([],this.datas);
|
||||
this.checkedList = []; //清空旧值-解决出现累加问题
|
||||
if (this.checkAll && this.dataList) {
|
||||
this.checkedList=this.dataList.map((e) =>e.value);
|
||||
this.confirm();
|
||||
}
|
||||
if(this.value){
|
||||
this.checkedList=this.value;
|
||||
const filters=this.olddatas.filter((f)=>{
|
||||
return this.checkedList.find((c)=>c==f.value);
|
||||
});
|
||||
if(filters.length>0){
|
||||
const [onedatas,...otherdatas]=filters;
|
||||
this.valuelength=otherdatas.length;
|
||||
this.dropdownvalue=onedatas.label;
|
||||
if(filters.length==this.olddatas.length){
|
||||
this.checkAll=true;
|
||||
this.isIndeterminate=false;
|
||||
}else{
|
||||
this.checkAll=false;
|
||||
this.isIndeterminate=true;
|
||||
}
|
||||
}else{
|
||||
this.valuelength=0;
|
||||
this.dropdownvalue="";
|
||||
this.checkAll=false;
|
||||
this.isIndeterminate=false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
this.olddatas=Object.assign([],this.dataList);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
datas: {
|
||||
handler(val) {
|
||||
if(val&&Array.isArray(val)){
|
||||
this.dataList = val;
|
||||
this.olddatas=Object.assign([],val);
|
||||
this.checkedList = []; //清空旧值-解决出现累加问题
|
||||
if (this.checkAll&&this.dataList) {
|
||||
this.checkedList=this.dataList.map((e) =>e.value);
|
||||
this.confirm();
|
||||
}
|
||||
if(this.value){
|
||||
this.checkedList=this.value;
|
||||
const filters=this.olddatas.filter((f)=>{
|
||||
return this.checkedList.find((c)=>c==f.value);
|
||||
});
|
||||
if(filters.length>0){
|
||||
const [onedatas,...otherdatas]=filters;
|
||||
this.valuelength=otherdatas.length;
|
||||
this.dropdownvalue=onedatas.label;
|
||||
if(filters.length==this.olddatas.length){
|
||||
this.checkAll=true;
|
||||
this.isIndeterminate=false;
|
||||
}else{
|
||||
this.checkAll=false;
|
||||
this.isIndeterminate=true;
|
||||
}
|
||||
}else{
|
||||
this.valuelength=0;
|
||||
this.dropdownvalue="";
|
||||
this.checkAll=false;
|
||||
this.isIndeterminate=false;
|
||||
}
|
||||
}
|
||||
} else{
|
||||
this.olddatas=Object.assign([],this.dataList);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clear(){
|
||||
this.checkedList = [];
|
||||
this.valuelength=0;
|
||||
this.dropdownvalue="";
|
||||
this.isIndeterminate = false;
|
||||
this.checkAll=false;
|
||||
this.nextTick(()=>{
|
||||
this.$refs.multioncheckref.hide();
|
||||
});
|
||||
},
|
||||
checkeddown(val){
|
||||
this.oldvalue={list:this.checkedList,checkAll:this.checkAll,isIndeterminate:this.isIndeterminate};
|
||||
},
|
||||
dropdownchange(){
|
||||
this.down = !this.down;
|
||||
},
|
||||
inputblur(val){
|
||||
this.dataList=this.olddatas.filter((f)=>f.label.indexOf(val)>-1);
|
||||
|
||||
},
|
||||
handleCheckAllChange(val){
|
||||
this.checkedList = val ? this.olddatas.map((h)=>h.value) : [];
|
||||
this.isIndeterminate = false;
|
||||
this.checkAll=val;
|
||||
},
|
||||
confirm(e,type){
|
||||
if(e&&type=="only"){
|
||||
this.checkedList=[e.value];
|
||||
if(this.olddatas.length!=1){
|
||||
this.isIndeterminate=true;
|
||||
this.checkAll=false;
|
||||
}else{
|
||||
this.isIndeterminate=false;
|
||||
this.checkAll=true;
|
||||
}
|
||||
|
||||
const filters=this.olddatas.filter((f)=>{
|
||||
return f.value==e.value
|
||||
});
|
||||
if(this.$listeners.onSearch){
|
||||
this.$emit("onSearch",[e.value]);
|
||||
}
|
||||
if(filters.length==0){
|
||||
this.valuelength=0;
|
||||
this.dropdownvalue="";
|
||||
this.$refs.multioncheckref.hide();
|
||||
return;
|
||||
}
|
||||
const [onedatas,...otherdatas]=filters;
|
||||
this.valuelength=otherdatas.length;
|
||||
this.dropdownvalue=onedatas.label;
|
||||
}else{
|
||||
if(this.checkedList.length==0){
|
||||
this.valuelength=0;
|
||||
this.dropdownvalue="";
|
||||
if(this.$listeners.onSearch){
|
||||
this.$emit("onSearch",this.checkedList);
|
||||
}
|
||||
this.$refs.multioncheckref.hide();
|
||||
return;
|
||||
}
|
||||
const filters=this.olddatas.filter((f)=>{
|
||||
return this.checkedList.find((c)=>c==f.value);
|
||||
});
|
||||
const [onedatas,...otherdatas]=filters;
|
||||
this.valuelength=otherdatas.length;
|
||||
this.dropdownvalue=onedatas.label;
|
||||
if(this.$listeners.onSearch){
|
||||
this.$emit("onSearch",this.checkedList);
|
||||
}
|
||||
}
|
||||
this.$refs.multioncheckref.hide();
|
||||
},
|
||||
handleCheckedCitiesChange(val){
|
||||
if(val.length>0){
|
||||
if(val.length==this.olddatas.length){
|
||||
this.isIndeterminate = false;
|
||||
this.checkAll=true;
|
||||
}else{
|
||||
this.isIndeterminate = true;
|
||||
}
|
||||
}else{
|
||||
this.isIndeterminate = false;
|
||||
this.checkAll=false;
|
||||
}
|
||||
},
|
||||
cancel(){
|
||||
this.checkedList=this.oldvalue.list;
|
||||
this.isIndeterminate=this.oldvalue.isIndeterminate;
|
||||
this.checkAll=this.oldvalue.checkAll;
|
||||
|
||||
this.$refs.multioncheckref.hide();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .el_input {
|
||||
padding: 0 10px;
|
||||
.el-input__inner {
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
.el-input__inner:hover {
|
||||
border-bottom: 1px solid #409eff;
|
||||
}
|
||||
}
|
||||
.el-dropdown {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.el-dropdown:hover {
|
||||
border: 1px solid #c0c4cc;
|
||||
}
|
||||
.el-dropdown_active {
|
||||
border: 1px solid #409eff;
|
||||
}
|
||||
.el-dropdown_active:hover {
|
||||
border: 1px solid #409eff;
|
||||
}
|
||||
.el-icon-arrow-up {
|
||||
transform: rotate(0deg);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.rotate-arrow {
|
||||
transform: rotate(180deg);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.el-dropdown-menu {
|
||||
min-width: 400px;
|
||||
padding: 10px 0 0 0;
|
||||
}
|
||||
.checkbox-group {
|
||||
overflow: hidden;
|
||||
padding: 5px 0px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.all-checked {
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
.invertstatus:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
.checked-list {
|
||||
max-height: 180px;
|
||||
margin-top:5px;
|
||||
overflow-y: auto;
|
||||
padding: 5px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.top-height {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.el-checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.el-checkbox {
|
||||
margin-right: 0px !important;
|
||||
padding: 5px 0px 5px 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.btnbox {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
border-top: 1px solid #dcdfe6;
|
||||
}
|
||||
.el-dropdown-link {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height:100%;
|
||||
min-width: 180px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #c0c4cc;
|
||||
cursor: pointer;
|
||||
}
|
||||
.list-length {
|
||||
padding: 3px 7px;
|
||||
margin-left: 10px;
|
||||
border-radius: 4px;
|
||||
color: #33333379;
|
||||
background-color: #dcdfe6;
|
||||
}
|
||||
.color {
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
}
|
||||
:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
.nothing {
|
||||
min-height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
.el-icon-close {
|
||||
opacity: 0;
|
||||
}
|
||||
.el-icon-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.setScore {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
span {
|
||||
display: none;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
::v-deep .el-checkbox {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.setScore:hover {
|
||||
background-color: rgba(192, 196, 204, 0.267);
|
||||
span {
|
||||
display: block;
|
||||
color: #409eff;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,4 +1,4 @@
|
|||
import agNumberRange from './src'
|
||||
import agNumberRange from './src';
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agNumberRange.install = function (Vue) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
@input="handleStartInput"
|
||||
@blur="handleInputBlur"
|
||||
></el-input>
|
||||
<span class="separator">{{ rangeSeparator }}</span>
|
||||
<span class="separator">{{ rangeSeparator||'-'}}</span>
|
||||
<el-input
|
||||
:style="{ width: width + 'px' }"
|
||||
:size="size"
|
||||
|
@ -63,6 +63,9 @@ export default {
|
|||
// 结束数值
|
||||
endValue: "",
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
watch: {
|
||||
value(newValue) {
|
||||
|
|
|
@ -10,17 +10,14 @@
|
|||
<ag-row>
|
||||
<ag-col :span="12" v-for="(item,index) in inputs" :key="index">
|
||||
<el-form-item :label="item.label" :rules="item.rules" :prop="item.name">
|
||||
<ag-input :placeholder="item.placeholder" :value="item.value||''" closeable v-if="item.elem=='el-input'" @change="onSelect($event,item,index)"/>
|
||||
<ag-select :placeholder="item.placeholder" :value="item.value||''" closeable v-if="item.elem=='el-select'" :options="item.options" style="width:100%" @change="onSelect($event,item,index)"/>
|
||||
</el-form-item>
|
||||
</ag-col>
|
||||
<ag-col :offset="16" :span="8">
|
||||
<el-form-item >
|
||||
<el-button size="small" @click="onCancel">取消</el-button>
|
||||
<el-button size="small" type="primary" @click="onQuery">查询</el-button>
|
||||
<ag-select :placeholder="item.placeholder" :value="item.value||''" closeable :options="item.options" style="width:100%" @change="onSelect($event,item,index)"/>
|
||||
</el-form-item>
|
||||
</ag-col>
|
||||
</ag-row>
|
||||
<div class="footerbox">
|
||||
<el-button size="small" @click="onCancel">取消</el-button>
|
||||
<el-button size="small" type="primary" @click="onQuery">查询</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-popover>
|
||||
</div>
|
||||
|
@ -55,10 +52,28 @@
|
|||
return [];
|
||||
},
|
||||
},
|
||||
props:{
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
lazyLoad (node, resolve) {
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
model: {
|
||||
prop: 'values', // 明确指定 prop 为 'value'
|
||||
event: 'onSearch' // 自定义事件名,用于更新 value
|
||||
},
|
||||
mounted(){
|
||||
let newinput=this.inputs.map((g)=>g.label);
|
||||
this.placeholder="请选择"+newinput.join("/");
|
||||
if(this.props.lazyLoad){
|
||||
this.props.lazyLoad({level:0,pathLabels:this.values,value:""},(datas)=>{
|
||||
this.inputs[index+1].options=datas;
|
||||
});
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -66,39 +81,49 @@
|
|||
placeholderValue:"",
|
||||
placeholder:"请选择",
|
||||
popState:false,
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onReset(){
|
||||
this.values={};
|
||||
this.$emit('onSearch',this.values);
|
||||
},
|
||||
onSelect(value,item,index){
|
||||
item.value=value;
|
||||
this.$set(this.inputs,index,item);
|
||||
let newvalues={};
|
||||
|
||||
let newplaceholderValue=[];
|
||||
this.inputs.map((g)=>{
|
||||
if(g.value&&g.name){
|
||||
newvalues[g.name]=g.value;
|
||||
g.options.find((f)=>f.value==g.value).label&&(newplaceholderValue.push(g.options.find((f)=>f.value==g.value).label));
|
||||
this.inputs.map((g)=>{
|
||||
if(g.value&&g.name){
|
||||
newvalues[g.name]=g.value;
|
||||
g.options.find((f)=>f.value==g.value).label&&(newplaceholderValue.push(g.options.find((f)=>f.value==g.value).label));
|
||||
}
|
||||
});
|
||||
this.values=newvalues;
|
||||
if(this.$listeners.change){
|
||||
this.$emit('change',newvalues);
|
||||
}
|
||||
});
|
||||
this.$emit('change',newvalues);
|
||||
this.values=newvalues;
|
||||
this.placeholderValue=newplaceholderValue.join("/")
|
||||
if(this.props.lazyLoad){
|
||||
this.props.lazyLoad({level:index+1,pathLabels:newvalues,value},(datas)=>{
|
||||
this.inputs[index+1].options=datas;
|
||||
});
|
||||
}
|
||||
this.placeholderValue=newplaceholderValue.join("/")
|
||||
},
|
||||
onCancel(){
|
||||
this.popState=false;
|
||||
this.$emit('cancel');
|
||||
if(this.$listeners.onCancel){
|
||||
this.$emit('onCancel');
|
||||
}
|
||||
},
|
||||
onQuery(){
|
||||
console.log(this.$refs.queryformref,'this.$refs.queryformref');
|
||||
if(this.$refs.queryformref){
|
||||
this.$refs.queryformref.validate((valid) => {
|
||||
console.log(valid,"valid");
|
||||
if (valid) {
|
||||
this.$emit('onSearch',this.values);
|
||||
this.popState=false;
|
||||
} else {
|
||||
console.log('error submit!!');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
@ -120,6 +145,12 @@
|
|||
caret-color: transparent; /* 隐藏光标 */
|
||||
}
|
||||
}
|
||||
.footerbox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-top:5px;
|
||||
}
|
||||
::v-deep {
|
||||
.el-form-item--small .el-form-item__label{
|
||||
line-height: 40px;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import agSearch from './src';
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agSearch.install = function (Vue) {
|
||||
Vue.component(agSearch.name, agSearch);
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agSearch;
|
|
@ -0,0 +1,229 @@
|
|||
<template>
|
||||
<el-form v-bind="$attrs" v-on="$listeners" :model="formValue" ref="formref">
|
||||
<ag-row class="searchbox">
|
||||
<ag-col v-for="item,index in data" :key="index" :span="item.span||24">
|
||||
<el-form-item :prop="item.enName" >
|
||||
<slot :name="item.soltName" v-if="item.soltName" :row="item"/>
|
||||
<div class="contentbox" v-else>
|
||||
<ag-input v-model="formValue[item.enName]" type="textarea" v-bind="item" v-if="item.type=='ag-textarea'" size="small" clearable></ag-input>
|
||||
<ag-input v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-input'" size="small" clearable></ag-input>
|
||||
<ag-date-picker v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-date-picker'" size="small" clearable/>
|
||||
<ag-select v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-select'" size="small" clearable/>
|
||||
<el-radio-group v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-radio'&&formValue[item.enName]" size="small" clearable>
|
||||
<el-radio :label="it.value" v-for="it,index in item.options" :key="index">{{it.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-checkbox-group v-bind="item" v-if="item.type=='ag-checkbox'&&formValue[item.enName]" v-model="formValue[item.enName]" size="small" clearable>
|
||||
<el-checkbox v-for="it,index in item.options" :label="it.value" :key="index">{{it.label}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-input-number v-model="formValue[item.enName]" v-bind="item" v-if="item.type=='ag-input-number'" clearable></el-input-number>
|
||||
<el-cascader v-model="formValue[item.enName]" v-bind="item" size="small" v-if="item.type=='ag-cascader'" clearable :style="{width:'100%'}"></el-cascader>
|
||||
<el-switch
|
||||
v-model="formValue[item.enName]"
|
||||
v-bind="item" size="small" v-if="item.type=='ag-switch'&&formValue[item.enName]" >
|
||||
</el-switch>
|
||||
<el-slider v-model="formValue[item.enName]"
|
||||
v-bind="item" size="small" v-if="item.type=='ag-slider'"></el-slider>
|
||||
<el-time-select
|
||||
:style="{width:'100%'}"
|
||||
clearable
|
||||
v-model="formValue[item.enName]"
|
||||
v-bind="item" size="small"
|
||||
v-if="item.type=='ag-time-select'"
|
||||
:picker-options="item.options">
|
||||
</el-time-select>
|
||||
<ag-upload v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-upload'" clear isPre></ag-upload>
|
||||
<el-rate v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-rate'" size="small"></el-rate>
|
||||
<agColorPicker v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-color-picker'" size="small">
|
||||
</agColorPicker>
|
||||
<el-transfer :data="item.data" v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-transfer'" size="small"></el-transfer>
|
||||
<agNumberRange v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-numberRange'" size="small" clearable/>
|
||||
<ag-multion-input v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-multion-input'" size="small" clearable/>
|
||||
<agQuery v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-query'" size="small" clearable/>
|
||||
<ag-mution-checkbox :datas="item.datas" v-bind="item" :placeholder="item.placeholder" v-model="formValue[item.enName]" v-if="item.type=='ag-mution-checkbox'" size="small"> </ag-mution-checkbox>
|
||||
<ag-multion-date-picker v-bind="item" v-model="formValue[item.enName]" v-if="item.type=='ag-multion-datte-picker'" size="small"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</ag-col>
|
||||
<ag-col :span="4">
|
||||
<el-button @click="onSubmit" type="primary" size="small" class="submitbtn">
|
||||
{{submittitle||'查询'}}
|
||||
</el-button>
|
||||
<el-button @click="onRest" size="small" class="submitbtn">
|
||||
重置
|
||||
</el-button>
|
||||
</ag-col>
|
||||
</ag-row>
|
||||
</el-form>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
|
||||
import agInput from './../../agInput/src/index.vue';
|
||||
import agDatePicker from './../../agDatePicker/src/index.vue';
|
||||
import agSelect from './../../agSelect/src/index.vue';
|
||||
import agRow from './../../agRow/src/index.vue';
|
||||
import agCol from './../../agCol/src/index.vue';
|
||||
import agUpload from './../../agUpload/src/index.vue';
|
||||
import agColorPicker from './../../agColorPicker/src/index.vue';
|
||||
import agNumberRange from './../../agNumberRange/src/index.vue';
|
||||
import agMultionInput from './../../agMultionInput/src/index.vue';
|
||||
import agQuery from './../../agQuery/src/index.vue';
|
||||
import agMultionDatePicker from '../../agMultionDatePicker';
|
||||
|
||||
|
||||
export default{
|
||||
name:"agSearch",
|
||||
components:{
|
||||
agMultionDatePicker,
|
||||
agInput:agInput,
|
||||
agDatePicker,
|
||||
agSelect,
|
||||
agRow,
|
||||
agCol,
|
||||
agUpload:agUpload,
|
||||
agColorPicker,
|
||||
agNumberRange,
|
||||
agMultionInput,
|
||||
agQuery
|
||||
},
|
||||
props:{
|
||||
submittitle:{
|
||||
type:String,
|
||||
default:'查询'
|
||||
},
|
||||
data:{
|
||||
type:Array,
|
||||
default(){
|
||||
return []
|
||||
}
|
||||
},
|
||||
span:{
|
||||
type:Number,
|
||||
default:24
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
formValue:{
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
model:{
|
||||
prop:'value',
|
||||
event:{
|
||||
'onSubmit':'submit',
|
||||
'onRest':'rest'
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.formValue=this.$attrs.value;
|
||||
setTimeout(()=>{
|
||||
this.$refs.formref.clearValidate();
|
||||
},1);
|
||||
if(this.$refs.formref){
|
||||
for(const key in this.$refs.formref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.formref[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
watch:{
|
||||
value(val){
|
||||
this.formValue = val;
|
||||
setTimeout(()=>{
|
||||
this.$refs.formref.clearValidate();
|
||||
},1);
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
onSubmit(){
|
||||
if(this.$listeners.onSearch){
|
||||
this.$emit('onSearch',this.formValue);
|
||||
}
|
||||
},
|
||||
onRest(){
|
||||
Object.keys(this.formValue).map((key,index)=>{
|
||||
let itemvalue=Object.values(this.formValue)[index];
|
||||
if(typeof(itemvalue)=="string"||typeof(itemvalue)=="number"){
|
||||
this.formValue[key]=null;
|
||||
}else{
|
||||
this.formValue[key]=[];
|
||||
}
|
||||
});
|
||||
setTimeout(()=>{
|
||||
this.$refs.formref.clearValidate();
|
||||
},1);
|
||||
if(this.$listeners.onRest){
|
||||
this.$emit('onRest',this.formValue);
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.searchbox{
|
||||
align-items: center;
|
||||
}
|
||||
.footerbox{
|
||||
margin-top:12px;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
.submitbtn{
|
||||
width:200px;
|
||||
}
|
||||
}
|
||||
.el-form--inline{
|
||||
.el-form-item{
|
||||
display:flex;
|
||||
}
|
||||
.el-form-item__content{
|
||||
flex:1;
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
.contentbox{
|
||||
width:100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
.flexcenter{
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
::v-deep{
|
||||
.el-form--inline{
|
||||
.el-form-item{
|
||||
display:flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.el-form-item__content{
|
||||
display:flex;
|
||||
flex:1;
|
||||
width:100%;
|
||||
margin-left:0;
|
||||
align-items: center;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.el-form-item{
|
||||
width:100%;
|
||||
margin-bottom: 0px;
|
||||
line-height:1;
|
||||
}
|
||||
.el-form-item__content{
|
||||
flex:1;
|
||||
display:flex;
|
||||
width:100%;
|
||||
align-items: center;
|
||||
margin-left:0!important;
|
||||
margin-bottom: 0px;
|
||||
line-height:1;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,23 +1,21 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-select
|
||||
class="ag_select"
|
||||
:style="{ width: `100%` }"
|
||||
:value="selectValue"
|
||||
v-bind="attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<slot />
|
||||
<slot name="prefix" slot="prefix" />
|
||||
<slot name="empty" slot="empty" />
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-select
|
||||
class="ag_select"
|
||||
:style="{ width: `100%` }"
|
||||
:value="selectValue"
|
||||
ref="apselectref"
|
||||
:size="$attrs.size||'small'"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<slot v-for="(_,name) in $slots" :name="name" :slot="name"> </slot>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -43,6 +41,15 @@ export default {
|
|||
selectValue:""
|
||||
};
|
||||
},
|
||||
mounted(){
|
||||
if(this.$refs.apselectref){
|
||||
for(const key in this.$refs.apselectref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.apselectref[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal) {
|
||||
|
@ -57,16 +64,6 @@ export default {
|
|||
immediate: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
attrs() {
|
||||
return {
|
||||
size: "small",
|
||||
clearable: true,
|
||||
filterable: true,
|
||||
...this.$attrs,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
};
|
||||
|
@ -76,6 +73,7 @@ export default {
|
|||
::v-deep {
|
||||
.ag_select{
|
||||
min-width: 90px;
|
||||
width:100%;
|
||||
}
|
||||
.el-input__icon {
|
||||
font-size: 16px !important;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import agTable from './src';
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agTable.install = function (Vue) {
|
||||
Vue.component(agTable.name, agTable)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agTable;
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<div class="agtablebox">
|
||||
<el-table v-bind="$attrs" v-on="$listeners" :data="data" size="small" :header-cell-style="$attrs.headerCellStyle||{backgroundColor:'#f7f7f7'}" ref="tableref">
|
||||
<el-table-column v-for="item,index in columns" :key="index" v-bind="item">
|
||||
<template slot-scope="scope">
|
||||
<div v-if="item.soltName">
|
||||
<slot :name="item.soltName" :row="scope.row" >
|
||||
</slot>
|
||||
</div>
|
||||
<div v-else>
|
||||
{{scope.row[item.prop]}}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="agtablefooter">
|
||||
<el-pagination
|
||||
ref="paginationref"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page.sync="currentPage"
|
||||
:page-sizes="pageSizes||[10,100,200,500]"
|
||||
:page-size="pageSize"
|
||||
layout="sizes,prev, pager, next, jumper"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "agTable",
|
||||
props:["columns","data",'pageSize','currentPage','total','pageSizes'],
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
for(const key in this.$refs.tableref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.tableref[key];
|
||||
}
|
||||
}
|
||||
for(const key in this.$refs.paginationref){
|
||||
if(!this[key]&&key!='value'&&key!='pageSizes'){
|
||||
this[key]=this.$refs.paginationref[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(e){
|
||||
if(this.$listeners.onSizeChange){
|
||||
this.$emit('onSizeChange',e);
|
||||
}
|
||||
},
|
||||
handleCurrentChange(e){
|
||||
if(this.$listeners.onCurrentChange){
|
||||
this.$emit('onCurrentChange',e);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.agtablebox{
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
height:100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.agtablefooter{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding:12px;
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.el-table {
|
||||
width: 100%;
|
||||
height:100%;
|
||||
}
|
||||
.el-table__empty-block{
|
||||
min-height:300px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,4 +6,4 @@ agTabs.install = function (Vue) {
|
|||
}
|
||||
|
||||
// 导出组件
|
||||
export default agTabs
|
||||
export default agTabs;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-tabs class="ag-tabs" v-bind="$attrs" v-on="$listeners">
|
||||
<el-tabs class="ag-tabs" v-bind="$attrs" v-on="$listeners" ref="tabsref">
|
||||
<slot v-if="!tabsData.length" name="default" />
|
||||
<el-tab-pane
|
||||
v-else
|
||||
|
@ -31,6 +31,13 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for(const key in this.$refs.tabsref){
|
||||
if(!this[key]&&key!='value'){
|
||||
this[key]=this.$refs.tabsref[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import agUpload from './src'
|
||||
|
||||
// 为组件提供 install 安装方法,供按需引入
|
||||
agUpload.install = function (Vue) {
|
||||
Vue.component(agUpload.name, agUpload)
|
||||
}
|
||||
|
||||
// 导出组件
|
||||
export default agUpload;
|
|
@ -0,0 +1,692 @@
|
|||
<template>
|
||||
<div class="uploadbox">
|
||||
<div class="uploadimgbox" :style="{height:width+'px'}" v-if="listType=='picture-card'">
|
||||
<div v-for="img,index in imageList" :key="index" :style="{width:width+'px'}" :draggable="dragmove" class="imgitem" :class="dragmove&&dragmoveclass" @dragstart="onDragstart" @dragenter="onDragenter" @dragover="onDragover" @dragend="onDragend" @dragleave="onMouseup" >
|
||||
<slot name="file" :file="img">
|
||||
<img :src="img.url" class="img" v-if="img.type.indexOf('image')>-1"/>
|
||||
<div v-else class="filetext">
|
||||
<div class="filetitletext">文件</div>
|
||||
<div>{{img.name}}</div>
|
||||
</div>
|
||||
<div class="uploadimgmask" v-if="clear||isPrew" >
|
||||
<i class="el-icon-search" v-if="isPrew&&img.type.indexOf('image')>-1" @click="handlePictureCardPreview(img)"></i>
|
||||
<i class="el-icon-delete" v-if="clear" @click="handleRemove(img.raw,index)"></i>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="uploadcontain" :style="{height:width+'px',aspectRatio:isDrap?4/3:1/1}"
|
||||
:draggable="isDrap"
|
||||
@dragover.prevent
|
||||
@dragenter.prevent
|
||||
@drop="onUploadDrap"
|
||||
v-if="limit>imageList.length">
|
||||
<label for="uploadinput" class="uploadlabel" @click="onInputClick">
|
||||
<slot>
|
||||
<i class="el-icon-plus"></i>
|
||||
<span class="draptiptext">{{isDrap?'拖拽上传':'上传'}}</span>
|
||||
</slot>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uploadtextbox" v-if="listType=='text'||listType=='picture'">
|
||||
<div class="uploadtextcontain"
|
||||
:draggable="isDrap"
|
||||
@dragover.prevent
|
||||
@dragenter.prevent
|
||||
@drop="onUploadDrap"
|
||||
>
|
||||
<label for="uploadinput" class="uploadlabel" @click="onInputClick" >
|
||||
<slot>
|
||||
<el-button type="primary" size="small"><i class="el-icon-plus"></i> {{isDrap?'拖拽上传':'上传'}}</el-button>
|
||||
</slot>
|
||||
</label>
|
||||
</div>
|
||||
<slot name="tip">
|
||||
</slot>
|
||||
<ul class="uploadtextlist" :class="'upload-list--'+listType">
|
||||
<li v-for="img,index in imageList" :key="index" class="uploadtextitem" >
|
||||
<div class="ag-upload-list__item-namebox" @click="handlePictureCardPreview(img)">
|
||||
<slot name="icon">
|
||||
<i class="el-icon-document ag-icon-document"></i>
|
||||
</slot>
|
||||
<slot name="file" :file="img">
|
||||
<img v-if="listType=='picture'" :src="img.url" class="ag-upload-list__item-thumbnail" />
|
||||
<a class="ag-upload-list__item-name" >{{img.name}}</a>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="uploadrightbox">
|
||||
<slot name="status" :file="img">
|
||||
<span class="uploadstatusbpx">
|
||||
<i v-if="img.status==='uploading'" class="el-icon-loading uploadingicon" ></i>
|
||||
<i v-if="img.status==='success'" class="el-icon-circle-check statusicon"></i>
|
||||
<i v-if="img.status==='failed'" class="el-icon-circle-close failedicon"></i>
|
||||
<span v-if="img.msg" class="uploadmsg">{{img.msg}}</span>
|
||||
</span>
|
||||
</slot>
|
||||
<el-popconfirm
|
||||
:title="`确定移除${img.name}吗?`"
|
||||
@confirm="handleRemove(img.raw,index)"
|
||||
>
|
||||
<i class="el-icon-close ag-icon-close" slot="reference"></i>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="file" style="display:none;" :multiple="limit>1&&$attrs.multiple" :accept="$attrs.accept" id="uploadinput" @change="onUpdate" ref="fileinputref"/>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "agUpload",
|
||||
props:{
|
||||
isPrew:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
clear:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
width:{
|
||||
type:Number,
|
||||
default:80
|
||||
},
|
||||
dragmove:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
isDrap:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
limit:{
|
||||
type:Number,
|
||||
default:1
|
||||
},
|
||||
|
||||
fileList:{
|
||||
type:Array,
|
||||
default(){
|
||||
return [];
|
||||
}
|
||||
},
|
||||
listType:{
|
||||
type:String,
|
||||
default:'picture-card'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'fileList', // 明确指定 prop 为 'value'
|
||||
event: 'onUpload' // 自定义事件名,用于更新 value
|
||||
},
|
||||
mounted() {
|
||||
if(this.fileList.length>0){
|
||||
let list=[];
|
||||
this.fileList.map((h)=>{
|
||||
if(typeof(h)=='object'){
|
||||
list.push(h);
|
||||
}else{
|
||||
let imgurl=h.split("/");
|
||||
let filename=imgurl[imgurl.length-1];
|
||||
let extarr=h.split(".");
|
||||
let extname=extarr[extarr.length-1];
|
||||
if(['jpg','jpeg','png','gif','svg'].indexOf(extname)>-1){
|
||||
list.push({
|
||||
name:filename,
|
||||
url:h,
|
||||
type:'image/'+extname.toLowerCase(),
|
||||
raw:null
|
||||
});
|
||||
}else{
|
||||
list.push({
|
||||
name:filename,
|
||||
url:h,
|
||||
type:'other/'+extname.toLowerCase(),
|
||||
raw:null
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
this.imageList=list;
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
fileList(val){
|
||||
if(val.length>0){
|
||||
let list=[];
|
||||
val.map((h)=>{
|
||||
if(typeof(h)=='object'){
|
||||
list.push(h);
|
||||
}else{
|
||||
let imgurl=h.split("/");
|
||||
let filename=imgurl[imgurl.length-1];
|
||||
let extarr=h.split(".");
|
||||
let extname=extarr[extarr.length-1];
|
||||
if(['jpg','jpeg','png','gif','svg'].indexOf(extname)>-1){
|
||||
list.push({
|
||||
name:filename,
|
||||
url:h,
|
||||
type:'image/'+extname.toLowerCase(),
|
||||
raw:null
|
||||
});
|
||||
}else{
|
||||
list.push({
|
||||
name:filename,
|
||||
url:h,
|
||||
type:'other/'+extname.toLowerCase(),
|
||||
raw:null
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
this.imageList=list;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogImageUrl: '',
|
||||
dialogVisible: false,
|
||||
imageList:[],
|
||||
sourceNode:null,
|
||||
partNode:null,
|
||||
selectTop:false,
|
||||
drag:false,
|
||||
dragmoveclass:'imghover'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleRemove(file,index) {
|
||||
this.imageList=this.imageList.filter((item,inkey)=>{
|
||||
return inkey !== index;
|
||||
});
|
||||
this.$emit('onRemove',file,this.imageList);
|
||||
},
|
||||
handlePictureCardPreview(file) {
|
||||
if(file.type.indexOf('image/')>-1){
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
}
|
||||
},
|
||||
onUpdate(e){
|
||||
if(this.limit<=this.imageList.length){
|
||||
return;
|
||||
}
|
||||
try{
|
||||
let uplist=[];
|
||||
let files=[...e.target.files].slice(0,this.limit-this.imageList.length);
|
||||
const find=files.find((f,i)=>{
|
||||
if(this.$attrs.accept){
|
||||
let acceptarr=this.$attrs.accept.split(",");
|
||||
if(!acceptarr.includes(f.type)){
|
||||
if(this.$listeners.onError){
|
||||
this.$emit('onError',`其中第${i+1}张文件类型错误`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(this.$attrs.maxSize){
|
||||
if(f.size>this.$attrs.maxSize){
|
||||
if(this.$listeners.onError){
|
||||
this.$emit('onError',`其中第${i+1}张文件大小不能超过${this.$attrs.maxSize/1024/1024}M"`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(find){
|
||||
return;
|
||||
}
|
||||
|
||||
files.map((item,index) => {
|
||||
if(item.type.indexOf("image")>-1){
|
||||
let filerender=new FileReader();
|
||||
filerender.onload=function(e){
|
||||
uplist.push({
|
||||
name:item.name,
|
||||
url:e.target.result,
|
||||
type:item.type,
|
||||
size:item.size,
|
||||
raw:item,
|
||||
status:'init',
|
||||
msg:""
|
||||
});
|
||||
if(files.length==uplist.length){
|
||||
if(this.$listeners.onUpload){
|
||||
this.fileList.push(...uplist);
|
||||
this.$emit('onUpload',this.fileList,uplist);
|
||||
}else{
|
||||
this.imageList.push(...uplist);
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
filerender.readAsDataURL(item);
|
||||
}else{
|
||||
uplist.push({
|
||||
name:item.name,
|
||||
type:item.type,
|
||||
size:item.size,
|
||||
raw:item,
|
||||
status:'init',
|
||||
msg:""
|
||||
});
|
||||
if(files.length==uplist.length){
|
||||
if(this.$listeners.onUpload){
|
||||
this.fileList.push(...uplist);
|
||||
this.$emit('onUpload',this.fileList,uplist);
|
||||
}else{
|
||||
this.imageList.push(...uplist);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}catch(err){
|
||||
console.log(err,"uploaderr");
|
||||
|
||||
if(this.$listeners.onError){
|
||||
this.$emit('onError',e);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragstart(e){
|
||||
this.sourceNode=e.target;
|
||||
this.partNode=e.target.parentNode;
|
||||
e.target.classList.add("tabsbg");
|
||||
setTimeout(()=>{
|
||||
e.target.classList.remove("tabsbg");
|
||||
e.target.classList.add("moving");
|
||||
},1);
|
||||
},
|
||||
onDragenter(e){
|
||||
e.preventDefault();
|
||||
if(!this.dragmove){
|
||||
return;
|
||||
}
|
||||
if(this.partNode===e.target||e.target===this.sourceNode){
|
||||
return
|
||||
}
|
||||
const childrens=[...this.partNode.children];
|
||||
let thistarget=childrens.find((f)=>f==e.target);
|
||||
if(!thistarget){
|
||||
thistarget=e.target.parentNode;
|
||||
}
|
||||
if(!thistarget){
|
||||
return
|
||||
}
|
||||
|
||||
const sourceIndex=childrens.indexOf(this.sourceNode);
|
||||
const targetIndex=childrens.indexOf(thistarget);
|
||||
if(sourceIndex<targetIndex){
|
||||
this.partNode.insertBefore(this.sourceNode,thistarget.nextElementSibling);
|
||||
}else{
|
||||
this.partNode.insertBefore(this.sourceNode,thistarget);
|
||||
}
|
||||
|
||||
},
|
||||
onDragover(e){
|
||||
e.preventDefault();
|
||||
},
|
||||
onMouseup(e){
|
||||
e.preventDefault();
|
||||
if(!this.dragmove){
|
||||
return;
|
||||
}
|
||||
if(this.partNode===e.target||e.target===this.sourceNode){
|
||||
return
|
||||
}
|
||||
this.sourceNode.classList.remove("moving");
|
||||
},
|
||||
onDragend(e){
|
||||
e.preventDefault();
|
||||
if(!this.dragmove){
|
||||
return;
|
||||
}
|
||||
e.target.classList.remove("moving");
|
||||
e.target.classList.remove("tabsbg");
|
||||
this.sourceNode.classList.remove("moving");
|
||||
if(this.partNode===e.target||e.target===this.sourceNode){
|
||||
return
|
||||
}
|
||||
const childrens=[...this.partNode.children];
|
||||
|
||||
const sourceIndex=childrens.indexOf(this.sourceNode);
|
||||
const item = this.imageList.splice(sourceIndex, 1)[0];
|
||||
this.imageList.splice(sourceIndex, 0, item);
|
||||
this.sourceNode=null;
|
||||
this.partNode=null;
|
||||
},
|
||||
onUploadDrap(e){
|
||||
e.preventDefault(); // 阻止默认行为(打开文件)
|
||||
e.stopPropagation(); // 停止事件冒泡
|
||||
if(this.drap){
|
||||
return;
|
||||
}
|
||||
const files = event.dataTransfer.files;
|
||||
this.onUpdate({target:{files: files}});
|
||||
},
|
||||
onInputClick(e){
|
||||
e.preventDefault(); // 阻止默认行为(打开文件)
|
||||
e.stopPropagation(); // 停止事件冒泡
|
||||
this.$refs.fileinputref.click();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uploadcontain{
|
||||
position: relative;
|
||||
width:100px;
|
||||
aspect-ratio: 1/1;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
.uploadlabel{
|
||||
font-size: 16px;
|
||||
color:#97a8be;
|
||||
display: block;
|
||||
width:100%;
|
||||
cursor: pointer;
|
||||
height:100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
.draptiptext{
|
||||
font-size:13px;
|
||||
color:#666;
|
||||
text-align: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.uploadimgbox{
|
||||
position: relative;
|
||||
width: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap:5px;
|
||||
.imgitem{
|
||||
position: relative;
|
||||
width:100px;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 1/1;
|
||||
transition: all .3s;
|
||||
&.imghover:hover{
|
||||
cursor: move;
|
||||
}
|
||||
&.tabsbg{
|
||||
border-radius:6px 6px 0 0;
|
||||
background:#fff;
|
||||
overflow:hidden;
|
||||
}
|
||||
&.opcacityzero{
|
||||
opacity: 0;
|
||||
}
|
||||
&.moving{
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
img{
|
||||
display: block;
|
||||
aspect-ratio: 1/1;
|
||||
width:100%;
|
||||
}
|
||||
.uploadimgmask{
|
||||
position: absolute;
|
||||
top:0;
|
||||
display: none;
|
||||
left: 0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
background-color: rgba(0,0,0,.3);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap:6px;
|
||||
z-index: 1;
|
||||
i{
|
||||
font-size: 20px;
|
||||
color:#fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
.uploadimgmask{
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
.filetext{
|
||||
font-size:12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding:5px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
height:100%;
|
||||
white-space: nowrap; /* 文本不换行 */
|
||||
overflow: hidden; /* 隐藏溢出的内容 */
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
.filetitletext{
|
||||
font-size:15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.uploadtextbox{
|
||||
.uploadtextcontain{
|
||||
margin-bottom:7px;
|
||||
.uploadtextcontaindefaultbtn{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:5px;
|
||||
background: #fff;
|
||||
width:fit-content;
|
||||
padding:5px 12px;
|
||||
box-sizing: border-box;
|
||||
border-radius:4px;
|
||||
font-size:13px;
|
||||
}
|
||||
}
|
||||
.uploadtextlist{
|
||||
display: block;
|
||||
list-style-type: disc;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
padding-inline-start: 40px;
|
||||
unicode-bidi: isolate;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
margin-top:12px;
|
||||
|
||||
|
||||
}
|
||||
.upload-list--text{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
&:first-child{
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.uploadtextitem{
|
||||
position: relative;
|
||||
list-style: none;
|
||||
transition: all .5s cubic-bezier(.55,0,.1,1);
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
line-height:1;
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 5px 10px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
&:hover{
|
||||
background-color: #f5f7fa;
|
||||
.ag-icon-close{
|
||||
display:inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ag-upload-list__item-namebox{
|
||||
margin-right: 40px;
|
||||
padding-left: 4px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.ag-upload-list__item-name{
|
||||
text-decoration: none;
|
||||
color: #606266;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: color .3s;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
|
||||
.ag-icon-document{
|
||||
height: 100%;
|
||||
margin-right: 7px;
|
||||
color: #909399;
|
||||
line-height: inherit;
|
||||
&:hover{
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.el-icon-close{
|
||||
position: relative;
|
||||
right: 5px;
|
||||
cursor: pointer;
|
||||
opacity: .75;
|
||||
color: #606266;
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.upload-list--picture{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
.uploadtextitem{
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
background-color: #fff;
|
||||
border: 1px solid #c0ccda;
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
margin-top: 10px;
|
||||
padding: 10px 10px 10px 90px;
|
||||
height: 92px;
|
||||
gap:10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
.ag-icon-close{
|
||||
display:inline-block;
|
||||
}
|
||||
}
|
||||
.ag-upload-list__item-thumbnail{
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
float:left;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-left: -80px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.ag-upload-list__item-namebox{
|
||||
margin-right: 40px;
|
||||
padding-left: 4px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.ag-upload-list__item-name{
|
||||
flex:1;
|
||||
color: #606266;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: color .3s;
|
||||
white-space: nowrap;
|
||||
line-height: 70px;
|
||||
font-size:14px;
|
||||
margin-top: 0;
|
||||
text-decoration: none;
|
||||
.ag-icon-document{
|
||||
display:none;
|
||||
}
|
||||
&:hover{
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-icon-close{
|
||||
position: absolute;
|
||||
font-family: element-icons !important;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
vertical-align: baseline;
|
||||
display: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
line-height: 1;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
cursor: pointer;
|
||||
opacity: .75;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.uploadrightbox{
|
||||
display:flex;
|
||||
justify-content:flex-end;
|
||||
align-items: center;
|
||||
.uploadstatusbpx{
|
||||
margin-right: 7px;
|
||||
}
|
||||
}
|
||||
.uploadingicon{
|
||||
color:#409eff;
|
||||
}
|
||||
.failedicon{
|
||||
color:red;
|
||||
}
|
||||
.statusicon{
|
||||
color:green;
|
||||
}
|
||||
.uploadmsg{
|
||||
margin:0 7px;
|
||||
}
|
||||
::v-deep {
|
||||
.el-table {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,11 +1,45 @@
|
|||
// 导入组件
|
||||
import agInput from './agInput/index'
|
||||
import agSelect from './agSelect/index'
|
||||
import agInput from './agInput/index';
|
||||
import agSelect from './agSelect/index';
|
||||
import agUpload from './agUpload';
|
||||
import agForm from './agForm';
|
||||
import agColorPicker from './agColorPicker';
|
||||
import agQuery from './agQuery';
|
||||
import agTable from './agTable';
|
||||
import agTabs from './agTabs';
|
||||
import agDialog from './agDialog';
|
||||
import agPagination from './agPagination';
|
||||
import agRow from './agRow';
|
||||
import agCol from './agCol';
|
||||
import agMutionCheckbox from './agMutionCheckbox';
|
||||
import agSearch from './agSearch';
|
||||
import agDatePicker from "./agDatePicker";
|
||||
import agNumberRange from "./agNumberRange";
|
||||
import agMultionDatePicker from "./agMultionDatePicker";
|
||||
import agMultionInput from "./agMultionInput";
|
||||
|
||||
// 注册组件
|
||||
|
||||
// 组件列表
|
||||
const components = [
|
||||
agInput,
|
||||
agSelect
|
||||
agSelect,
|
||||
agUpload,
|
||||
agForm,
|
||||
agColorPicker,
|
||||
agQuery,
|
||||
agTable,
|
||||
agDialog,
|
||||
agTabs,
|
||||
agPagination,
|
||||
agCol,
|
||||
agRow,
|
||||
agDatePicker,
|
||||
agMutionCheckbox,
|
||||
agSearch,
|
||||
agNumberRange,
|
||||
agMultionDatePicker,
|
||||
agMultionInput
|
||||
]
|
||||
|
||||
// 定义 install 方法,接收 Vue 作为参数(使用 use 注册插件,那么所有的组件都会被注册)
|
||||
|
@ -13,7 +47,9 @@
|
|||
// 判断是否安装
|
||||
if (install.installed) return
|
||||
// 遍历注册全局组件
|
||||
components.map(component => Vue.component(component.name, component))
|
||||
components.forEach(component => {
|
||||
Vue.component(component.name, component);
|
||||
});
|
||||
}
|
||||
|
||||
// 判断是否是直接引入文件
|
||||
|
@ -22,11 +58,9 @@
|
|||
}
|
||||
|
||||
export default {
|
||||
version:'2.15.14',
|
||||
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
|
||||
install,
|
||||
}
|
||||
export {
|
||||
// 以下是具体的组件列表
|
||||
agInput,
|
||||
agSelect
|
||||
...components
|
||||
}
|
165
src/App.vue
165
src/App.vue
|
@ -2,15 +2,12 @@
|
|||
<div>
|
||||
<el-button type="success" @click="abb = true">点击打开 Dialog</el-button>
|
||||
<ag-dialog :visible.sync="abb"> </ag-dialog>
|
||||
<ag-datePicker v-model="date_value" :showTime="true" :range="true" @change="onPicker">
|
||||
</ag-datePicker>
|
||||
<ag-input value="value"> </ag-input>
|
||||
<ag-date-picker v-model="date_value" :showTime="true" :range="true" @change="onPicker">
|
||||
</ag-date-picker>
|
||||
|
||||
<ag-input v-model="inputValue" placeholder="请输入" @change="onInputChange" ref="aginputref">
|
||||
</ag-input>
|
||||
<ag-select :options="a_options" v-model="value">
|
||||
<!-- <template slot="prefix">
|
||||
{{
|
||||
(a_options.find((e) => e.value == value) || {}).label
|
||||
}}
|
||||
</template> -->
|
||||
</ag-select>
|
||||
<ag-NumberRange v-model="values"> </ag-NumberRange>
|
||||
<el-form
|
||||
|
@ -31,7 +28,7 @@
|
|||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<ag-MultifunctionSearch
|
||||
<ag-multion-input
|
||||
size="small"
|
||||
ref="ttt"
|
||||
v-model="values"
|
||||
|
@ -39,12 +36,27 @@
|
|||
:clearable="true"
|
||||
:options="a_options"
|
||||
@change="onInputinput"
|
||||
|
||||
@blur="onblur"
|
||||
>
|
||||
</ag-MultifunctionSearch>
|
||||
</ag-multion-input>
|
||||
<ag-color-picker size="small" v-model="colorvalue"/>
|
||||
<agQuery :inputs="inputs" @onSearch="onSearch"/>
|
||||
<agTable :columns="columns" :data="tabledata" :currentPage="2" :pageSize="100" :total="500" >
|
||||
<template #name="{row}">
|
||||
<div>{{row.name}}11</div>
|
||||
</template>
|
||||
<template #date="{row}">
|
||||
<div>{{row.date}} </div>
|
||||
</template>
|
||||
</agTable>
|
||||
<agUpload @onUpload="onUpload" isDrap dragmove multiple :limit="5" @onError="onError" :maxSize="1024*1024" :value="filelist">
|
||||
<div slot="tip">只能上传jpg/png文件,且不超过500kb</div>
|
||||
</agUpload>
|
||||
<ag-form :data="formdata" label-width="120px" label-position="left" v-model="formvalue">
|
||||
</ag-form>
|
||||
<ag-mution-checkbox :datas="checklist" @onSearch="onCheckSearch" v-model="checkvalue"> </ag-mution-checkbox>
|
||||
|
||||
<!-- <el-input
|
||||
<!-- <el-input agMultionCheckbox
|
||||
size="small"
|
||||
placeholder="请输入内容"
|
||||
v-model="value"
|
||||
|
@ -57,29 +69,35 @@
|
|||
</el-select>
|
||||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||||
</el-input> -->
|
||||
<ag-multion-date-picker size="small"
|
||||
ref="ttt"
|
||||
v-model="datevalues"
|
||||
:showExtra="true"
|
||||
:clearable="true"
|
||||
:range="true"
|
||||
:options="a_options" />
|
||||
<ag-search :data="searchdatas" v-model="searchvalue" @onRest="onRest" @onSearch="onSearch"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import agDialog from "../packages/agDialog/src/index.vue";
|
||||
import agDatePicker from "../packages/agDatePicker/src/index.vue";
|
||||
import agInput from "../packages/agInput/src/index.vue";
|
||||
import agSelect from "../packages/agSelect/src/index.vue";
|
||||
import agNumberRange from "../packages/agNumberRange/src/index.vue";
|
||||
import ElementUI from 'element-ui';
|
||||
import Vue from 'vue';
|
||||
import agCascadeOptional from "../packages/agCascadeOptional/src/index.vue";
|
||||
import agMultifunctionSearch from "../packages/agMultifunctionSearch/src/index.vue";
|
||||
import agQuery from "../packages/agQuery/src/index.vue";
|
||||
import vuedraggable from 'vuedraggable';
|
||||
import agElemUI from "../packages/index.js";
|
||||
|
||||
|
||||
Vue.use(ElementUI);
|
||||
Vue.use(agElemUI);
|
||||
// Vue.use(vuedraggable);
|
||||
Vue.component('vuedraggable', window.vuedraggable)
|
||||
|
||||
export default {
|
||||
|
||||
components: {
|
||||
agDialog,
|
||||
agDatePicker,
|
||||
agInput,
|
||||
agSelect,
|
||||
agNumberRange,
|
||||
agCascadeOptional,
|
||||
agMultifunctionSearch,
|
||||
agQuery
|
||||
vuedraggable
|
||||
},
|
||||
data() {
|
||||
var validatePass = (rule, value, callback) => {
|
||||
|
@ -99,15 +117,37 @@ export default {
|
|||
// }
|
||||
};
|
||||
return {
|
||||
colorvalue:"#ffffff",
|
||||
ruleForm: {
|
||||
pass: [],
|
||||
},
|
||||
columns:[
|
||||
{soltName: "date", width:200,type:"expand" },
|
||||
{soltName: "name", label: "姓名" },
|
||||
{prop: "xinghao", label: "型号",width:120 },
|
||||
{prop: "dianchi", label: "电池" ,width:500},
|
||||
{prop: "pinpai", label: "品牌" ,width:200},
|
||||
{prop: "address", label: "地址" ,fixed:'right',width:100}
|
||||
],
|
||||
tabledata:[
|
||||
{date: "2016-05-02", name: "王小虎1", address: "上海市普陀区金沙江路 1518 弄"},
|
||||
{date: "2016-05-03", name: "王小虎2", address: "上海市普陀区金沙江路 1518 弄"},
|
||||
{date: "2016-05-04", name: "王小虎3", address: "上海市普陀区金沙江路 1518 弄"},
|
||||
{date: "2016-05-05", name: "王小虎4", address: "上海市普陀区金沙江路 1518 弄"}
|
||||
],
|
||||
checklist:[
|
||||
{label:"方法1",value:"1"},
|
||||
{label:"方法2",value:"2"}
|
||||
],
|
||||
rules: {
|
||||
pass: [{ validator: validatePass, trigger: "blur" }],
|
||||
},
|
||||
inputValue:"",
|
||||
date_value:null,
|
||||
checkvalue:[],
|
||||
value: "选项1",
|
||||
a_value: "59584",
|
||||
datevalues:["4",["2022-12-12","2022-12-13 "]],
|
||||
values: ["4",""],
|
||||
options: [
|
||||
{
|
||||
|
@ -178,7 +218,7 @@ export default {
|
|||
},
|
||||
{
|
||||
label:"型号",
|
||||
elem:'el-select',
|
||||
elem:'el-input',
|
||||
name:"model",
|
||||
options: []
|
||||
},
|
||||
|
@ -319,9 +359,9 @@ export default {
|
|||
enName: "time",
|
||||
TimeType: "daterange",
|
||||
clearable: true,
|
||||
startplaceholder: "开始日期",
|
||||
endplaceholder: "结束日期",
|
||||
rangeseparator: "至",
|
||||
startPlaceholder: "开始日期",
|
||||
endPlaceholder: "结束日期",
|
||||
rangeSeparator: "至",
|
||||
format: "timestamp",
|
||||
placeholder: "请选择日期",
|
||||
filterable: true,
|
||||
|
@ -333,18 +373,55 @@ export default {
|
|||
handleChange: () => {},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
values: {
|
||||
handler(val) {
|
||||
console.log(val, 238);
|
||||
filelist:['https://git.aiguoai.com/assets/img/logo.svg'],
|
||||
formdata:[
|
||||
{label:"订单编号",span:10,type:"ag-input",enName:'order_sn',placeholder:'请输入洗碗机',size:'small',clearable:true,show:true,value:false,required:true,options:[{label:"是",value:'1'},{label:"否",value:'2'}]},
|
||||
{label:"IMEI/机器编号",span:10,type:"ag-input-number",enName:'imei',labelWidth:'120px',placeholder:'请输入IMEI/机器编号',size:'small',clearable:true,max:10,min:2,step:2,show:true},
|
||||
{label:"质检码",span:12,type:"ag-rate",value:'',enName:'ser_sn',placeholder:'请输入质检码',size:'small',clearable:true,show:true,options:[{value:'1',label:'112'},{value:'2',label:'2223'}]},
|
||||
{label:"质检时间",span:12,type:"ag-multifunction-search",enName:'time',showAlpha:true,size:'small',colorFormat:'hsv',show:true},
|
||||
|
||||
],
|
||||
searchdatas:[
|
||||
{label:"IMEI",span:4,type:"ag-input",enName:'order_sn',placeholder:'请输入洗碗机',size:'small',clearable:true,show:true,value:false,required:true,options:[{label:"是",value:'1'},{label:"否",value:'2'}]},
|
||||
{label:"订单编号",span:4,type:"ag-input-number",enName:'imei',labelWidth:'120px',placeholder:'请输入IMEI/机器编号',size:'small',clearable:true,max:10,min:2,step:2,show:true},
|
||||
{label:"质检码",span:4,type:"ag-rate",value:'',enName:'ser_sn',placeholder:'请输入质检码',size:'small',clearable:true,show:true,},
|
||||
{label:"质检时间",span:6,type:"ag-multion-input",enName:'time',showAlpha:true,size:'small',colorFormat:'hsv',options:[{value:'1',label:'112'},{value:'2',label:'2223'}],show:true},
|
||||
],
|
||||
searchvalue:{
|
||||
order_sn:"11",
|
||||
imei:'',
|
||||
ser_sn:2,
|
||||
timer:['1','2']
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
formvalue:{
|
||||
order_sn:"11",
|
||||
imei:'',
|
||||
ser_sn:2,
|
||||
time:['11','2'],
|
||||
avatar:["https://git.aiguoai.com/assets/img/logo.svg"],
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted(){
|
||||
this.$refs.aginputref.value=123;
|
||||
},
|
||||
methods: {
|
||||
onUpload(files,list){
|
||||
console.log("onUpload",files,list);
|
||||
this.filelist=list;
|
||||
|
||||
},
|
||||
onError(err){
|
||||
console.log("onError",err);
|
||||
},
|
||||
onblur(val,elem){
|
||||
console.log("onblur",val,elem,this);
|
||||
|
||||
},
|
||||
onInputChange(value){
|
||||
console.log(value,"onSearch");
|
||||
},
|
||||
onPicker(value){
|
||||
this.date_value=value;
|
||||
},
|
||||
|
@ -352,7 +429,7 @@ export default {
|
|||
console.log(values,"onSearch");
|
||||
},
|
||||
onInputinput(value){
|
||||
console.log(value,"oninput");
|
||||
console.log(value,"oninput222");
|
||||
this.values=value;
|
||||
},
|
||||
change() {
|
||||
|
@ -361,6 +438,9 @@ export default {
|
|||
submit() {
|
||||
this.$refs.ttt.values;
|
||||
},
|
||||
onCheckSearch(val){
|
||||
console.log(val,'onCheckSearch',this.checkvalue);
|
||||
},
|
||||
changes(val) {
|
||||
console.log(val);
|
||||
console.log(999);
|
||||
|
@ -368,13 +448,16 @@ export default {
|
|||
handleSizeChange() {},
|
||||
handleCurrentChange() {},
|
||||
handleClose() {},
|
||||
onRest(val){
|
||||
console.log(val,"onRest")
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
body {
|
||||
background: #918d8d;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
.div {
|
||||
span {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
12
yarn.lock
12
yarn.lock
|
@ -5130,6 +5130,11 @@ sockjs@^0.3.24:
|
|||
uuid "^8.3.2"
|
||||
websocket-driver "^0.7.4"
|
||||
|
||||
sortablejs@1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "http://112.124.55.31:4873/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
|
||||
integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==
|
||||
|
||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
|
||||
|
@ -5576,6 +5581,13 @@ vue@^2.6.14:
|
|||
"@vue/compiler-sfc" "2.7.16"
|
||||
csstype "^3.1.0"
|
||||
|
||||
vuedraggable@^2.24.3:
|
||||
version "2.24.3"
|
||||
resolved "http://112.124.55.31:4873/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
|
||||
integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
|
||||
dependencies:
|
||||
sortablejs "1.10.2"
|
||||
|
||||
vuex@^3.6.2:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"
|
||||
|
|
Loading…
Reference in New Issue