Commit 1a092ae5 by zhaopanyu

zpy

parent 9196f89a
# 页面标题
VUE_APP_TITLE = 若依管理系统
VUE_APP_TITLE = 系统
# 开发环境配置
ENV = 'development'
......
# 页面标题
VUE_APP_TITLE = 若依管理系统
VUE_APP_TITLE = 系统
# 生产环境配置
ENV = 'production'
......
# 页面标题
VUE_APP_TITLE = 若依管理系统
VUE_APP_TITLE = 系统
BABEL_ENV = production
......
{
"name": "ruoyi",
"version": "3.8.9",
"description": "若依管理系统",
"description": "系统",
"author": "若依",
"license": "MIT",
"scripts": {
......
import {ImagePattern} from '@int/geotoolkit/attributes/ImagePattern';
export const LINE_PATTERNS = {
None: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAAQCAYAAADeWHeIAAAAUElEQVRoQ+3UAQ0AAAyDsM+/6QspcwAh2zXawGj6' +
'4K8A8AgKoABwAzh+D1AAuAEcvwcoANwAjt8DFABuAMfvAQoAN4Dj9wAFgBvA8XsAPIAHMKcAEXKeuJoAAAAASUVORK5CYII=',
Solid: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAaElEQVRoQ+3XsQkAMAwEMXv/oROSJa6RF3gQ13j' +
'HEQgFNtw2TWAEKIJUQIApv3EBaiAVEGDKb/wFeDAQqAQEWMnb/QICFEIqIMCU37gnRAOpgABTfuMC1EAqIMCU37gANZAKCDDlN34BPpAEDVc2FJ4' +
'AAAAASUVORK5CYII=',
Dash: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAi0lEQVRoQ+3X0QaAUBBF0fr/jy691Y04HEasnq8Z' +
'll1X++YhMCiwD+62msAmQBGMCghwlN9yAWpgVECAo/yWXwEeZYY1avOfwHxuHgJ8v30C+f4iVX0EKMD0AhTgIuaK//EV7yckff+drwoIsMppWCog' +
'wFTM+aqAAKuchqUCAkzFnK8KCLDKaVgqcAJIIRwN6KSBLwAAAABJRU5ErkJggg==',
Dot: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAeUlEQVRoQ+3XKw6AMBRFwXb/i4YgW/vEEQwWcZOT4' +
'dO9XAqEBXa4bVqBBSAEaQEA0/zGAWQgLQBgmt/4B/C5Mtwo3T8D6XP2GPkA0AM4AjR9gQEIIIB+AY4Cv/rEO4Q4B6QFAEzzGweQgbQAgGl+4wAyk' +
'BYAMM1v/AU90FARWj7aowAAAABJRU5ErkJggg==',
DashDot: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAlklEQVRoQ+3XOw6AMAwE0eT+hwZRAoVlxdI2j' +
'9bGi0ZDPnt5EAgS2MFs0QgsApIgSoCAUfzCCciBKAECRvELfwS8hjF8pf7Or+qnn1PNr+ryzwhUfF91AvoBowsQAQlIwLMV//d2awtwBMkewVxCh' +
'u03rkeAgD1euocJEHAYqHE9AgTs8dI9TICAw0CN6xEgYI+X7mECN9g0KBED690OAAAAAElFTkSuQmCC',
ShortDash: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAkUlEQVRoQ+3XMQqAMBBFQXP/QytiIUpgA/L' +
'dZmyDWRhego7NQ6BRYDTONprAJkARtAoIsJXfcAFqoFVAgK38hp8B7osM71i9d8FxmQe05CLAG28JbGLtPQE+BATxIYi/D5gb0A1YfYFFD7SfkIr' +
'felRAgFFem1cCAqyErEcFBBjltXklIMBKyHpUQIBRXptXAgd6wjANpuZVDgAAAABJRU5ErkJggg==',
LongDash: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAkklEQVRoQ+3XOQ6AMBQDUbj/oUG0NEiWJVO8' +
'9H/JeFLkPBwEhgTO4WyjETgISIIpAQJO8RtOQA5MCRBwit/wR8Dr5xjej8S+3cCmfAnYDfPpNg00uM50XwIGiX2UTAMNrjPdl4BBYgTsQfMJ6bHU' +
'KSBAwACakh4BAvZY6hQQIGAATUmPAAF7LHUKCBAwgKakR+AGA1EQDdCHei0AAAAASUVORK5CYII=',
DashDotDot: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAl0lEQVRoQ+3XMQ6AIBBEUbj/oTV2iglbjM' +
'laPNvNOOTzJTiHB4FGArOxWzUCg4AkaCVAwFb8ygnIgVYCBGzFr/wS8PgYwyr1+v50ni437a/y1vcksN1/Ar4/wEqwak5AAm4dqARK5wQkIAFvBH' +
'59xfITkp5X8hEBAkb4hFMCBEwJykcECBjhE04JEDAlKB8RIGCETzglcAKGBTAR0FL66QAAAABJRU5ErkJggg==',
DashLongDash: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAAmElEQVRoQ+3XMQ7AIAhAUb3/odt0lC4M' +
'UNLkORMw3w/qXhYCgwT2YG2lEVgEJMEoAQKO4lecgBwYJUDAUfyKPwJexRii1NX5i7f7egdX7xeP88QOHgRcBAwd3d0wBJwE3nDj/PpGMAFNwCjw' +
'5xOwuoPkQyBNwC84jUpgBwECdlCVM02AgGlUAjsIELCDqpxpAgRMoxLYQeAG5aIUERB9l2QAAAAASUVORK5CYII='
};
export const FILL_PATTERNS = {
None: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAAQCAYAAADeWHeIAAAAUElEQVRoQ+3UAQ0AAAyDsM+/6QspcwAh2zXawGj6' +
'4K8A8AgKoABwAzh+D1AAuAEcvwcoANwAjt8DFABuAMfvAQoAN4Dj9wAFgBvA8XsAPIAHMKcAEXKeuJoAAAAASUVORK5CYII=',
Slashes: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBA' +
'JqcGAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5T/wDltzBKAAAAQElEQVR4nI3PsQ0AIAwDwd88o2UURqCkQMIMYCOR61IkNiVHyzHkmHIsObYcC' +
'vNYhqOE55MQcxAKNaF6ceT+c178tSs+7ibgDAAAAABJRU5ErkJggg==',
Carets: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJ' +
'qcGAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5TAP9bkSK1AAAALklEQVR4nGNQYMCEDAFYIEMHFsjAwogJGRgEsEAGDSyQwQULZGjCAmlgJC3cCQ' +
'BFqCenjZUrKwAAAABJRU5ErkJggg==',
SlantedBricks: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwA' +
'ACxMBAJqcGAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5TAP9bkSK1AAAAKElEQVR4nGNgEMACGRSwQKyC/7EABg4sELsgVsuJFyTamdjdSQOHAgD' +
'RijHZUjxFTAAAAABJRU5ErkJggg==',
Bricks: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJ' +
'qcGAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5TAP9bkSK1AAAAHElEQVR4nGNgEMACiRf8jwVQaCRNBLG6kwY2AQB8OzCZKCBODAAAAABJRU5Erk' +
'Jggg==',
Dots: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqc' +
'GAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5TAP9bkSK1AAAAMElEQVR4nHXBQQ2AMAAAsSMjC889kYEkpEw6BkpbcmLdSBsb+OPCB+3AmkgL60X5' +
'AB52DQ3f6RevAAAAAElFTkSuQmCC',
Squiggles: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxM' +
'BAJqcGAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5TAP9bkSK1AAAAI0lEQVR4nGNgoAyEOmBChlUNmJBCeygFjKGYkIFpFSak0B4AHSAbi6G9BXs' +
'AAAAASUVORK5CYII=',
SquiggleDots: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQAQMAAACry+YbAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAA' +
'CxMBAJqcGAAAAAZQTFRFAAAAAAAApWe5zwAAAAJ0Uk5TAP9bkSK1AAAAKUlEQVR4nGNgZMCElIJQB0zIsKoBE5JiKAsWSCFgDMWEDEyrMCHxRgIA' +
'/+UbvSn9I4YAAAAASUVORK5CYII='
};
export const TEXT_PATTERNS = {
'Arial': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAB0klEQVRoQ+2ZIU4FQQyGvyfBIjkAkgMA50BAg' +
'iQEhUCSkCARGBBoQCBAg0IAB0ByABwIFJb8yTRpmn2bFW+ymU2fepvMdqadL/3b7oz8ZQRGjMBsxL1z64wACWBCMGoEEsBRw5+bRwCXgAtgH9gE3' +
'geEyN55Be4GrNeSDeAE2AF+Br6TyyYYgQjgGnAK/BZfj4C/Cn4ngBWC2qLJCKCy0irwAJwD28BnBccSwApBbdGkB3ClSOgN8OT+e1nVmkvgBbgGP' +
'oA94ADwEqxMeg+su6B4SU8AW6Slwpk9gILiymU9y4Zehg1SHcXqt1gDGnyHrobU2mNnOwGscJktmvQARuAEyVtoRnyWtMwYARRsW4AHN0KZALZIS' +
'4UzG4BdWcvA+gLOyt4GoJ6tQ+7rggXjbYcMJ4AVLrNFkwZgBMX78uzkdgiAsf5T7fddakKT5QSwRVoqnFkAdmU62ypmxiEAdtWOKcEVLm8KJgVgl' +
'/yabwannlXTLZfueJ4EP5ZBdhxKW4a1Tjgz4BToWYAPAlAZS0DM+yrhO1hJqZqPvhow2vOSvFveTwAXcHlTMCEANfNTQ2GNRvTLANJg2uaDfQD6z' +
'3mypVmhaj+BafskgFOgZwE+/AO6bokRdqnAggAAAABJRU5ErkJggg==',
'Arial Black': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACvklEQVRoQ+2ZrW9UQRTFTyW1VBNSgyQ' +
'hdaChuqaCejQJFkT7B+AICBIEFVXV9cURElyxOBKqa5uTzE1Obu7Mm5lud99uZk3Tt/Nm7sdv7tduYXyGBVZoga0Vnj2OHhbAAHBAsFILDABXav5' +
'xeATgcwCXyTRfALwFcNNgqtcAvi/pfT0rEvE3gEMAf9KXTwCcAXgKwH/XoOLk0ocATgG8uudzJgWZ+4IIwPcAjpPgPU6aE4BUQ3UYAM6MSA+gOsh' +
'E/QDgZIlytwCsa3OgUfSjFJEGgEt0ZM1RHsAopV0A4PNr2VDX0bm7KWpy7TmAz5kUrNFV5XsB4Ed6sAgANQXWAlgjm8msZYo9UzvlUrA/Q/Wu8df' +
'GrVEAvdH+AXiZNPaGUkhYU7HOMkfzb1QD5hxsRrUzFgGgj+S2dy4C1spGWUtrLQr/D2rAPbFLdKk3Dq4ahRRA33z8AsAmhB/fjORSH9dGAG1ninJ' +
'da6m+F8Ccvnp5IgAjWNi0RLLlAFbbUY9PTl/+b7bsqatrfLmWawzABwA+AngjkexnoWMsQVIDkE+RCvlBQxc91QVz39YmpFa2Um0c7WGALLumnjW' +
'YBmB0s/86KNVwUXQwRXMATsFiUbYXQAXNXyjb+1HmUtXK9k4mBL0AjggoV8IAnHIAX9G6pRXAZzJb5F6ldLsIAH0pYLLvBADymc09W2RrBVBr5Z7' +
'56qwjWa9wBLCULvy+Ns5oBTCCintr2r/PCFgCUJsDkyEnm14kjWS+fubY6msaRHMv1qFXUhfaM+v8e/239u8RQDVelB6064sg8ZEgSsGa+nJGuyu' +
'AJWeU5oB8z34dmZKNvwjVdMwKm9q0pj5ee6haFCCAnNlZ8xGlBj/z4m1+LI1CDYB0nN+HZ/Hsb+mnMYtS+wtuQgw+2qWmi7WGKJLNZqG9c0A/HlL' +
'ZWvy2MWtvAUCtUyAuXJypAAAAAElFTkSuQmCC',
'Bookman': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACV0lEQVRoQ+2Zv09UQRDHP9fSamdCYaOdDbE' +
'RG2OC/4GFUlMQSCwoIQZKChIJCZZGLSyk1h5aEjrt+AOwtiXfZCaZbO7u3Y8Ny73MNsftvLc7b97n5juzDMiREWgYgUHDvXPrjAAJYELQNAIJYNP' +
'w5+YJYDLQNAIC8BTYGOHFe+B7RQ8f2HpfK69b0cVc6i4j4BnwBbALvAP+mQOaOwf2gIMKTjl8a0BtsCu4l0u0iMA4AOWPoBSIEcx5/MwMOE/0enh' +
'vF4ACbwd4C/yt8PwJYIUg9mmJcQA+AX4APwsJjlKqWHwGPgD/LTDj7CWAAvyb3SdZ/hVqRE3LdmU/gIdWEmh+Fbiw++IamoryLts6sA18AiT/tUq' +
'KPnHQ7FkigKr3ylHWag6QakIB4N+vDcIlA6jLribkDDgC9HdcS5A4SH6NmiQHR1C9tP2WDSwBpgztwOnzTYD7t9meAicVM3qzF9eXjSfJgHpWl+D' +
'48j3jqUb0l7oS4BhmvzFABcRz4GMh7cMkWnWohjdCETJvmLxe3QccNtnKa5XVlQkd2L68x4V9jq4asJRhwfCokFy/ZhN41WH/YwDGLBePeWYB0CV' +
'YsuwgetOUAN5zNKcFcFhTErOKMmDZtES7Z0DJrmRbsh/ruWkBlKTG46PyOCkBXGAAYzPhkJQ1n2Q2SuSkdj+ILgGZBcBY05XHRgngAgA47j8h3oH' +
'GI5iyyy27ylH2cl4NjoZ3wV9Mvl+HJuQxoLpOQ932pX3qu2q9LeDYulvNyRddL7+17qHdq2tVQwrWZzYXM+89f039de8WI+LHET+7z3IAAAAASUV' +
'ORK5CYII=',
'Calibri': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAABw0lEQVRoQ+2YL0gFQRCHvxe1GgWr0SqoxSI' +
'2kwY1iyiCWZQHYjIIoohdg80mZrXarYLRbJUf7MKw3Ht3nPdY795sO27/zezH/Gamhw/3QEYP9DKe7Ue7B3AAHYKsHnAAs7rfD3cAnYGsHmgKwE1' +
'gCTgEfhKLFoBjQHO+s1rrh/87D1gAp4B7YMXcchF4q3BrC+AM8ADshbV1AdSe2w5uBe+3eEoEcDZAcx4glEkC8gw4qhC5HMAWQ5Dz6hFASaTGac3' +
'LuATXdNy4LxOAUXoF3zC5FWR3A+TZAjgZomjcL0rwDfAY1j8baZ0ALoAnYDekAJJ+Dc8dO06oAJT8XgIHwMcAewXRsomQaX5WBuArcGuKFIE1Hb5' +
'1pACcBzbMHermjh1/sm6ZVxXA1GpB2wf2Q35YBmAaySz0nwHAF5N/6jwHsFusFVoTAbRVa9HEKJM75qeVUQdwDGAZhYkCMML1NaQIsZKpPt9fI6C' +
'i23WQXI+Ao3jZluwZq2ABoTxtK2nDXAWpXU+qZAGpNbG5XBYBtfdJADwFPn67BLcEmiavaRvRsRc4V1Dppk3qNWDV9AjLAFRD+T0UItreFiQOYJM' +
'v2rK9fgHtF40RvjfO9wAAAABJRU5ErkJggg==',
'Candara': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACDUlEQVRoQ+2YvUrFQBCFv1vaCVoIPoB2PoB' +
'a+wgWYi2iCD6AP2hpIQgK1mphY6+t2AqWNnaWVoK2cmAHliWb3BtIluCky81m5+Tsd2d2doRf7kBBB0YFY3todwAH0CEo6oADWNR+D+4AOgNFHSg' +
'N4DJwAGwAX0Wd8OBFHEgBXADugaWg5hrYB347UucAdmTsUKaNAVQmmu8YuNQXB3AopHSk0wBUCVztGT59kgPY0cIOZVoBOAPcAafAS0a4jVmLnsf' +
'lWaX7AjgJezobl5bwtMSr3E+HPeAPcA5sRTEeo/2hvXsEbAOKcQhcBf05bUNZi3+pUwBqYY+B3QkaAQPyJiy+3ctEaygMmLMwxu53ItA1djPThEw' +
'FID/Dn6MqRtWipdr+5cIO5aMNQGWvPeB9AuHaM+pS5sxlUY35CADG4y1ME/zx1kDvKEM+h/nqpFbFmuDTfGhfDoxbgqUnLZ/6TSVwHAAfAjzKmHG' +
'ZTwGsK/V1ANZp68tLj9PCAWtClDHUEOTO4/TsEliPsmRTBrQSqoxlAKbZKwZwNhwBpSXamqMcgE3aWtjir/TlgAFomWcugcx0pF1ybn8WNzIxgGp' +
'yqkCJu+DFikPp+GgoB2CTtr689DgtHEgPorWYt8k8K8Br0qG+AU/Ad00JTgG0BiWeX3Posv2ngFMnbZdKvJ1N5gC0ONY9p9pa2OKv9OXAHwgglRF' +
'M2ETEAAAAAElFTkSuQmCC',
'Comic Sans MS': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAAGWElEQVRoQ+2ZBaisVRSFv6diYrdio' +
'oiBKBY2tiImdnd3t9iFPjuwuxVFsRULFFsRuwuxFTv5YB04/M7ceG/evXNhDjzmvpnzn9h77bXX3v8oeqNngWG0wKhh3Lu3dc8C9ADYA8GwWqAHw' +
'GE1f2/zVgBcBDgCWBP4FXgd2A74eByYa3zgSGB64JDsNzbbjAesCOwDrAJ8CzwMnAO8NjYLd+jZ+YELgYOB56s1ZwOuAC4Hbmqz15y514bANMDTw' +
'KXA3cBfHTrfkC9TA9C/Bd1FwByNkyyXC3f6gJ0E4GQJHIOnOU4Hjgb+6PQFBrne/sBZwAHA6OrZ1YAHA84Dgd+q3/TLBnmu6ZfHgW3GETkM8mpjN' +
'r0G4OLAbcCngEZ4DlgoRtkLeHnMthiSp7yHrKeDjwfuBL4bkp0HvsmkYeKdWgCtAPMBYEvgm2rZ4pc7gPOBD4F/Br5td88sADQFXgLMAmwPvNHdx' +
'/7f6SYJo5imdOY7XZiWtO31wIQJjq3z6f9PBTz7DJE771Y3FJBnAHsC93dApnSVawsAdwROALYCHu3jhBMBapB9gQXCmMcCnwCmQCNUIz0DmPbmA' +
'ox499kBkAXOrfTYFMDFccy91b4GxEnAZoBpxrTlZ7vIN5V7DtNsPR6JpLgH+D0/NHWijKIuuzrO3RZYBjgc2BQ4NOf1zu9Xi08ALAysGrvd10+ad' +
'+41wGWxoYH+UfTvlcCNwO6x7QvVPmpZGX3y6ru3gKuiGb/qKkQN8jACY+pcRONaEBRHNZfS4KZmo7UeGsIUPXGA9EQKgdUz6RVgqkpX3gzsAvwIT' +
'Jtnrs2njwjK86Jtyj4/RQcJqHbDAFAPCaClGpMOA87MdzKkQLVAkSk9w0zAOoCOdw3B8VLYtCyltjwlwbR+/p6v2kd2E0CetdVYN+sdlWC3EHG/x' +
'VKUeCbvbTBYWJTRDJgaiHcBuwJfDtLvXTNdABqZaj8p/qE+TrYgcCvwVICqTtkiwl+m+iwgWgN4NsbW6ILtxFR5m8RgzjfNtAKgbCx77p2K0Dk+f' +
'wvQFwCbRzctL5GzWmVuDPiddzVoTGs/A55R3SjbySymvOvCTlbmMvPJgOwveE2TN+S+gsUA+x74tw/bydBmGJldALq36xqMAsjvLUoMEs9QFyiti' +
'MBiRH95HjOM1fOIHAJwWeCCygHtLqKDSlrSSI6iazTqizGcbZyiI43qWWMoWzolDQkyo18G0Qk6RAaZMinKtQTh3x2w6qLZwzMtCcjM6q+vs7aAs' +
'81kMJnOvKOA2y9yQWDV95g96yk7rFxth7zaj+Y0y8jyzjWDKBdsnRTQ3Z7gdx/ZuFkJtzKDttJv+kJwj8hRAKh+WavRapEtNISpTYPJILWjmgDUC' +
'RrEtFYMYoSqYYrgniesJuOYZpoALL+rt3TWQIYi3v0+rwBTP7dy2FfWtd0xb9ijpMoVArACQEHgPP9vR8BRA/DPsObOCV5TokBUhnj3VqOZZQzmt' +
'cN42lY7qQebweAcbWdqb1b1AlU9qZ2UBiNyCMCZI47VfhrivVRkpr3Nw0Q6YPmkHrWQKcqUZD/L3qHz1HSymILZitqhoW2P6EwNXFJumdME4HRhC' +
'tlFx3yRlOf6suKTLays9jR16Sz3sgiy3yfr+N1BwNtJdUoAGc60ZbHlHdR8pjN/ezNgk+UMgl8qAAoin/uhOoPgnxs4LYVXOyCYZus9XEuGfyyFm' +
'nY3Q5iNlDlFj2o/G9PHpYUjCN1TJveufm7UaGqPKCAKQP/pYKvRWuB6EUWxhYlsoUMFlkxYD3WSVaqFhgBUH1ntOZrpvfTC1IsaVcA5X03ms55FR' +
'5kC67O4v1qy3VsC335YxTYbtZ5BhjDlm6pKT63VvKKlmrLBNQSpILLAkfm8c3M0m8vl96L/lg7DydQl0Aze3aqALRnANxzaesZ8rtdiP4sobaWE6' +
'Ut/djUgSxvGSstUdUyYTrEvq1iU1K95pH0ZRT2lXlLDCB7Z05RtVOto2zEO9eDZYQ6LjtIukXl0tOzVbMNYbVsY7JH0bQulvzaMe9WvqgSYbRudI' +
'7BlZ4f3XSmFk9LAtT2fjrZ4Mo0KMgsu72mR4nCugagEUXvJjrZf3MdqWfCbDsv82ukylmxuISRgDKbS+xOABrSvOx3FhmpfK3ffiDSre+1rAaPc+' +
'WAkg88L/wcEjo0g/sDjmgAAAABJRU5ErkJggg==',
'Courier': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACL0lEQVRoQ+2YO0seQRSGH0trWwux0c4foCl' +
'Mo/gHLDSlBEwQAraKl1YQRERrTWFjKaSxMfZa2kgKW2tbeWEODIfZ/dzPkSVwtpvZmTMz7zx7LjtCPKFAjwqM9Lh2LB0KEAAGBL0qEAD2Kn8sHgA' +
'GA70q8D8BOAt8A34Br72qFotXUyAArCZlGBpGgRzAMeA3sJAMnQGnwDxwOIzxmBMKDFLAAJwCjoAN4DFNUsj7C2wD+4MMxftQYBgFDMA14Ap4cUY' +
'E4VcH4Bawl42bA+5S27yomivJnuC+BGaAfKzeXwB/0tjF1NbcfJx9COqXV27KAf2+/Iczmjz59/RRHWRt24M//zCaxpwOCghAQbMO6EIGJfe65Kc' +
'UqrWMXeqt69sEThzQmnuTwWrzdxOc8rbytLIpaO/dOdr2KZj1KIWwR31fCsDKttacBn6k/YynSc8dtIuhFRToAqAubqmQDwqYHDjftm02Aaj88ty' +
'BWTpaE4BN65kX/uds6xw7wM+Cx68gaZjookAXABUKJ5yXsbUUFq9T/tgVwJK37AKgL5783FW356YPqYtuMbaSApYD5gA1mf4sD/hRANs8YOksAWA' +
'leGqYMQDlRY5TaLIq2ELYZFaElEAt5V95uM2T/7y4sBzwowDKTqlYUr/PWdUXANYgp5KNtv+AWsJXkqVwV/pNk1e+siPwVE2relZIVMWt3E8VaVv' +
'IbAuvviK2qjq3l4dfvycb9wAsZ7+fKkkbZt6jwBs3TI0RJcyP9wAAAABJRU5ErkJggg==',
'Georgia': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACfklEQVRoQ+2aMWsWQRCGn5TW2tnYpbSx084' +
'itQZioQHBQkEQBC1jSFKmEATFdIJaKPgDtFXB1tIqglgI2sY2vLAvDMPdeUnht5fbrT7u9nZnd557Z2bvW6K1tgML3IGlBc593Kk3gFXgGvDtuIO' +
'05+rYgQzgMvAGOJ/Mew9cB/4s2OxTwGPgXCX2LHg7pj99BFDKsg1cAj6XpTWHT9/HVa/AAErdXiX4bLggfAA8q0ABq97MZtzRd0AAngZeA9+B+8D' +
'fEcNcBD6FflE1dTnffwTslP6G/SuwCWyVkO8xrMTZjMvAGnAbiCmB7V8pD2jclh+OcGINXQSgYYmQDNmm/k+Dk/28ARJgD8N9A6KwniHcA54DL4D' +
'dMul6yO8E49n0Ymj83Ec26PpByRE11NiXqQY/zNaGCOCNooRDm+Gc8GPo62s/S5iWmkbYNF6GMkPsOTNwGTaPFQGM9tqWBuBEkB5SwBxGtaQ7wBX' +
'A4S4uUwr6tlTRd0MhE0OyVbIPwAzqGAWM4yv8/gL2mwJOg8AxOWCE4ndRvpc9auljHIVTKaFbDtN9AFrhVBCpdR3/DIVgHRN1QTsNb8zQSlfBXUc' +
'w3o7o8H/lWF353lFCsMBUeB3K36I9GlugxxeiATghkA2gcydVmDkXzIpjNYv9pHy3SlV7NR3pdEE5pIBdVXCcq0uRnXNagb+0EDwNCvOXkK68T3n' +
'VTeBHOAfM/VTNRtXK9zNADrHapVh9Cz41V8v6LaieAPeACwVuXfdxy5lwJCQ73gEfesL3NLwyIytr+hZs9coFjBVUUPoLzYxcdLKXWhOAQ/lj37H' +
'LyfbODFZXE4AOt/nPELX8EWIGOPz/JR4CB0XAEaDbLb8AAAAASUVORK5CYII=',
'Impact': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAABw0lEQVRoQ+2av0oEMRCHvyutfQHxBWyu08rG' +
'R7DQUrBSsBX/oIKVICgoV1gIWijYq4WVtoKlD2FtKz9IYAi523Nx9zYyaQ4uk83sbz4mmWF7+HAFJqhAb4J7+9auAAJwHngNWjwBK8CXa+MKtKFA' +
'KQBOA7fAUhBlAXhrQyDfo1kFHMBm9fWnVyiQA3ADOA/Z5gPYBw6AOWAVeDTZaA84Csf2TdhrALwD+tX6ZeATmAJOgXXjU1yvv3Lz2k+Zbxc4NOvs' +
'cz3IBStQBWDVq0UQ+kAEMF0jyC6SI9TaaP4kA2e0EYSzDmBVKMqcrwJQRckmcJbcvxYNELqPzRgAlfkegGeTES+B65BFBdyLKXxkb+fTPTWvLHvl' +
'd8AyIRvltQP4/2Ja1Bu1BeAW8D3knpfLgGkryKvgorAa39m2ANwGjk0BcheKE3maA3AN2An2fgSPH8/iLNsC8Ld3QAewOJTqOdwVAG2RoSLEApir' +
'kr0RXS/enVvVBIC5Nsw9oGNXvcR06IhNj2hrI9jUV7Q9RO8Ddg6leg41AeCwRnRsJqfNbdmrSNFIG9U206kwib1GB7BevDu36q++hrFwRKBU9fpw' +
'BUYq8ANfnMgRwWEk7AAAAABJRU5ErkJggg==',
'Roboto': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACDklEQVRoQ+2ZsStHURTHP7+RlUEp2diUbFgs' +
'/gQDZkkpg5GB0aCUYpbBooxm/AEGxSalDMxGOnW/dbvdS++Xet575y48z7n3nnM/v3PO9/56+PAI1BiBXo1r+9IeARxAh6DWCDiAtYbfF3cAnYFa' +
'I2AAngBrmV3cA0vAU4UdDgHnwFn4WcHU/7WLEVAGnAV2gGXgAxBIIxUglM0isOIAdhGn6j6XALSZDMrbijD9RQacACaBq+ruuEXTIvDfABwADoEb' +
'z6BNQ6m//ZYAtCx0AbxFZVkrxKXW/nYKbAGfUem+BKZDb5n2kiX7sbDmVFhIdi8BSvWp15k99ee9W9UegRhAK7caJQEiePaBuwi45wDhYMhc6h0F' +
'z3iAxuY3kfKbvURMmhH1rPmsX/XR4AjkMuBwyEQHmTJoImU+ynjqFY+DWHnPqGBl0w3AwKlin4ojWy+ezz4EPhocgVIJNtC2MwrYlPJoAmAMxGMG' +
'wDhrLlS0t32sJiX3L4ROg4+sXVsvAahSZ96qv7Pfc2AagEfAJlDKgHo/kwH7J3sp8blQ8m0PaRvQrhPpmDcxgCqjunjWQQu8+H5QPZ8JD8uKNqyv' +
'k42VRnsWyK/J+5J93PM9AF/AeijduqPMtQEdO7b2uJv7JiS+RFYGMo+ldiU07MLZxm6AS1FJVW56KZ2+T+0N6L1oXkEpFRyr7vacREc9+QZO2aYR' +
'7XZ7ewAAAABJRU5ErkJggg==',
'Times New Roman': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAADwklEQVRoQ+2ZT6hNYRTF1xsypQx' +
'MZMKMZIaJwtC/YoAxIqUYkj9TpRRlYIQBRRmiTFAGEgPFTEoZMGWqX+1Vu9137rv33Xf/eJ0zue+c+75v77O/tddee98F9VcfgRlGYGGGtnvTfQT' +
'UA7AHwUwj0ANwpuHvjfcA7DEw0wgAwB2S3izixU5JHyTdlPRa0sMZeX1M0oOw/VwS97/jflX4dzLu70o6L+nvBHxdEzHY19i7+jUB8ytnSwDIIXI' +
'BKh9iBtklSa8kvZ2j1zYQL0u6XvwioTZMKUnwY1cC+iZJjyT9LMkxR6GbL1cA4J5gN5ikBUCCyvOPc+T6fknrJMFyxwvYACDXNBKmAhC7Tg6qxjR' +
'8mKNjGd2VqgFbABx918mvAIBfJB2RdFjSUUlfw2wPwMnHf9ksjAJA6x5KHpnt+/vhDdrsU4BhbdKVmQmqTsvslcsXNtjjWcebGoDfQ/dRcq0HKwB' +
'bNp8mvWifAfO1sGe/kB88a5V6s10uwdbTLf2Z9Strc1z47oSkc5JuSUJbYvNG8rPuad8cIu836FycpMsGoHE3GhaAWXTzorAPmtEinAPLh+oDyyU' +
'KX69KuhdslQFNg+PvfsXeALur2TEACaiB+yT0YAYg4OuySRJxiFzWkazlmcGMj9skvewIdAVVVwNSS3Uu0yRPbaw2RwI7ORwTJ3/1E5/Xx3sQ39a' +
'5/Gjo5XHxM/b6YQGIoUEMaKDUA3Vm8+mgVqdzpg8bpAxA9jPzkAjfkgbs6vCdIPUg/f9mk63RRXcxRwYWQGWaULVfjRvumZX9vjlOaHGSCiaEEbG' +
'dWS0nZWZ3M+TqRgLXcxkbOMu1wbQBSJnpGo1ksCw2yqgAJB4EGT14R9LnkAnsOchmZWH+lwsw4edeSS8GjHIqs+EDNvN4yAx9pjQlZi3sHAo/vW4' +
'YAPp90b/bUzfeAzBRfWXAXN66kmiYUUYLgJkNzEKV4Vo2zQ6Pg5mYG8I+aD8Os6v8tjSgAU15d1lvPXPCuPyPyoCtkm4tuiIA2CqFtQy0ysKgEvw' +
'nBDVBNwtaY1G6LgR7uQRdkXQ2DZozeFoA5PvKNgZly6aBZZCiYd1QMXDn4nOQcK/AyT68S+9ZRzOV4ZYCQNiadTWu/y0Aq17KZbBO/k9JOljE7sb' +
'URaJHaCz45PJe/J2bFz8niACQErol1rTmaNWPrkE0W3gGV9fU8t5KpNZ8LydA65eQ2tW6scgNmZ+5uQDc9dcdmPN2isMBSadLrN/HwJtYsRcy4WL' +
'8YICfu8NZNHE9l0n9OrQkWfgPnwRrIOzXC8gAAAAASUVORK5CYII=',
'Verdana': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACXUlEQVRoQ+2ZO0oEQRBA34bGhh7A0AOoqR7' +
'AwECNBQVB0EhUVIwUBEHRTFADj2CuBzA0ERPBxNhUCragKKp7B5ZxmqE32aWnP9VVb+s3A+qnaqBDDQw6PLseXTVABbBC0KkGSgFwBVgD5PunU43' +
'Uw/9VAwLgPjCbMf4k8Ai8AictSVcBbEmxpW8rAAp8L8DcEDIvszy/ApaB95YuVAFsSbGlbysAjvJw4iGngG3gt6ULVQBbUmzp22oOmAJA4bwfhmG' +
'9j0B5bC63GjwXaG+AO2AGODAh3K+XrZ5NGjABXADrToH+HJV7C7gEFofz7VkypPfQ57ptyuuXbrfeyKcATgNPwKYLwz78KhiiAPWIuvbMQKiA3Tr' +
'PGa2XvfwfQObtANemKInOkXUPDt5ongC4AZwbLz4q9eiNkUu+iAIYgRGNpTyljM8b2FJhO5VPNgnBKs+X8aTRumheZIOUdy/ZXr2TzbZhxJi7ptj' +
'wniRnWAFLoNM2SgrA1HgKwChUW6+aA9B6afmdCus+XPfOyCVfyALogfNApgyo93sz8I4LoMryHeSFFqymAGq4tfCOKr5KtltvZLMA2pC7B5wCNtw' +
'1DW2inHEBjHqTTVMCP0/kkYLGe8QKYAEY+zch6vUOgaOgKGmSq+UAzOWQ9k1IBPC4ANo/k62M22ywF2DiskXwAGrok7aJbYvoLdRrfLrq1leZKQ8' +
'YeR0Nj/a8qFiJKuumITiqsrXNU3PADhmN3gWroXOGiYoD26PLNa99T07O+QjeBWuLRdWzACy5UNoUQPXK2ruUfFVaTiJn9YAdAvgHeovoEWdFa7w' +
'AAAAASUVORK5CYII=',
'sans-serif': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAQCAYAAACRBXRYAAACcklEQVRoQ+2ZvS8FURDFj5KWTqehk2hR' +
'0ysUiFJEIvEHUFCSSMRH1CgUEq1KgU4kSn+AUq2Vk9xJJifz3t7GrnjzqvfcvTN3Z3975sMQ8pMR6DACQx36TtcZASSACUGnEUgAOw1/OvcATgK4' +
'BTDtwnIJYAfA9z8O1TCAYwBPAG7Kfc4CeC7fV93f/3EYurk1A9ACPgfgxR1lFwDXVgB8dXPE1r2OFuCuErzfj70BSND4ORCXg/gwBvGef5+0Hh4I' +
'oKWgzwDAaJtdv+EW99xeKiaBvgBw766J1HXfrdekOp8auTUqEejb7L4DWAbwUfwQrlMAj2Uv19cBbJYU/CplyMOAqX/rIJoCMsVeA2gKeASr1Y6H' +
'JWUZJB4OTeX8Pe7qS7OxJSWADwjtnjmgorOoHy0tTN1o18oKrQFTAVvE0DchBqF3r6pEUE4AbDtVURAUFNrzgL2Vor9Wce08PN9aH0XqBbGHfSSo' +
'7xLAFoFTV9EYRlOspjGzoV2zpWFLwb5xUThqFdef1/vTdG6KFgHqz8Pr2Omy1rVmKwH8YwBGD/2uPDSFk9AdiaLVAEgfNfWchsbS40JZ8C9HpOC2' +
'30qLBLBD2CLXNYNon8JmpA6jzSgFc08/BdSzGIwE+ryolEHGayPF03pusSFF047tSQX8IyASwKYGwI9oCNW8DKdtv6lkrQJqCCLbTWHyNelY8HJY' +
'arYzWw2YADZFtqV1PwdckpGFNQ++6dCu0qdk63qpkv0UMGpCajrPqAnRblq7YH25UgFbAqvWjU/BWpPRRjRn01qLnfKE+4/JVAOALP6bZom9zq++' +
'o7GRnwNq+k4Aa8lo6bof11nuESEolD4AAAAASUVORK5CYII='
};
export const FS_KEYS = Object.keys(FILL_PATTERNS);
export const LS_KEYS = Object.keys(LINE_PATTERNS);
export const TS_KEYS = Object.keys(TEXT_PATTERNS);
export const IMAGE_PATTERNS = {
None: null,
Slashes: new ImagePattern({'url': FILL_PATTERNS.Slashes}),
Carets: new ImagePattern({'url': FILL_PATTERNS.Carets}),
SlantedBricks: new ImagePattern({'url': FILL_PATTERNS.SlantedBricks}),
Bricks: new ImagePattern({'url': FILL_PATTERNS.Bricks}),
Dots: new ImagePattern({'url': FILL_PATTERNS.Dots}),
Squiggles: new ImagePattern({'url': FILL_PATTERNS.Squiggles}),
SquiggleDots: new ImagePattern({'url': FILL_PATTERNS.SquiggleDots})
};
export const LINESTYLE_PATTERNS = {
None: [0, 10],
Solid: [],
Dash: [20, 4],
Dot: [2, 4],
DashDot: [20, 4, 2, 4],
ShortDash: [10, 4],
LongDash: [40, 4],
DashDotDot: [20, 4, 2, 4, 2, 4],
DashLongDash: [20, 4, 40, 4]
};
<template>
<div class="int-slider">
<div class="slider-header">
<span class="slider-label">{{ label }}</span>
</div>
<div class="slider-content">
<el-slider
v-model="sliderValue"
:min="parseInt(min)"
:max="parseInt(max)"
@input="handleInput"
></el-slider>
<div class="slider-append">
<slot name="append"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'IntSlider',
props: {
label: {
type: String,
default: ''
},
value: {
type: [Number, String],
default: 0
},
min: {
type: [Number, String],
default: 0
},
max: {
type: [Number, String],
default: 100
}
},
data() {
return {
sliderValue: parseFloat(this.value)
}
},
methods: {
handleInput(value) {
this.$emit('input', value);
}
},
watch: {
value(val) {
this.sliderValue = parseFloat(val);
}
}
}
</script>
<style scoped>
.int-slider {
margin-bottom: 15px;
}
.slider-header {
margin-bottom: 8px;
}
.slider-label {
font-weight: bold;
font-size: 14px;
}
.slider-content {
display: flex;
align-items: center;
}
.slider-append {
margin-left: 15px;
min-width: 40px;
text-align: center;
}
</style>
\ No newline at end of file
<template>
<v-row
class="px-1"
no-gutters
justify="space-between"
style="width: 100%"
>
<v-select
class="pt-0 mt-0"
:value="pattern"
:items="Object.keys(patternList)"
background-color="white"
hide-details
required
light
@input="updatePattern"
>
<template v-slot:selection="{item}">
<div
v-if="item !== 'None'"
:title="item"
style="width: 100%; height: 16px;"
:style="{background: '5px no-repeat url(' + patternList[item] + ')'}"
/>
<div
v-else
class="ml-2"
>
None
</div>
</template>
<template v-slot:item="{item}">
<div
v-if="item !== 'None'"
:title="item"
style="width: 100%; height: 16px;"
:style="{background: '5px no-repeat url(' + patternList[item] + ')'}"
/>
{{ item === 'None' ? 'None' : '' }}
</template>
<template v-slot:append-outer>
<v-menu
transition="scale-transition"
:close-on-content-click="false"
offset-x
>
<template v-slot:activator="{ on }">
<v-badge
class="eyedropper-badge mr-1"
icon="mdi-eyedropper"
bottom
overlap
:bordered="isEyeDropperActive"
@click.native="setEyeDropperEnabled(!isEyeDropperActive)"
>
<v-btn
ref="eyeButton"
:color="colorInfo.rgb"
retain-focus-on-click
fab
height="25"
width="25"
@click.native.stop
v-on="on"
/>
</v-badge>
</template>
<v-color-picker
:value="colorInfo.rgba"
:swatches="SWATCHES"
show-swatches
@input="updateColor"
/>
</v-menu>
</template>
</v-select>
</v-row>
</template>
<script>
import Vuetify, {VRow, VBtn, VMenu, VBadge, VColorPicker} from 'vuetify/lib';
import {RgbaColor} from '@int/geotoolkit/util/RgbaColor';
const SWATCHES = [
['#FF0000', '#AA0000', '#550000'],
['#FFFF00', '#AAAA00', '#555500'],
['#00FF00', '#00AA00', '#005500'],
['#00FFFF', '#00AAAA', '#005555'],
['#0000FF', '#0000AA', '#000055']
];
export default {
name: 'ColorInput',
components: {VRow, VBtn, VMenu, VBadge, VColorPicker},
props: {
name: {
type: String,
default: ''
},
color: {
type: String,
default: '#000000'
},
pattern: {
type: String,
default: ''
},
patternList: {
type: Object,
default: function () {
return null;
}
}
},
data () {
return {
isEyeDropperActive: false,
SWATCHES
};
},
computed: {
colorInfo: function () {
const rgba = new RgbaColor(this.color);
return {
rgb: rgba.toHex(),
rgba: rgba.toHex(true)
};
}
},
mounted: function () {
this._onKeyDown = this.setEyeDropperEnabled.bind(this, false);
window.addEventListener('keydown', this._onKeyDown);
},
destroyed: function () {
this.setEyeDropperEnabled(false);
window.removeEventListener('keydown', this._onKeyDown);
},
methods: {
updateColor (color) {
this.$emit('changed', color, this.pattern);
},
updatePattern (value) {
this.$emit('changed', this.colorInfo.rgba, value);
},
isActive () {
return this.isEyeDropperActive;
},
setEyeDropperEnabled (value) {
if (this.isEyeDropperActive === value) return;
this.isEyeDropperActive = value;
this.$emit('eyedropper-changed', this, value);
}
}
};
</script>
<style scoped>
.eyedropper-badge >>> i.mdi-eyedropper {
color: white !important;
cursor: pointer;
}
.v-badge.eyedropper-badge >>> .v-badge__badge:after {
border-color: red;
}
</style>
<template>
<div class="color-input">
<div class="color-input-header">
<span class="color-input-label">{{ name }}</span>
</div>
<div class="color-input-content">
<div class="color-picker-container">
<el-color-picker
v-model="colorValue"
show-alpha
@change="colorChanged"
></el-color-picker>
</div>
<div class="pattern-selector">
<el-select v-model="patternValue" placeholder="模式" @change="patternChanged">
<el-option
v-for="(pattern, index) in patternList"
:key="index"
:label="pattern"
:value="pattern">
</el-option>
</el-select>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ColorInput',
props: {
name: {
type: String,
default: 'Color'
},
color: {
type: String,
default: '#000000'
},
pattern: {
type: [String, Array],
default: null
},
patternList: {
type: Array,
default: () => []
}
},
data() {
return {
colorValue: this.color,
patternValue: this.pattern
}
},
methods: {
colorChanged(value) {
this.$emit('changed', {
color: value,
pattern: this.patternValue
});
},
patternChanged(value) {
this.$emit('changed', {
color: this.colorValue,
pattern: value
});
},
updateEyeDropper(color) {
this.colorValue = color;
this.$emit('eyedropper-changed', color);
}
},
watch: {
color(val) {
this.colorValue = val;
},
pattern(val) {
this.patternValue = val;
}
}
}
</script>
<style scoped>
.color-input {
margin-bottom: 15px;
}
.color-input-header {
margin-bottom: 8px;
}
.color-input-label {
font-weight: bold;
font-size: 14px;
}
.color-input-content {
display: flex;
align-items: center;
}
.color-picker-container {
margin-right: 15px;
}
.pattern-selector {
flex: 1;
}
</style>
\ No newline at end of file
<template>
<div class="context-menu" v-show="visible" :style="style">
<ul class="menu-list">
<li class="menu-item" @click="handleDelete">
<i class="el-icon-delete"></i>
删除
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'ContextMenu',
data() {
return {
visible: false,
x: 0,
y: 0
}
},
computed: {
style() {
return {
left: this.x + 'px',
top: this.y + 'px'
}
}
},
methods: {
show(x, y) {
this.x = x
this.y = y
this.visible = true
document.addEventListener('click', this.hide)
},
hide() {
this.visible = false
document.removeEventListener('click', this.hide)
},
handleDelete() {
this.$emit('delete')
this.hide()
}
},
beforeDestroy() {
document.removeEventListener('click', this.hide)
}
}
</script>
<style scoped>
.context-menu {
position: fixed;
background: white;
border: 1px solid #e4e7ed;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 2000;
}
.menu-list {
list-style: none;
padding: 0;
margin: 0;
}
.menu-item {
padding: 8px 16px;
cursor: pointer;
display: flex;
align-items: center;
font-size: 14px;
}
.menu-item:hover {
background-color: #f5f7fa;
}
.menu-item i {
margin-right: 8px;
}
</style>
\ No newline at end of file
<template>
<v-dialog
v-bind="$props"
v-on="$listeners"
>
<v-card :style="absolute ? absoluteStyle : ''">
<v-card-title
class="headline"
>
{{ title }}
</v-card-title>
<v-card-text>
<v-container>
<slot />
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
v-if="displayOk"
text
@click="$emit('ok')"
>
Ok
</v-btn>
<v-btn
text
@click="$emit('input', false)"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
// TODO: vuetify will implement the feature of setting custom position for dialog, current solution is temporary
// https://github.com/vuetifyjs/vuetify/issues/4807
export default {
name: 'IntDialog',
props: {
value: {
type: Boolean,
default: false
},
title: {
type: String,
default: 'Title'
},
width: {
type: String,
default: '600px'
},
minWidth: {
type: String,
default: '600px'
},
maxWidth: {
type: String,
default: '600px'
},
absolute: {
type: Boolean,
default: false
},
position: {
type: Object,
default: () => {}
},
displayOk: {
type: Boolean,
default: false
}
},
computed: {
absoluteStyle: function () {
return {
'position': 'absolute',
'top': this.position.top,
'bottom': this.position.bottom,
'right': this.position.right,
'left': this.position.left,
'max-width': this.maxWidth,
'min-width': this.minWidth,
'width': this.width
};
}
}
};
</script>
<style scoped>
>>>.v-dialog {
background-color: white;
}
>>>.v-card__text {
padding-right: 10px!important;
padding-left: 10px!important;
}
</style>
<template>
<v-expansion-panel>
<v-expansion-panel-header
class="int-expansion-header"
expand-icon="mdi-menu-down"
>
{{ title }}
</v-expansion-panel-header>
<v-expansion-panel-content>
<slot />
</v-expansion-panel-content>
</v-expansion-panel>
</template>
<script>
import {VExpansionPanel} from 'vuetify/lib';
export default {
name: 'IntExpansionPanel',
components: {VExpansionPanel},
props: {
title: {
type: String,
default: ''
}
}
};
</script>
<style scoped>
.int-expansion-header {
padding: 4px 8px 4px 12px !important;
flex-direction: row;
justify-content: flex-end;
min-height: 32px !important;
}
.theme--dark.v-expansion-panels .v-expansion-panel {
background-color: #272727;
}
</style>
<template>
<div class="int-expansion-panels">
<el-collapse v-model="activeNames">
<slot />
</el-collapse>
</div>
</template>
<script>
export default {
name: 'IntExpansionPanels',
props: {
openedPanels: {
type: Array,
default: () => []
}
},
data() {
return {
activeNames: this.openedPanels || []
}
},
watch: {
openedPanels(val) {
this.activeNames = val;
}
},
methods: {
handleChange(val) {
this.$emit('update:openedPanels', val);
}
}
};
</script>
<style scoped>
.int-expansion-panels {
margin-bottom: 10px;
}
/* 确保与Element UI折叠面板样式兼容 */
.int-expansion-panels .el-collapse {
border-top: 1px solid #EBEEF5;
border-bottom: 1px solid #EBEEF5;
}
.int-expansion-panels .el-collapse-item__header {
font-size: 14px;
padding-left: 12px;
}
.int-expansion-panels .el-collapse-item__content {
padding: 10px;
}
</style>
<template>
<div style="width: 112px; height: 90px">
<div class="int-loader" />
<div v-if="label != null" style="text-align: center; padding-left: 14px;">
{{ label }}
</div>
</div>
</template>
<script>
export default {
name: 'IntLoader',
props: {
label: {
type: String,
default: null
}
}
};
</script>
<style scoped>
.int-loader {
margin: auto;
border: 5px solid #f3f3f3; /* Light grey */
border-top: 5px solid #1c3d62; /* Blue */
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<template>
<v-navigation-drawer class="int-navigation-drawer" permanent clipped app touchless :width="computedWidth"
:min-width="computedWidth" mini-variant-width="40" :mini-variant="collapsed" :right="right">
<v-btn v-if="collapse" :class="right ? 'float-left' : 'float-right'" icon
:title="collapsed ? 'Show Panel' : 'Hide Panel'" @click.stop="onCollapseClick()">
<v-icon>{{ chevronIcon }}</v-icon>
</v-btn>
<slot v-if="!collapsed" name="default" />
<slot v-else name="collapsed" />
</v-navigation-drawer>
</template>
<script>
import { VNavigationDrawer } from 'vuetify/lib';
import PlotHostHeightUtil from '../utils/PlotHostHeightUtil';
export default {
name: 'IntSidebar',
components: { VNavigationDrawer },
props: {
right: {
type: Boolean,
default: false
},
collapse: {
type: Boolean,
default: false
},
isCollapsed: {
type: Boolean,
default: false
},
closable: {
type: Boolean,
default: false
},
width: {
type: [Number, String],
default: 236
}
},
data() {
return {
collapsed: this.isCollapsed
};
},
computed: {
chevronIcon: function () {
const collapsedIcon = this.right ? 'mdi-chevron-double-left' : 'mdi-chevron-double-right';
const defaultIcon = this.right ? 'mdi-chevron-double-right' : 'mdi-chevron-double-left';
return this.collapsed ? collapsedIcon : defaultIcon;
},
computedWidth: function () {
// TODO: Should also accept string, but because of a bug in vuetify resize doesn't work or
// because the navigation drawer is inside v-content which is forbidden by docs
return parseInt(this.width);
}
},
watch: {
isCollapsed(val) {
this.collapsed = val;
}
},
methods: {
onCollapseClick: function () {
this.collapsed = !this.collapsed;
this.$emit('collapse', this.collapsed);
},
plotHostHeight() {
return new PlotHostHeightUtil().plotHostHeight;
}
}
};
</script>
<style scoped>
.int-navigation-drawer {
top: auto !important;
vertical-align: top;
}
.int-navigation-drawer.v-navigation-drawer--mini-variant {
width: 40px !important;
min-width: 40px;
}
.int-navigation-drawer>>>button {
outline: none;
}
.int-navigation-drawer.theme--dark {
background-color: #272727;
}
</style>
<template>
<div>
<v-tooltip bottom>
<template v-slot:activator="on">
<v-btn
class="int-sidebar-mini-button"
:title="title"
width="100%"
min-width="100%"
tile
text
height="110px"
:ripple="false"
v-on="on"
@click="$emit('input', true)"
>
{{ title }}
</v-btn>
</template>
<span>{{ title }}</span>
</v-tooltip>
<int-dialog
absolute
:title="title"
:max-width="dialogWidth"
:min-width="dialogWidth"
:width="dialogWidth"
:value="value"
:position="absolutePosition"
@input="$emit('input', $event)"
>
<slot name="dialog-content" />
</int-dialog>
</div>
</template>
<script>
import {VBtn, VTooltip} from 'vuetify/lib';
import IntDialog from '../components/IntDialog.vue';
const SIDE_MARGIN = '45px';
const TOP_MARGIN = '190px';
export default {
name: 'IntSidebarMiniButton',
components: {VBtn, VTooltip, IntDialog},
props: {
title: {type: String, default: ''},
right: {type: Boolean, default: false},
value: {type: Boolean, default: false},
dialogWidth: {type: [String, Number], default: '600px'}
},
computed: {
absolutePosition: function () {
return {
top: TOP_MARGIN,
left: this.right ? null : SIDE_MARGIN,
right: this.right ? SIDE_MARGIN : null
};
}
}
};
</script>
<style scoped>
.int-sidebar-mini-button {
font: bold 12px Arial;
transition: none !important;
}
::v-deep .v-btn__content {
transition: none !important;
transform: rotate(-90deg);
}
::v-deep .v-btn.outlined {
background-color: rgba(155, 155, 155, 0.5);
}
</style>
<template>
<v-slider
class="int-slider"
:input-value="value"
v-bind="$props"
v-on="$listeners"
>
<template v-slot:prepend>
<slot name="prepend" />
</template>
<template v-slot:append>
<slot name="append" />
</template>
</v-slider>
</template>
<script>
import {VSlider} from 'vuetify/lib';
export default {
name: 'IntSlider',
components: {VSlider},
props: {
label: {
type: String,
default: ''
},
max: {
type: [String, Number],
default: 0
},
min: {
type: [String, Number],
default: 0
},
step: {
type: Number,
default: 1
},
value: {
type: Number,
default: 1
}
}
};
</script>
<style scoped>
.int-slider {
max-height: 30px;
max-width: 200px;
}
</style>
<template>
<!-- 左侧面板组件,用于配置绘图形状和样式 -->
<int-sidebar
v-if="visible"
collapse
:is-collapsed="collapse"
width="260px"
@collapse="collapse=$event"
>
<!-- 默认展开状态的内容 -->
<template v-slot:default>
<!-- 可折叠面板组 -->
<int-expansion-panels :opened-panels="openedPanels">
<!-- 形状选择面板 -->
<int-expansion-panel
title="Shapes"
>
<v-row no-gutters>
<v-col
v-for="(icon, shape) in shapes"
:key="icon"
cols="3"
>
<!-- 形状选择按钮 -->
<v-btn
ref="shapeButtons"
icon
class="mx-2"
:title="shape"
:class="{'outlined': activeShape === shape}"
@click="setShape(shape)"
>
<v-icon>{{ icon }}</v-icon>
</v-btn>
</v-col>
</v-row>
</int-expansion-panel>
<!-- 填充样式面板,只有当fillStyle存在时显示 -->
<int-expansion-panel
v-if="fillStyle != null"
title="Fill Style"
>
<!-- 颜色输入组件,用于设置填充颜色和模式 -->
<ColorInput
ref="fillInput"
name="Fill"
:color="fillStyle.color"
:pattern="fillStyle.pattern"
:pattern-list="FILL_PATTERNS"
@changed="updateFill"
@eyedropper-changed="updateEyeDropper"
/>
</int-expansion-panel>
<!-- 线条样式面板,只有当lineStyle存在时显示 -->
<int-expansion-panel
v-if="lineStyle != null"
title="Line Style"
>
<!-- 颜色输入组件,用于设置线条颜色和模式 -->
<ColorInput
ref="lineInput"
name="Line"
:color="lineStyle.color"
:pattern="lineStyle.pattern"
:pattern-list="LINE_PATTERNS"
@changed="updateLine"
@eyedropper-changed="updateEyeDropper"
/>
<!-- 线条宽度滑块控件 -->
<int-slider
max="12"
min="1"
label="Width"
:value="lineStyle.width"
@input="updateLineStyleWidth"
>
<template v-slot:append>
{{ lineStyle.width }}
</template>
</int-slider>
</int-expansion-panel>
<!-- 文本样式面板,只有当textStyle存在时显示 -->
<int-expansion-panel
v-if="textStyle != null"
title="Text Style"
>
<!-- 颜色输入组件,用于设置文本颜色和字体 -->
<ColorInput
ref="textInput"
name="Text"
:color="textStyle.color"
:pattern="textStyle.font"
:pattern-list="TEXT_PATTERNS"
@changed="updateText"
@eyedropper-changed="updateEyeDropper"
/>
<!-- 文本大小控制 -->
<v-row>
<v-col class="px-3 pb-0">
<v-slider
:value="textStyle.size"
title="Text Size"
class="align-center"
max="60"
min="8"
hide-details
@input="updateTextSize"
>
<template v-slot:append>
<!-- 文本大小输入框 -->
<v-text-field
title="Text Size"
:value="textStyle.size"
class="mt-0 pt-0 paint-text-item"
hide-details
single-line
min="5"
type="number"
style="width: 40px"
@input="updateTextSize"
/>
</template>
</v-slider>
</v-col>
</v-row>
<!-- 文本对齐和样式按钮组 -->
<v-row
class="px-1"
no-gutters
justify="space-between"
style="width: 100%"
>
<v-btn-toggle
multiple
tile
:value="textStyle.icons"
:dark="dark"
@change="updateTextIcons"
>
<!-- 左对齐按钮 -->
<v-btn
style="min-width: 20%; max-width: 20%"
title="Left Align"
value="left"
height="35"
@click="textStyle.align = 'left'"
>
<v-icon>mdi-format-align-left</v-icon>
</v-btn>
<!-- 居中对齐按钮 -->
<v-btn
style="min-width: 20%; max-width: 20%"
title="Center Align"
value="center"
height="35"
@click="textStyle.align = 'center'"
>
<v-icon>mdi-format-align-center</v-icon>
</v-btn>
<!-- 右对齐按钮 -->
<v-btn
style="min-width: 20%; max-width: 20%"
title="Right Align"
value="right"
height="35"
@click="textStyle.align = 'right'"
>
<v-icon>mdi-format-align-right</v-icon>
</v-btn>
<!-- 粗体按钮 -->
<v-btn
style="min-width: 20%; max-width: 20%"
title="Bold"
value="bold"
height="35"
@click="textStyle.bold = !textStyle.bold"
>
<v-icon>mdi-format-bold</v-icon>
</v-btn>
<!-- 斜体按钮 -->
<v-btn
style="min-width: 20%; max-width: 20%"
title="Italic"
value="italic"
height="35"
@click="textStyle.italic = !textStyle.italic"
>
<v-icon>mdi-format-italic</v-icon>
</v-btn>
</v-btn-toggle>
</v-row>
</int-expansion-panel>
<!-- 属性面板,只有当相关属性存在时显示 -->
<int-expansion-panel
v-if="props != null && (name || radius != null || sizemode != null || arrow)"
title="Properties"
>
<!-- 名称属性输入框 -->
<v-row
v-if="name != null"
class="px-1"
no-gutters
>
<v-text-field
v-model="name"
label="Name"
required
@input="setProperties({'name': name}); $emit('update')"
/>
</v-row>
<!-- 边框圆角半径输入框 -->
<v-row
v-if="radius != null"
class="px-1"
no-gutters
>
<v-text-field
v-model="radius"
label="Border Radius"
required
min="0"
type="number"
@input="setProperties({'radius': +radius}); $emit('shape-updated')"
/>
</v-row>
<!-- 固定字体大小选项 -->
<v-row
v-if="sizemode != null"
class="px-1"
no-gutters
>
<v-checkbox
v-model="sizemode"
class="mt-0"
label="Fixed font"
required
dense
hide-details
@change="updateSizeMode"
/>
</v-row>
<!-- 箭头宽度输入框 -->
<v-row
v-if="arrow != null"
class="px-1"
no-gutters
>
<v-text-field
v-model="arrow.width"
label="Arrow Width"
min="0"
type="number"
required
@input="setProperties({'symbolend': arrow}); $emit('shape-updated')"
/>
</v-row>
<!-- 箭头高度输入框 -->
<v-row
v-if="arrow != null"
class="px-1"
no-gutters
>
<v-text-field
v-model="arrow.height"
label="Arrow Height"
min="0"
type="number"
required
@input="setProperties({'symbolend': arrow}); $emit('shape-updated')"
/>
</v-row>
</int-expansion-panel>
</int-expansion-panels>
</template>
<!-- TODO rewrite with dialogs, see RB -->
<!-- 折叠状态下的内容 -->
<template v-slot:collapsed>
<!-- 折叠状态下的迷你按钮们 -->
<int-sidebar-mini-button
title="Shapes"
@input="collapse = false;"
/>
<int-sidebar-mini-button
v-if="fillStyle != null"
title="Fill Style"
@input="collapse = false;"
/>
<int-sidebar-mini-button
v-if="lineStyle != null"
title="Line Style"
@input="collapse = false;"
/>
<int-sidebar-mini-button
v-if="textStyle != null"
title="Text Style"
@input="collapse = false;"
/>
<int-sidebar-mini-button
v-if="props != null && (name || radius != null || sizemode != null || arrow)"
title="Properties"
@input="collapse = false;"
/>
</template>
</int-sidebar>
</template>
<script>
// 导入颜色输入组件
import ColorInput from './ColorInput.vue';
// 导入可折叠面板组组件
import IntExpansionPanels from '../components/IntExpansionPanels.vue';
// 导入可折叠面板组件
import IntExpansionPanel from '../components/IntExpansionPanel.vue';
// 导入迷你侧边栏按钮组件
import IntSidebarMiniButton from '../components/IntSidebarMiniButton.vue';
// 导入滑块组件
import IntSlider from '../components/IntSlider.vue';
// 导入侧边栏组件
import IntSidebar from '../components/IntSidebar.vue';
// 导入线条样式类
import {LineStyle} from '@int/geotoolkit/attributes/LineStyle';
// 导入填充样式类
import {FillStyle} from '@int/geotoolkit/attributes/FillStyle';
// 导入文本样式类
import {TextStyle} from '@int/geotoolkit/attributes/TextStyle';
// 导入RGBA颜色类
import {RgbaColor} from '@int/geotoolkit/util/RgbaColor';
// 导入文本大小模式枚举
import {SizeMode} from '@int/geotoolkit/scene/shapes/Text';
// 导入样式模式常量和图案
import {LINE_PATTERNS, FILL_PATTERNS, TEXT_PATTERNS, LINESTYLE_PATTERNS, IMAGE_PATTERNS, LS_KEYS, FS_KEYS} from '@/api/Patterns';
// 导入编辑事件枚举
import {EditEvents} from '@int/geotoolkit/controls/tools/EditEvents';
// 定义工具变量,用于在组件实例间共享
let _tool = null;
export default {
// 组件名称
name: 'LeftPaintPanel',
// 注册使用的子组件
components: {
ColorInput,
IntSidebarMiniButton,
IntExpansionPanel,
IntExpansionPanels,
IntSidebar,
IntSlider
},
// 定义v-model所使用的属性
model: {
prop: 'visible'
},
// 组件接收的属性定义
props: {
// 控制面板是否可见
visible: {
type: Boolean,
default: true
},
// 控制面板是否可切换
toggleable: {
type: Boolean,
default: true
},
// 控制是否使用暗色主题
dark: {
type: Boolean,
default: false
},
// 画布ID
canvasId: {
type: String,
default: 'plot'
},
// 可用的形状及其图标
shapes: {
type: Object,
default: function () {
return {};
}
}
},
// 组件的响应式数据
data () {
return {
// 迷你变体状态
miniVariant: true,
// 当前活动的形状
activeShape: null,
// 当前形状的属性
props: null,
// 填充样式对象
fillStyle: null,
// 线条样式对象
lineStyle: null,
// 文本样式对象
textStyle: null,
// 圆角半径
radius: null,
// 箭头样式对象
arrow: null,
// 名称
name: null,
// 大小模式
sizemode: null,
// 线条模式常量
LINE_PATTERNS,
// 填充模式常量
FILL_PATTERNS,
// 文本模式常量
TEXT_PATTERNS,
// 面板折叠状态
collapse: false,
// 初始打开的面板索引数组(不要移除,Vue如果提供常量给expansion panels会工作不正确)
openedPanels: [0, 1, 2, 3, 4]
};
},
// 组件挂载时的钩子函数
mounted: function () {
// 根据窗口宽度和可切换选项决定是否使用迷你模式
this.miniVariant = this.toggleable && window.innerWidth < 1200;
// 获取画布元素
this.canvas = document.getElementById(this.canvasId);
// 创建用于吸管工具的像素显示框
this.px = document.createElement('div');
// eslint-disable-next-line
this.px.style.cssText = 'position: absolute; margin: 2px 0 0 -12px; left: 0; top: 0; width: 10px; height: 10px; border: 1px solid black; z-index: 2000; pointer-events: none; background-color: blue;';
// 定义事件监听器集合
this.listeners = {
// 鼠标移动事件处理
move: (event) => {
// 如果没有激活的输入框,则不处理
if (this.getActiveInput() == null) return;
// 获取画布上当前位置的像素颜色
const ctx = this.canvas.getContext('2d');
const data = ctx.getImageData(event.offsetX, event.offsetY, 1, 1).data;
// 移动吸管工具的显示框
this.px.style.transform = 'translate(' + event.x + 'px, ' + event.y + 'px)';
// 更新显示框颜色为当前像素颜色
this.px.style.backgroundColor = data[3] === 0 ? 'white' : 'rgb(' + data[0] + ',' + data[1] + ',' + data[2] + ')';
},
// 鼠标按下事件处理
down: (event) => {
// 如果没有激活的输入框,则不处理
if (this.getActiveInput() == null) return;
// 创建颜色对象
const color = new RgbaColor(this.px.style.backgroundColor);
// 获取当前激活的输入框
const input = this.getActiveInput();
if (input != null) {
// 更新颜色值
input.updateColor(color.toHex());
// 禁用吸管工具
input.setEyeDropperEnabled(false);
}
// 阻止事件冒泡
event.stopImmediatePropagation();
},
// 鼠标进入画布事件处理
enter: (event) => {
// 如果没有激活的输入框,则不处理
if (this.getActiveInput() == null) return;
// 添加吸管工具显示框到页面
document.body.appendChild(this.px);
},
// 鼠标离开画布事件处理
leave: (event) => {
// 如果没有激活的输入框,则不处理
if (this.getActiveInput() == null) return;
// 从页面移除吸管工具显示框
document.body.removeChild(this.px);
}
};
// 添加画布事件监听器
this.canvas.addEventListener('pointermove', this.listeners.move);
this.canvas.addEventListener('pointerdown', this.listeners.down);
this.canvas.addEventListener('pointerenter', this.listeners.enter);
this.canvas.addEventListener('pointerleave', this.listeners.leave);
// 触发初始化事件
this.$emit('init');
},
// 组件销毁时的钩子函数
destroyed: function () {
// 移除画布事件监听器
this.canvas.removeEventListener('pointermove', this.listeners.move);
this.canvas.removeEventListener('pointerdown', this.listeners.down);
this.canvas.removeEventListener('pointerenter', this.listeners.enter);
this.canvas.removeEventListener('pointerleave', this.listeners.leave);
},
methods: {
// 初始化绘图工具
init (tool) {
// 保存工具引用
_tool = tool;
// 添加编辑器变更事件监听器
_tool.addListener(EditEvents.EditorChanged, (tool, editor) => {
// 如果没有选择形状或是多个形状,清除属性
if (tool.getShape() == null || Array.isArray(tool.getShape())) {
this.props = null;
this.activeShape = null;
} else {
// 获取当前形状的属性
this.props = tool.getShape().getProperties();
}
// 更新各种样式属性
this.fillStyle = this.getFillStyle();
this.lineStyle = this.getLineStyle();
this.textStyle = this.getTextStyle();
this.name = this.props && this.props['name'] || null;
this.radius = (this.fillStyle || this.lineStyle) && this.props['radius'] != null ? this.props['radius'] : null;
this.arrow = this.getArrowSize();
this.sizemode = this.getSizeMode();
});
},
// 获取填充样式数据
getFillStyle () {
// 从属性中获取填充样式
const style = this.props && this.props['fillstyle'];
if (!style) return null;
// 获取样式模式源和颜色
const source = style.getPattern() ? style.getPattern().getProperties()['src'] : null;
const color = new RgbaColor(style.getColor());
// 返回填充样式对象
return {
color: color.toHex(true).toUpperCase(),
pattern: source ? FS_KEYS.filter((key) => FILL_PATTERNS[key] === source)[0] : FS_KEYS[0]
};
},
// 获取线条样式数据
getLineStyle () {
// 从属性中获取线条样式
const style = this.props && this.props['linestyle'];
if (!style) return null;
// 获取颜色
const color = new RgbaColor(style.getColor());
// 返回线条样式对象
return {
color: color.toHex(true).toUpperCase(),
width: style.getWidth(),
pattern: LS_KEYS.filter((key) => LINESTYLE_PATTERNS[key].toString() === style.getPattern().toString())[0]
};
},
// 获取文本样式数据
getTextStyle () {
// 从属性中获取文本样式
const style = this.props && this.props['textstyle'];
if (!style) return null;
// 获取字体和颜色
const font = style.getProcessedFont();
const color = new RgbaColor(style.getColor());
// 返回文本样式对象
return {
size: parseInt(font['fontsize']),
font: font['fontfamily'],
color: color.toHex(true).toUpperCase(),
icons: [style.getAlignment(), font['fontweight'], font['fontstyle']],
align: style.getAlignment(),
bold: font['fontweight'] === 'bold',
italic: font['fontstyle'] === 'italic'
};
},
// 获取大小模式
getSizeMode () {
// 从属性中获取大小模式
const mode = this.props && this.props['sizemode'];
if (mode == null) return null;
// 判断是否是自动换行模式
return mode === SizeMode.WrappedWidth;
},
// 获取箭头大小
getArrowSize () {
// 从属性中获取箭头样式
const arrow = this.props && this.props['symbolend'];
if (!arrow) return null;
// 返回箭头尺寸对象
return {
width: arrow.getWidth(),
height: arrow.getHeight()
};
},
// 设置当前选中的形状
setShape(shape) {
console.log("点击的形状", shape);
// 如果点击当前已选中的形状,则取消选择
if (this.activeShape === shape) {
if (this.activeShape === null) return;
shape = null;
}
// 更新活动形状
this.activeShape = shape;
// 触发形状变更事件
this.$emit('shape-changed', shape);
},
// 设置活动形状(供外部调用)
setActiveShape (shape) {
this.activeShape = shape;
},
// 更新文本样式
updateText (color, font) {
if (_tool == null) return;
// 更新文本样式数据
this.textStyle.color = color;
this.textStyle.font = font;
// 设置新的文本样式属性
this.setProperties({
'textstyle': new TextStyle(color, 'middle', this.textStyle.align,
this.textStyle.icons[2] + ' ' + this.textStyle.icons[1] + ' ' + this.textStyle.size + 'px ' + font)
});
// 触发形状更新事件
this.$emit('shape-updated');
},
// 更新文本图标状态(粗体、斜体等)
updateTextIcons () {
// 更新文本样式图标数组
this.textStyle.icons = [this.textStyle.align, this.textStyle.bold ? 'bold' : '', this.textStyle.italic ? 'italic' : ''];
// 设置新的文本样式属性
this.setProperties({
'textstyle': new TextStyle(this.textStyle.color, 'middle', this.textStyle.align,
this.textStyle.icons[2] + ' ' + this.textStyle.icons[1] + ' ' + this.textStyle.size + 'px ' + this.textStyle.font)
});
},
// 更新文本大小
updateTextSize (value) {
if (_tool == null) return;
// 更新文本大小
this.textStyle.size = +value;
// 设置新的文本样式属性
this.setProperties({
'textstyle': new TextStyle(this.textStyle.color, 'middle', this.textStyle.align,
this.textStyle.icons[2] + ' ' + this.textStyle.icons[1] + ' ' + this.textStyle.size + 'px ' + this.textStyle.font)
});
},
// 更新填充样式
updateFill (color, pattern) {
if (_tool == null) return;
// 更新填充样式数据
this.fillStyle.color = color;
this.fillStyle.pattern = pattern;
// 设置新的填充样式属性
this.setProperties({
'fillstyle': new FillStyle(color, IMAGE_PATTERNS[pattern])
});
},
// 更新线条样式
updateLine (color, pattern) {
if (_tool == null) return;
// 更新线条样式数据
this.lineStyle.color = color;
this.lineStyle.pattern = pattern;
// 设置新的线条样式属性
this.setProperties({
'linestyle': new LineStyle(this.lineStyle.color, this.lineStyle.width, LINESTYLE_PATTERNS[pattern])
});
},
// 更新线条宽度
updateLineStyleWidth (value) {
if (_tool == null) return;
// 更新线条宽度
this.lineStyle.width = +value;
// 设置新的线条样式属性
this.setProperties({
'linestyle': new LineStyle(this.lineStyle.color, this.lineStyle.width, LINESTYLE_PATTERNS[this.lineStyle.pattern])
});
},
// 更新大小模式
updateSizeMode (value) {
if (_tool == null) return;
// 设置新的大小模式属性
this.setProperties({
'sizemode': value ? SizeMode.WrappedWidth : SizeMode.FixedWidth | SizeMode.FixedHeight
});
// 触发形状更新事件
this.$emit('shape-updated');
},
// 更新吸管工具状态
updateEyeDropper (component, enabled) {
if (enabled) {
// 确保只有一个吸管工具激活
this.getInputs().forEach((input) => input.setEyeDropperEnabled(component === input));
// 添加吸管光标类
this.canvas.classList.add('eyedropper-cursor');
} else {
// 移除吸管光标类
this.canvas.classList.remove('eyedropper-cursor');
// 移除吸管显示框
if (this.px.parentNode) this.px.parentNode.removeChild(this.px);
}
// 触发吸管状态变更事件
this.$emit('eyedropper-changed', enabled);
},
// 获取所有颜色输入组件
getInputs () {
return [this.$refs.fillInput, this.$refs.lineInput, this.$refs.textInput].filter((input) => input != null);
},
// 获取当前激活的颜色输入组件
getActiveInput () {
return this.getInputs().filter((input) => input.isActive())[0] || null;
},
// 切换面板展开/折叠状态
toggle () {
if (!this.toggleable) return;
this.miniVariant = !this.miniVariant;
},
// 设置形状属性
setProperties (props) {
// 设置工具节点属性
_tool.setProperties({'node': props});
// 如果有当前形状,直接设置属性并触发重绘
if (this.props != null) {
_tool.getShape().setProperties(props).invalidate();
}
}
}
};
</script>
<style lang="css">
/* 定义吸管工具光标样式 */
.eyedropper-cursor {
cursor: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAe\
QAAAHkBOLWIEgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAJfSURBVDiNjdFdSJNhFAfw/969U6ZOzS+0nGLaRVcWhgbeDAIvM\
g2bTglXWbCrCEsjZDeBRFBiUBTWhWAXCnVVFAwpQm1OU0IdVpCZygw/lpt7e/c+2/txupBCydkOPHfn9+c85+iICPFWlbWxUtO06zodf1wSf/VqOrlLF\
2/ASautnjemDmTsN/PgOATWV7GyMHeLjwefOtPUkGBK78/KL+RVjaBqGhKMydAbEi/uGVDb1NzKcfqbBpMpObugiFc1ApEGRVYgM4ZohLm5WLiu+UJVU\
mp6d17x4TRN03gWDoOIoCgKGBPhX/EpiqrcjRnAoupiWAhpESYh21yE9eVFiEIITArD71tSIoJgnRp++2HXgGqbLTcnM/1Vp/OG3qRXEWEScgoO4ufyE\
vy+BVkKBusnhgZfAsA/V7C1tOSmJJlGnO3XSgrN+RDFMJydt7HOVKiKiuX5LwHP4OuMP/07JrDa7XkpyWnvne1tJYXm/K0GTgdrbTVW5r8qG6s/SJHlj\
u2G344z9mWNdFxtLS4wH9jaA2Pwzn5C96PHnxWgRgoGDk28G3TtGJmI4HA4khxX2ua+fV8gWZZJlmUSBIHcY+NU02iftVhqsogIuz0QERrOXbo8POr5i\
0VRJLdnjE432b3lJ+oyY2Ei2vqC0Wg8W1ZaCgCIRqOYmp7BnQc93rXAmmX8jWsj1qkBgLe1OI5UlB2tMBh4BDc3MeL24Omz59ObUsgy6nIF98IAwCcm6\
Hsry49xXfcfqh+nvUNCSOzz++YGJicn5f9hAOAlKTp+r+eJjrHo+Rf9fTPxoO31G8TrUH9rumszAAAAAElFTkSuQmCC') 0 16, auto !important;
}
</style>
<!-- 引入面板样式 -->
<style src="../assets/styles/panels.css" scoped />
<style lang="css" scoped>
/* 修复linter错误:使用正确的选择器语法 */
:deep(.int-slider) {
margin-top: 10px;
}
</style>
<template>
<el-button
:icon="icon"
:plain="plain"
:loading="loading"
:title="title"
@click="handleClick"
>
<slot></slot>
</el-button>
</template>
<script>
export default {
name: 'IntButton',
props: {
icon: {
type: String,
default: ''
},
plain: {
type: Boolean,
default: true
},
loading: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
}
},
methods: {
handleClick() {
this.$emit('click');
}
}
};
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<el-collapse-item :name="panelId" :title="title">
<template #title>
<span class="panel-title">{{ title }}</span>
</template>
<div class="panel-content">
<slot></slot>
</div>
</el-collapse-item>
</template>
<script>
export default {
name: 'IntExpansionPanel',
props: {
title: {
type: String,
default: ''
},
expanded: {
type: Boolean,
default: false
},
panelId: {
type: [String, Number],
default() {
return String(Date.now());
}
}
}
}
</script>
<style scoped>
.int-expansion-panel {
margin-bottom: 10px;
border-radius: 4px;
overflow: hidden;
}
.panel-title {
font-weight: bold;
font-size: 14px;
}
.panel-content {
padding: 10px;
}
</style>
\ No newline at end of file
<template>
<el-dialog :visible.sync="showDialog" width="800px" :before-close="onClose" :title="title" append-to-body>
<el-form :model="dialogData" label-width="120px">
<!-- 纸张格式 -->
<el-form-item label="纸张格式">
<el-select v-model="dialogData.paperFormat" @change="onChange">
<el-option v-for="format in papers" :key="format" :label="format" :value="format">
</el-option>
</el-select>
</el-form-item>
<!-- 宽度和高度 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="宽度">
<el-input-number v-model="dialogData.width" :disabled="dialogData.paperFormat !== 'Custom'" :precision="1"
:step="0.1">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="高度">
<el-input-number v-model="dialogData.height" :disabled="dialogData.paperFormat !== 'Custom'" :precision="1"
:step="0.1">
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<!-- 方向和缩放 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="方向">
<el-select v-model="dialogData.orientation" @change="onChange">
<el-option v-for="orient in orientations" :key="orient" :label="orientationLabels[orient] || orient"
:value="orient">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="缩放">
<el-select v-model="dialogData.scaling">
<el-option v-for="scale in scalingOptions" :key="scale" :label="scalingLabels[scale] || scale"
:value="scale">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 保持比例和连续 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item>
<el-checkbox v-model="dialogData.keepAspectRatio">保持比例</el-checkbox>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-checkbox v-model="dialogData.continuous">连续</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<!-- 边距设置 -->
<el-form-item label="单位">
<el-select v-model="dialogData.units">
<el-option v-for="unit in unitOptions" :key="unit" :label="unit" :value="unit">
</el-option>
</el-select>
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上边距">
<el-input-number v-model="dialogData.top" :precision="1" :step="0.1"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下边距">
<el-input-number v-model="dialogData.bottom" :precision="1" :step="0.1"></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="左边距">
<el-input-number v-model="dialogData.left" :precision="1" :step="0.1"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="右边距">
<el-input-number v-model="dialogData.right" :precision="1" :step="0.1"></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-checkbox v-model="dialogData.drawWestToEast">从西到东绘制</el-checkbox>
</el-form-item>
</el-form>
<slot />
<div v-if="exportPending" style="text-align: center; margin: 20px 0;">
<IntLoader label="导出中..." />
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="onClose">关闭</el-button>
<el-button type="primary" :disabled="exportPending" @click="onExport">导出</el-button>
</span>
</el-dialog>
</template>
<script>
import { PaperFormatFactory } from '@int/geotoolkit/scene/exports/PaperFormatFactory.js';
import { PaperOrientation } from '@int/geotoolkit/scene/exports/PaperOrientation.js';
import { ScalingOptions } from '@int/geotoolkit/scene/exports/ScalingOptions.js';
import IntLoader from '@/components/IntLoader.vue';
export default {
name: 'PrintDialog',
components: { IntLoader },
props: {
showDialog: {
type: Boolean,
default: false
},
exportPending: {
type: Boolean,
default: false
},
title: {
type: String,
default: 'Export to PDF'
},
paperFormat: {
type: String,
default: 'Letter'
},
orientation: {
type: String,
default: PaperOrientation.Portrait
},
top: {
type: [Number, String],
default: 1
},
bottom: {
type: [Number, String],
default: 1
},
left: {
type: [Number, String],
default: 0.5
},
right: {
type: [Number, String],
default: 0.5
},
keepAspectRatio: {
type: [Boolean, String],
default: false
},
scaling: {
type: [String],
default: ScalingOptions.FitToPage
},
continuous: {
type: [Boolean, String],
default: false
},
drawWestToEast: {
type: [Boolean, String],
default: false
},
units: {
type: String,
default: 'cm'
}
},
data() {
return {
paperFactory: null,
papers: [],
orientations: [],
scalingOptions: [],
unitOptions: ['cm', 'mm', 'px', 'inch'],
dialogData: {},
// 方向选项的中文映射
orientationLabels: {
'Portrait': '纵向',
'Landscape': '横向'
},
// 缩放选项的中文映射
scalingLabels: {
'AsIs': '原始大小',
'FitBoth': '适应页面',
'FitWidth': '适应宽度',
'FitHeight': '适应高度',
'Custom': '自定义'
}
};
},
created() {
this.paperFactory = PaperFormatFactory.getInstance();
this.papers = this.paperFactory.getPaperList();
this.orientations = Object.keys(PaperOrientation);
this.scalingOptions = Object.keys(ScalingOptions);
this.dialogData = {
'paperFormat': this.paperFormat,
'orientation': this.orientation,
'top': Number(this.top),
'bottom': Number(this.bottom),
'left': Number(this.left),
'right': Number(this.right),
'scaling': this.scaling,
'keepAspectRatio': this.keepAspectRatio === 'true' || this.keepAspectRatio,
'continuous': this.continuous === 'true' || this.continuous,
'units': this.units,
'drawWestToEast': this.drawWestToEast === 'true' || this.drawWestToEast,
'width': 10,
'height': 15
};
// 初始化宽高
const paper = this.getPaper();
this.dialogData.width = +paper.getWidth().toFixed('1');
this.dialogData.height = +paper.getHeight().toFixed('1');
},
methods: {
getPaper() {
const { paperFormat, units, orientation } = this.dialogData;
return this.paperFactory.getPaper(paperFormat, units, orientation);
},
onChange() {
const paper = this.getPaper();
this.dialogData.width = +paper.getWidth().toFixed('1');
this.dialogData.height = +paper.getHeight().toFixed('1');
},
onExport() {
const settings = {
...this.dialogData,
'paperFormat': this.getPaper()
};
this.$emit('save', { 'printSettings': settings });
},
onClose() {
this.$emit('close');
}
}
};
</script>
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>若依后台管理框架</h2>
<p>
一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
</p>
<p>
<b>当前版本:</b> <span>v{{ version }}</span>
</p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button
type="primary"
size="mini"
icon="el-icon-cloudy"
plain
@click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
>访问码云</el-button
>
<el-button
size="mini"
icon="el-icon-s-home"
plain
@click="goTarget('http://ruoyi.vip')"
>访问主页</el-button
>
</p>
</el-col>
<el-col :sm="24" :lg="12" style="padding-left: 50px">
<el-row>
<el-col :span="12">
<h2>技术选型</h2>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<h4>后端技术</h4>
<ul>
<li>SpringBoot</li>
<li>Spring Security</li>
<li>JWT</li>
<li>MyBatis</li>
<li>Druid</li>
<li>Fastjson</li>
<li>...</li>
</ul>
</el-col>
<el-col :span="6">
<h4>前端技术</h4>
<ul>
<li>Vue</li>
<li>Vuex</li>
<li>Element-ui</li>
<li>Axios</li>
<li>Sass</li>
<li>Quill</li>
<li>...</li>
</ul>
</el-col>
</el-row>
</el-col>
</el-row>
<el-divider />
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>联系信息</span>
</div>
<div class="body">
<p>
<i class="el-icon-s-promotion"></i> 官网:<el-link
href="http://www.ruoyi.vip"
target="_blank"
>http://www.ruoyi.vip</el-link
>
</p>
<p>
<i class="el-icon-user-solid"></i> QQ群:<s> 满937441 </s> <s> 满887144332 </s>
<s> 满180251782 </s> <s> 满104180207 </s> <s> 满186866453 </s> <s> 满201396349 </s>
<s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s>
<s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s>
<s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s>
<s> 满161281055 </s> <s> 满138988063 </s> <s> 满151450850 </s> <s> 满224622315 </s>
<s> 满287842588 </s> <s> 满187944233 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329" target="_blank">228578329</a>
</p>
<p>
<i class="el-icon-chat-dot-round"></i> 微信:<a
href="javascript:;"
>/ *若依</a
>
</p>
<p>
<i class="el-icon-money"></i> 支付宝:<a
href="javascript:;"
class="支付宝信息"
>/ *若依</a
>
</p>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>更新日志</span>
</div>
<el-collapse accordion>
<el-collapse-item title="v3.8.9 - 2024-12-30">
<ol>
<li>用户管理支持分栏拖动</li>
<li>修改主题样式本地读取</li>
<li>用户头像http(s)链接支持</li>
<li>用户管理过滤掉已禁用部门</li>
<li>支持自定义显示Excel属性列</li>
<li>操作日志记录DELETE请求参数</li>
<li>白名单支持对通配符路径匹配</li>
<li>校检文件名是否包含特殊字符</li>
<li>代码生成创建表屏蔽违规的字符</li>
<li>菜单面包屑导航支持多层级显示</li>
<li>Excel注解支持wrapText是否允许内容换行</li>
<li>代码生成新增配置是否允许文件覆盖到本地</li>
<li>修复角色禁用权限不失效问题</li>
<li>修复代码生成上级菜单显示问题</li>
<li>修复导出子列表对象只能在最后的问题</li>
<li>修复TopNav无法正确获取active的问题</li>
<li>修复默认关闭Tags-Views内链页面打不开</li>
<li>升级oshi到最新版本6.6.5</li>
<li>升级tomcat到最新版本9.0.96</li>
<li>升级fastjson到最新版2.0.53</li>
<li>升级logback到最新版本1.2.13</li>
<li>升级spring-framework到最新版本5.3.39</li>
<li>升级quill到最新版本2.0.2</li>
<li>升级axios到最新版本0.28.1</li>
<li>优化身份证脱敏正则</li>
<li>优化权限更新后同步缓存</li>
<li>优化查询时间范围日期格式</li>
<li>优化参数键值更换为多行文本</li>
<li>优化导入带标题文件关闭清理</li>
<li>优化上传图片带域名不增加前缀</li>
<li>优化特殊字符密码修改失败问题</li>
<li>优化无用户编号不校验数据权限</li>
<li>优化TopNav内链菜单点击没有高亮</li>
<li>优化菜单管理切换Mini布局错乱问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.8 - 2024-06-30">
<ol>
<li>菜单管理新增路由名称</li>
<li>新增数据脱敏过滤注解</li>
<li>用户密码新增非法字符验证</li>
<li>限制用户操作数据权限范围</li>
<li>代码生成新增创建表结构功能</li>
<li>定时任务白名单配置范围缩小</li>
<li>优化代码生成主子表关联查询方式</li>
<li>Excel注解新增属性comboReadDict</li>
<li>Excel注解ColumnType类型新增文本</li>
<li>新增国际化资源文件配置</li>
<li>升级oshi到最新版本6.6.1</li>
<li>升级druid到最新版本1.2.23</li>
<li>升级core-js到最新版本3.37.1</li>
<li>更新HttpUtils中的User-Agent</li>
<li>更新compressionPlugin到6.1.2以兼容node18+</li>
<li>升级spring-security到安全版本,防止漏洞风险</li>
<li>升级spring-framework到安全版本,防止漏洞风险</li>
<li>优化自定义XSS注解匹配方式</li>
<li>优化缓存监控键名列表排序显示</li>
<li>优化定时任务日志默认按时间排序</li>
<li>优化默认文件大小超过2G无效的问题</li>
<li>优化查表特殊字符使用反斜杠进行转义</li>
<li>优化定时任务cron表达式小时配置显示错误问题</li>
<li>优化多个自定数据权限使用in查询,避免多次拼接</li>
<li>优化导入Excel时设置dictType属性重复查缓存问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.7 - 2023-12-08">
<ol>
<li>操作日志记录部门名称</li>
<li>全局数据存储用户编号</li>
<li>新增编程式判断资源访问权限</li>
<li>操作日志列表新增IP地址查询</li>
<li>定时任务新增页去除状态选项</li>
<li>代码生成支持选择前端模板类型</li>
<li>显隐列组件支持复选框弹出类型</li>
<li>通用排序属性orderBy参数限制长度</li>
<li>Excel自定义数据处理器增加单元格/工作簿对象</li>
<li>升级oshi到最新版本6.4.8</li>
<li>升级druid到最新版本1.2.20</li>
<li>升级fastjson到最新版2.0.43</li>
<li>升级pagehelper到最新版1.4.7</li>
<li>升级commons.io到最新版本2.13.0</li>
<li>升级element-ui到最新版本2.15.14</li>
<li>修复五级路由缓存无效问题</li>
<li>修复外链带端口出现的异常</li>
<li>修复树模板父级编码变量错误</li>
<li>修复字典表详情页面搜索问题</li>
<li>修复内链iframe没有传递参数问题</li>
<li>修复自定义字典样式不生效的问题</li>
<li>修复字典缓存删除方法参数错误问题</li>
<li>修复Excel导入数据临时文件无法删除问题</li>
<li>修复未登录带参数访问成功后参数丢失问题</li>
<li>修复HeaderSearch组件跳转query参数丢失问题</li>
<li>修复代码生成导入后必填项与数据库不匹配问题</li>
<li>修复Excels导入时无法获取到dictType字典值问题</li>
<li>优化下载zip方法新增遮罩层</li>
<li>优化头像上传参数新增文件名称</li>
<li>优化字典标签支持自定义分隔符</li>
<li>优化菜单管理类型为按钮状态可选</li>
<li>优化前端防重复提交数据大小限制</li>
<li>优化TopNav菜单没有图标svg不显示</li>
<li>优化数字金额大写转换精度丢失问题</li>
<li>优化富文本Editor组件检验图片格式</li>
<li>优化页签在Firefox浏览器被遮挡的问题</li>
<li>优化个人中心/基本资料修改时数据显示问题</li>
<li>优化缓存监控图表支持跟随屏幕大小自适应调整</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.6 - 2023-06-30">
<ol>
<li>支持登录IP黑名单限制</li>
<li>新增监控页面图标显示</li>
<li>操作日志新增消耗时间属性</li>
<li>屏蔽定时任务bean违规的字符</li>
<li>日志管理使用索引提升查询性能</li>
<li>日志注解支持排除指定的请求参数</li>
<li>支持自定义隐藏属性列过滤子对象</li>
<li>升级oshi到最新版本6.4.3</li>
<li>升级druid到最新版本1.2.16</li>
<li>升级fastjson到最新版2.0.34</li>
<li>升级spring-boot到最新版本2.5.15</li>
<li>升级element-ui到最新版本2.15.13</li>
<li>移除apache/commons-fileupload依赖</li>
<li>修复页面切换时布局错乱的问题</li>
<li>修复匿名注解Anonymous空指针问题</li>
<li>修复路由跳转被阻止时内部产生报错信息问题</li>
<li>修复isMatchedIp的参数判断产生空指针的问题</li>
<li>修复用户多角色数据权限可能出现权限抬升的情况</li>
<li>修复开启TopNav后一级菜单路由参数设置无效问题</li>
<li>修复DictTag组件value没有匹配的值时则展示value</li>
<li>优化文件下载出现的异常</li>
<li>优化选择图标组件高亮回显</li>
<li>优化弹窗后导航栏偏移的问题</li>
<li>优化修改密码日志存储明文问题</li>
<li>优化页签栏关闭其他出现的异常问题</li>
<li>优化页签关闭左侧选项排除首页选项</li>
<li>优化关闭当前tab页跳转最右侧tab页</li>
<li>优化缓存列表清除操作提示不变的问题</li>
<li>优化字符未使用下划线不进行驼峰式处理</li>
<li>优化用户导入更新时需获取用户编号问题</li>
<li>优化侧边栏的平台标题与VUE_APP_TITLE保持同步</li>
<li>优化导出Excel时设置dictType属性重复查缓存问题</li>
<li>连接池Druid支持新的配置connectTimeout和socketTimeout</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.5 - 2023-01-01">
<ol>
<li>定时任务违规的字符</li>
<li>重置时取消部门选中</li>
<li>新增返回警告消息提示</li>
<li>忽略不必要的属性数据返回</li>
<li>修改参数键名时移除前缓存配置</li>
<li>导入更新用户数据前校验数据权限</li>
<li>兼容Excel下拉框内容过多无法显示的问题</li>
<li>升级echarts到最新版本5.4.0</li>
<li>升级core-js到最新版本3.25.3</li>
<li>升级oshi到最新版本6.4.0</li>
<li>升级kaptcha到最新版2.3.3</li>
<li>升级druid到最新版本1.2.15</li>
<li>升级fastjson到最新版2.0.20</li>
<li>升级pagehelper到最新版1.4.6</li>
<li>优化弹窗内容过多展示不全问题</li>
<li>优化swagger-ui静态资源使用缓存</li>
<li>开启TopNav没有子菜单隐藏侧边栏</li>
<li>删除fuse无效选项maxPatternLength</li>
<li>优化导出对象的子列表为空会出现[]问题</li>
<li>优化编辑头像时透明部分会变成黑色问题</li>
<li>优化小屏幕上修改头像界面布局错位的问题</li>
<li>修复代码生成勾选属性无效问题</li>
<li>修复文件上传组件格式验证问题</li>
<li>修复回显数据字典数组异常问题</li>
<li>修复sheet超出最大行数异常问题</li>
<li>修复Log注解GET请求记录不到参数问题</li>
<li>修复调度日志点击多次数据不变化的问题</li>
<li>修复主题颜色在Drawer组件不会加载问题</li>
<li>修复文件名包含特殊字符的文件无法下载问题</li>
<li>修复table中更多按钮切换主题色未生效修复问题</li>
<li>修复某些特性的环境生成代码变乱码TXT文件问题</li>
<li>修复代码生成图片/文件/单选时选择必填无法校验问题</li>
<li>修复某些特性的情况用户编辑对话框中角色和部门无法修改问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.4 - 2022-09-26">
<ol>
<li>数据逻辑删除不进行唯一验证</li>
<li>Excel注解支持导出对象的子列表方法</li>
<li>Excel注解支持自定义隐藏属性列</li>
<li>Excel注解支持backgroundColor属性设置背景色</li>
<li>支持配置密码最大错误次数/锁定时间</li>
<li>登录日志新增解锁账户功能</li>
<li>通用下载方法新增config配置选项</li>
<li>支持多权限字符匹配角色数据权限</li>
<li>页面内嵌iframe切换tab不刷新数据</li>
<li>操作日志记录支持排除敏感属性字段</li>
<li>修复多文件上传报错出现的异常问题</li>
<li>修复图片预览组件src属性为null值控制台报错问题</li>
<li>升级oshi到最新版本6.2.2</li>
<li>升级fastjson到最新版2.0.14</li>
<li>升级pagehelper到最新版1.4.3</li>
<li>升级core-js到最新版本3.25.2</li>
<li>升级element-ui到最新版本2.15.10</li>
<li>优化任务过期不执行调度</li>
<li>优化字典数据使用store存取</li>
<li>优化修改资料头像被覆盖的问题</li>
<li>优化修改用户登录账号重复验证</li>
<li>优化代码生成同步后值NULL问题</li>
<li>优化定时任务支持执行父类方法</li>
<li>优化用户个人信息接口防止修改部门</li>
<li>优化布局设置使用el-drawer抽屉显示</li>
<li>优化没有权限的用户编辑部门缺少数据</li>
<li>优化日志注解记录限制请求地址的长度</li>
<li>优化excel/scale属性导出单元格数值类型</li>
<li>优化日志操作中重置按钮时重复查询的问题</li>
<li>优化多个相同角色数据导致权限SQL重复问题</li>
<li>优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.3 - 2022-06-27">
<ol>
<li>新增缓存列表菜单功能</li>
<li>代码生成树表新增(展开/折叠)</li>
<li>Excel注解支持color字体颜色</li>
<li>新增Anonymous匿名访问不鉴权注解</li>
<li>用户头像上传限制只能为图片格式</li>
<li>接口使用泛型使其看到响应属性字段</li>
<li>检查定时任务bean所在包名是否为白名单配置</li>
<li>添加页签openPage支持传递参数</li>
<li>用户缓存信息添加部门ancestors祖级列表</li>
<li>升级element-ui到最新版本2.15.8</li>
<li>升级oshi到最新版本6.1.6</li>
<li>升级druid到最新版本1.2.11</li>
<li>升级fastjson到最新版2.0.8</li>
<li>升级spring-boot到最新版本2.5.14</li>
<li>降级jsencrypt版本兼容IE浏览器</li>
<li>删除多余的salt字段</li>
<li>新增获取不带后缀文件名称方法</li>
<li>新增获取配置文件中的属性值方法</li>
<li>新增内容编码/解码方便插件集成使用</li>
<li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li>
<li>优化设置分页参数默认值</li>
<li>优化对空字符串参数处理的过滤</li>
<li>优化显示顺序orderNum类型为整型</li>
<li>优化表单构建按钮不显示正则校验</li>
<li>优化字典数据回显样式下拉框显示值</li>
<li>优化R响应成功状态码与全局保持一致</li>
<li>优化druid开启wall过滤器出现的异常问题</li>
<li>优化用户管理左侧树型组件增加选中高亮保持</li>
<li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
<li>优化默认不启用压缩文件缓存防止node_modules过大</li>
<li>修复字典数据显示不全问题</li>
<li>修复操作日志查询类型条件为0时会查到所有数据</li>
<li>修复Excel注解prompt/combo同时使用不生效问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.2 - 2022-04-01">
<ol>
<li>前端支持设置是否需要防止数据重复提交</li>
<li>开启TopNav没有子菜单情况隐藏侧边栏</li>
<li>侧边栏菜单名称过长悬停显示标题</li>
<li>用户访问控制时校验数据权限,防止越权</li>
<li>导出Excel时屏蔽公式,防止CSV注入风险</li>
<li>组件ImagePreview支持多图预览显示</li>
<li>组件ImageUpload支持多图同时选择上传</li>
<li>组件FileUpload支持多文件同时选择上传</li>
<li>服务监控新增运行参数信息显示</li>
<li>定时任务目标字符串过滤特殊字符</li>
<li>定时任务目标字符串验证包名白名单</li>
<li>代码生成列表图片支持预览</li>
<li>代码生成编辑修改打开新页签</li>
<li>代码生成新增Java类型Boolean</li>
<li>代码生成子表支持日期/字典配置</li>
<li>代码生成同步保留必填/类型选项</li>
<li>升级oshi到最新版本6.1.2</li>
<li>升级fastjson到最新版1.2.80</li>
<li>升级pagehelper到最新版1.4.1</li>
<li>升级spring-boot到最新版本2.5.11</li>
<li>升级spring-boot-mybatis到最新版2.2.2</li>
<li>添加遗漏的分页参数合理化属性</li>
<li>修改npm即将过期的注册源地址</li>
<li>修复分页组件请求两次问题</li>
<li>修复通用文件下载接口跨域问题</li>
<li>修复Xss注解字段值为空时的异常问题</li>
<li>修复选项卡点击右键刷新丢失参数问题</li>
<li>修复表单清除元素位置未垂直居中问题</li>
<li>修复服务监控中运行参数显示条件错误</li>
<li>修复导入Excel时字典字段类型为Long转义为空问题</li>
<li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li>
<li>优化加载字典缓存数据</li>
<li>优化IP地址获取到多个的问题</li>
<li>优化任务队列满时任务拒绝策略</li>
<li>优化文件上传兼容Weblogic环境</li>
<li>优化定时任务默认保存到内存中执行</li>
<li>优化部门修改缩放后出现的错位问题</li>
<li>优化Excel格式化不同类型的日期对象</li>
<li>优化菜单表关键字导致的插件报错问题</li>
<li>优化Oracle用户头像列为空时不显示问题</li>
<li>优化页面若未匹配到字典标签则返回原字典值</li>
<li>优化修复登录失效后多次请求提示多次弹窗问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.1 - 2022-01-01">
<ol>
<li>新增Vue3前端代码生成模板</li>
<li>新增图片预览组件</li>
<li>新增压缩插件实现打包Gzip</li>
<li>自定义xss校验注解实现</li>
<li>自定义文字复制剪贴指令</li>
<li>代码生成预览支持复制内容</li>
<li>路由支持单独配置菜单或角色权限</li>
<li>用户管理部门查询选择节点后分页参数初始</li>
<li>修复用户分配角色属性错误</li>
<li>修复打包后字体图标偶现的乱码问题</li>
<li>修复菜单管理重置表单出现的错误</li>
<li>修复版本差异导致的懒加载报错问题</li>
<li>修复Cron组件中周回显问题</li>
<li>修复定时任务多参数逗号分隔的问题</li>
<li>修复根据ID查询列表可能出现的主键溢出问题</li>
<li>修复tomcat配置参数已过期问题</li>
<li>升级clipboard到最新版本2.0.8</li>
<li>升级oshi到最新版本v5.8.6</li>
<li>升级fastjson到最新版1.2.79</li>
<li>升级spring-boot到最新版本2.5.8</li>
<li>升级log4j2到2.17.1,防止漏洞风险</li>
<li>优化下载解析blob异常提示</li>
<li>优化代码生成字典组重复问题</li>
<li>优化查询用户的角色组&岗位组代码</li>
<li>优化定时任务cron表达式小时设置24</li>
<li>优化用户导入提示溢出则显示滚动条</li>
<li>优化防重复提交标识组合为(key+url+header)</li>
<li>优化分页方法设置成通用方便灵活调用</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.0 - 2021-12-01">
<ol>
<li>新增配套并同步的Vue3前端版本</li>
<li>新增通用方法简化模态/缓存/下载/权限/页签使用</li>
<li>优化导出数据/使用通用下载方法</li>
<li>Excel注解支持自定义数据处理器</li>
<li>Excel注解支持导入导出标题信息</li>
<li>Excel导入支持@Excels注解</li>
<li>新增组件data-dict,简化数据字典使用</li>
<li>新增Jaxb依赖,防止jdk8以上出现的兼容错误</li>
<li>生产环境使用路由懒加载提升页面响应速度</li>
<li>修复五级以上菜单出现的404问题</li>
<li>防重提交注解支持配置间隔时间/提示消息</li>
<li>日志注解新增是否保存响应参数</li>
<li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
<li>升级SpringBoot到最新版本2.5.6</li>
<li>升级pagehelper到最新版1.4.0</li>
<li>升级spring-boot-mybatis到最新版2.2.0</li>
<li>升级oshi到最新版本v5.8.2</li>
<li>升级druid到最新版1.2.8</li>
<li>升级velocity到最新版本2.3</li>
<li>升级fastjson到最新版1.2.78</li>
<li>升级axios到最新版本0.24.0</li>
<li>升级dart-sass到版本1.32.13</li>
<li>升级core-js到最新版本3.19.1</li>
<li>升级jsencrypt到最新版本3.2.1</li>
<li>升级js-cookie到最新版本3.0.1</li>
<li>升级file-saver到最新版本2.0.5</li>
<li>升级sass-loader到最新版本10.1.1</li>
<li>升级element-ui到最新版本2.15.6</li>
<li>新增sendGet无参请求方法</li>
<li>禁用el-tag组件的渐变动画</li>
<li>代码生成点击预览重置激活tab</li>
<li>AjaxResult重写put方法,以方便链式调用</li>
<li>优化登录/验证码请求headers不设置token</li>
<li>优化用户个人信息接口防止修改用户名</li>
<li>优化Cron表达式生成器关闭时销毁避免缓存</li>
<li>优化注册成功提示消息类型success</li>
<li>优化aop语法,使用spring自动注入注解</li>
<li>优化记录登录信息,移除不必要的修改</li>
<li>优化mybatis全局默认的执行器</li>
<li>优化Excel导入图片可能出现的异常</li>
<li>修复代码生成模板主子表删除缺少事务</li>
<li>修复日志记录可能出现的转换异常</li>
<li>修复代码生成复选框字典遗漏问题</li>
<li>修复关闭xss功能导致可重复读RepeatableFilter失效</li>
<li>修复字符串无法被反转义问题</li>
<li>修复后端主子表代码模板方法名生成错误问题</li>
<li>修复xss过滤后格式出现的异常</li>
<li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.7.0 - 2021-09-13">
<ol>
<li>参数管理支持配置验证码开关</li>
<li>新增是否开启用户注册功能</li>
<li>定时任务支持在线生成cron表达式</li>
<li>菜单管理支持配置路由参数</li>
<li>支持自定义注解实现接口限流</li>
<li>Excel注解支持Image图片导入</li>
<li>自定义弹层溢出滚动样式</li>
<li>自定义可拖动弹窗宽度指令</li>
<li>自定义可拖动弹窗高度指令</li>
<li>修复任意账户越权问题</li>
<li>修改时检查用户数据权限范围</li>
<li>修复保存配置主题颜色失效问题</li>
<li>新增暗色菜单风格主题</li>
<li>菜单&部门新增展开/折叠功能</li>
<li>页签新增关闭左侧&添加图标</li>
<li>顶部菜单排除隐藏的默认路由</li>
<li>顶部菜单同步系统主题样式</li>
<li>跳转路由高亮相对应的菜单栏</li>
<li>代码生成主子表多选行数据</li>
<li>日期范围支持添加多组</li>
<li>升级element-ui到最新版本2.15.5</li>
<li>升级oshi到最新版本v5.8.0</li>
<li>升级commons.io到最新版本v2.11.0</li>
<li>定时任务屏蔽ldap远程调用</li>
<li>定时任务屏蔽http(s)远程调用</li>
<li>补充定时任务表字段注释</li>
<li>定时任务对检查异常进行事务回滚</li>
<li>启用父部门状态排除顶级节点</li>
<li>富文本新增上传文件大小限制</li>
<li>默认首页使用keep-alive缓存</li>
<li>修改代码生成字典回显样式</li>
<li>自定义分页合理化传入参数</li>
<li>修复字典组件值为整形不显示问题</li>
<li>修复定时任务日志执行状态显示</li>
<li>角色&菜单新增字段属性提示信息</li>
<li>修复角色分配用户页面参数类型错误提醒</li>
<li>优化布局设置动画特效</li>
<li>优化异常处理信息</li>
<li>优化错误token导致的解析异常</li>
<li>密码框新增显示切换密码图标</li>
<li>定时任务新增更多操作</li>
<li>更多操作按钮添加权限控制</li>
<li>导入用户样式优化</li>
<li>提取通用方法到基类控制器</li>
<li>优化使用权限工具获取用户信息</li>
<li>优化用户不能删除自己</li>
<li>优化XSS跨站脚本过滤</li>
<li>优化代码生成模板</li>
<li>验证码默认20s超时</li>
<li>BLOB下载时清除URL对象引用</li>
<li>代码生成导入表按创建时间排序</li>
<li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
<li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li>
<li>多图上传组件移除多余的api地址&验证失败导致图片删除问题&无法删除相应图片修复</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.6.0 - 2021-07-12">
<ol>
<li>角色管理新增分配用户功能</li>
<li>用户管理新增分配角色功能</li>
<li>日志列表支持排序操作</li>
<li>优化参数&字典缓存操作</li>
<li>系统布局配置支持动态标题开关</li>
<li>菜单路由配置支持内链访问</li>
<li>默认访问后端首页新增提示语</li>
<li>富文本默认上传返回url类型</li>
<li>新增自定义弹窗拖拽指令</li>
<li>全局注册常用通用组件</li>
<li>全局挂载字典标签组件</li>
<li>ImageUpload组件支持多图片上传</li>
<li>FileUpload组件支持多文件上传</li>
<li>文件上传组件添加数量限制属性</li>
<li>富文本编辑组件添加类型属性</li>
<li>富文本组件工具栏配置视频</li>
<li>封装通用iframe组件</li>
<li>限制超级管理员不允许操作</li>
<li>用户信息长度校验限制</li>
<li>分页组件新增pagerCount属性</li>
<li>添加bat脚本执行应用</li>
<li>升级oshi到最新版本v5.7.4</li>
<li>升级element-ui到最新版本2.15.2</li>
<li>升级pagehelper到最新版1.3.1</li>
<li>升级commons.io到最新版本v2.10.0</li>
<li>升级commons.fileupload到最新版本v1.4</li>
<li>升级swagger到最新版本v3.0.0</li>
<li>修复关闭confirm提示框控制台报错问题</li>
<li>修复存在的SQL注入漏洞问题</li>
<li>定时任务屏蔽rmi远程调用</li>
<li>修复用户搜索分页变量错误</li>
<li>修复导出角色数据范围翻译缺少仅本人</li>
<li>修复表单构建选择下拉选择控制台报错问题</li>
<li>优化图片工具类读取文件</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.5.0 - 2021-05-25">
<ol>
<li>新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)</li>
<li>布局设置支持保存&重置配置</li>
<li>修复树表数据显示不全&加载慢问题</li>
<li>新增IE浏览器版本过低提示页面</li>
<li>用户登录后记录最后登录IP&时间</li>
<li>页面导出按钮点击之后添加遮罩</li>
<li>富文本编辑器支持自定义上传地址</li>
<li>富文本编辑组件新增readOnly属性</li>
<li>页签TagsView新增关闭右侧功能</li>
<li>显隐列组件加载初始默认隐藏列</li>
<li>关闭头像上传窗口还原默认图片</li>
<li>个人信息添加手机&邮箱重复验证</li>
<li>代码生成模板导出按钮点击后添加遮罩</li>
<li>代码生成模板树表操作列添加新增按钮</li>
<li>代码生成模板修复主子表字段重名问题</li>
<li>升级fastjson到最新版1.2.76</li>
<li>升级druid到最新版本v1.2.6</li>
<li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li>
<li>升级oshi到最新版本v5.6.0</li>
<li>velocity剔除commons-collections版本,防止3.2.1版本的反序列化漏洞</li>
<li>数据监控页默认账户密码防止越权访问</li>
<li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
<li>修正后端导入表权限标识</li>
<li>修正前端操作日志&登录日志权限标识</li>
<li>设置Redis配置HashKey序列化</li>
<li>删除操作日志记录信息</li>
<li>上传媒体类型添加视频格式</li>
<li>修复请求形参未传值记录日志异常问题</li>
<li>优化xss校验json请求条件</li>
<li>树级结构更新子节点使用replaceFirst</li>
<li>优化ExcelUtil空值处理</li>
<li>日志记录过滤BindingResult对象,防止异常</li>
<li>修改主题后mini类型按钮无效问题</li>
<li>优化通用下载完成后删除节点</li>
<li>通用Controller添加响应返回消息</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.4.0 - 2021-02-22">
<ol>
<li>代码生成模板支持主子表</li>
<li>表格右侧工具栏组件支持显隐列</li>
<li>图片组件添加预览&移除功能</li>
<li>Excel注解支持Image图片导出</li>
<li>操作按钮组调整为朴素按钮样式</li>
<li>代码生成支持文件上传组件</li>
<li>代码生成日期控件区分范围</li>
<li>代码生成数据库文本类型生成表单文本域</li>
<li>用户手机邮箱&菜单组件修改允许空字符串</li>
<li>升级SpringBoot到最新版本2.2.13 提升启动速度</li>
<li>升级druid到最新版本v1.2.4</li>
<li>升级fastjson到最新版1.2.75</li>
<li>升级element-ui到最新版本2.15.0</li>
<li>修复IE11浏览器报错问题</li>
<li>优化多级菜单之间切换无法缓存的问题</li>
<li>修复四级菜单无法显示问题</li>
<li>修正侧边栏静态路由丢失问题</li>
<li>修复角色管理-编辑角色-功能权限显示异常</li>
<li>配置文件新增redis数据库索引属性</li>
<li>权限工具类增加admin判断</li>
<li>角色非自定义权限范围清空选择值</li>
<li>修复导入数据为负浮点数时丢失精度问题</li>
<li>移除path-to-regexp正则匹配插件</li>
<li>修复生成树表代码异常</li>
<li>修改ip字段长度防止ipv6地址长度不够</li>
<li>防止get请求参数值为false或0等特殊值会导致无法正确的传参</li>
<li>登录后push添加catch防止出现检查错误</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.3.0 - 2020-12-14">
<ol>
<li>新增缓存监控功能</li>
<li>支持主题风格配置</li>
<li>修复多级菜单之间切换无法缓存的问题</li>
<li>多级菜单自动配置组件</li>
<li>代码生成预览支持高亮显示</li>
<li>支持Get请求映射Params参数</li>
<li>删除用户和角色解绑关联</li>
<li>去除用户手机邮箱部门必填验证</li>
<li>Excel支持注解align对齐方式</li>
<li>Excel支持导入Boolean型数据</li>
<li>优化头像样式,鼠标移入悬停遮罩</li>
<li>代码生成预览提供滚动机制</li>
<li>代码生成删除多余的数字float类型</li>
<li>修正转换字符串的目标字符集属性</li>
<li>回显数据字典防止空值报错</li>
<li>日志记录增加过滤多文件场景</li>
<li>修改缓存Set方法可能导致嵌套的问题</li>
<li>移除前端一些多余的依赖</li>
<li>防止安全扫描YUI出现的风险提示</li>
<li>修改node-sass为dart-sass</li>
<li>升级SpringBoot到最新版本2.1.18</li>
<li>升级poi到最新版本4.1.2</li>
<li>升级oshi到最新版本v5.3.6</li>
<li>升级bitwalker到最新版本1.21</li>
<li>升级axios到最新版本0.21.0</li>
<li>升级element-ui到最新版本2.14.1</li>
<li>升级vue到最新版本2.6.12</li>
<li>升级vuex到最新版本3.6.0</li>
<li>升级vue-cli到版本4.5.9</li>
<li>升级vue-router到最新版本3.4.9</li>
<li>升级vue-cli到最新版本4.4.6</li>
<li>升级vue-cropper到最新版本0.5.5</li>
<li>升级clipboard到最新版本2.0.6</li>
<li>升级core-js到最新版本3.8.1</li>
<li>升级echarts到最新版本4.9.0</li>
<li>升级file-saver到最新版本2.0.4</li>
<li>升级fuse.js到最新版本6.4.3</li>
<li>升级js-beautify到最新版本1.13.0</li>
<li>升级js-cookie到最新版本2.2.1</li>
<li>升级path-to-regexp到最新版本6.2.0</li>
<li>升级quill到最新版本1.3.7</li>
<li>升级screenfull到最新版本5.0.2</li>
<li>升级sortablejs到最新版本1.10.2</li>
<li>升级vuedraggable到最新版本2.24.3</li>
<li>升级chalk到最新版本4.1.0</li>
<li>升级eslint到最新版本7.15.0</li>
<li>升级eslint-plugin-vue到最新版本7.2.0</li>
<li>升级lint-staged到最新版本10.5.3</li>
<li>升级runjs到最新版本4.4.2</li>
<li>升级sass-loader到最新版本10.1.0</li>
<li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
<li>升级svg-sprite-loader到最新版本5.1.1</li>
<li>升级vue-template-compiler到最新版本2.6.12</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.2.1 - 2020-11-18">
<ol>
<li>阻止任意文件下载漏洞</li>
<li>代码生成支持上传控件</li>
<li>新增图片上传组件</li>
<li>调整默认首页</li>
<li>升级druid到最新版本v1.2.2</li>
<li>mapperLocations配置支持分隔符</li>
<li>权限信息调整</li>
<li>调整sql默认时间</li>
<li>解决代码生成没有bit类型的问题</li>
<li>升级pagehelper到最新版1.3.0</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.2.0 - 2020-10-10">
<ol>
<li>升级springboot版本到2.1.17 提升安全性</li>
<li>升级oshi到最新版本v5.2.5</li>
<li>升级druid到最新版本v1.2.1</li>
<li>升级jjwt到版本0.9.1</li>
<li>升级fastjson到最新版1.2.74</li>
<li>修改sass为node-sass,避免el-icon图标乱码</li>
<li>代码生成支持同步数据库</li>
<li>代码生成支持富文本控件</li>
<li>代码生成页面时不忽略remark属性</li>
<li>代码生成添加select必填选项</li>
<li>Excel导出类型NUMERIC支持精度浮点类型</li>
<li>Excel导出targetAttr优化获取值,防止get方法不规范</li>
<li>Excel注解支持自动统计数据总和</li>
<li>Excel注解支持设置BigDecimal精度&舍入规则</li>
<li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
<li>允许用户分配到部门父节点</li>
<li>菜单新增是否缓存keep-alive</li>
<li>表格操作列间距调整</li>
<li>限制系统内置参数不允许删除</li>
<li>富文本组件优化,支持自定义高度&图片冲突问题</li>
<li>富文本工具栏样式对齐</li>
<li>导入excel整形值校验优化</li>
<li>修复页签关闭所有时固定标签路由不刷新问题</li>
<li>表单构建布局型组件新增按钮</li>
<li>左侧菜单文字过长显示省略号</li>
<li>修正根节点为子部门时,树状结构显示问题</li>
<li>修正调用目标字符串最大长度</li>
<li>修正菜单提示信息错误</li>
<li>修正定时任务执行一次权限标识</li>
<li>修正数据库字符串类型nvarchar</li>
<li>优化递归子节点</li>
<li>优化数据权限判断</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.1.0 - 2020-08-13">
<ol>
<li>表格工具栏右侧添加刷新&显隐查询组件</li>
<li>后端支持CORS跨域请求</li>
<li>代码生成支持选择上级菜单</li>
<li>代码生成支持自定义路径</li>
<li>代码生成支持复选框</li>
<li>Excel导出导入支持dictType字典类型</li>
<li>Excel支持分割字符串组内容</li>
<li>验证码类型支持(数组计算、字符验证)</li>
<li>升级vue-cli版本到4.4.4</li>
<li>修改 node-sass 为 dart-sass</li>
<li>表单类型为Integer/Long设置整形默认值</li>
<li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
<li>优化防重复提交拦截器</li>
<li>优化上级菜单不能选择自己</li>
<li>修复角色的权限分配后,未实时生效问题</li>
<li>修复在线用户日志记录类型</li>
<li>修复富文本空格和缩进保存后不生效问题</li>
<li>修复在线用户判断逻辑</li>
<li>唯一限制条件只返回单条数据</li>
<li>添加获取当前的环境配置方法</li>
<li>超时登录后页面跳转到首页</li>
<li>全局异常状态汉化拦截处理</li>
<li>HTML过滤器改为将html转义</li>
<li>检查字符支持小数点&降级改成异常提醒</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.0.0 - 2020-07-20">
<ol>
<li>单应用调整为多模块项目</li>
<li>升级element-ui版本到2.13.2</li>
<li>删除babel,提高编译速度。</li>
<li>新增菜单默认主类目</li>
<li>编码文件名修改为uuid方式</li>
<li>定时任务cron表达式验证</li>
<li>角色权限修改时已有权限未自动勾选异常修复</li>
<li>防止切换权限用户后登录出现404</li>
<li>Excel支持sort导出排序</li>
<li>创建用户不允许选择超级管理员角色</li>
<li>修复代码生成导入表结构出现异常页面不提醒问题</li>
<li>修复代码生成点击多次表修改数据不变化的问题</li>
<li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
<li>修复布局为small者mini用户表单显示错位问题</li>
<li>修复热部署导致的强换异常问题</li>
<li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
<li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>
<li>生成domain 如果是浮点型 统一用BigDecimal</li>
<li>定时任务调整label-width,防止部署出现错位</li>
<li>调整表头固定列默认样式</li>
<li>代码生成模板调整,字段为String并且必填则加空串条件</li>
<li>代码生成字典Integer/Long使用parseInt</li>
<li>
修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
</li>
<li>修正岗位导出权限注解</li>
<li>禁止加密密文返回前端</li>
<li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
<li>修复首页搜索菜单外链无法点击跳转问题</li>
<li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
<li>用户管理部门分支节点不可检查&显示计数</li>
<li>数据范围过滤属性调整</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.3.0 - 2020-06-01">
<ol>
<li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
<li>dev启动默认打开浏览器</li>
<li>vue-cli使用默认source-map</li>
<li>slidebar eslint报错优化</li>
<li>当tags-view滚动关闭右键菜单</li>
<li>字典管理添加缓存读取</li>
<li>参数管理支持缓存操作</li>
<li>支持一级菜单(和主页同级)在main区域显示</li>
<li>限制外链地址必须以http(s)开头</li>
<li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
<li>修改数据源类型优先级,先根据方法,再根据类</li>
<li>支持是否需要设置token属性,自定义返回码消息。</li>
<li>swagger请求前缀加入配置。</li>
<li>登录地点设置内容过长则隐藏显示</li>
<li>修复定时任务执行一次按钮后不提示消息问题</li>
<li>修改上级部门(选择项排除本身和下级)</li>
<li>通用http发送方法增加参数 contentType 编码类型</li>
<li>更换IP地址查询接口</li>
<li>修复页签变量undefined</li>
<li>添加校验部门包含未停用的子部门</li>
<li>修改定时任务详情下次执行时间日期显示错误</li>
<li>角色管理查询设置默认排序字段</li>
<li>swagger添加enable参数控制是否启用</li>
<li>只对json类型请求构建可重复读取inputStream的request</li>
<li>修改代码生成字典字段int类型没有自动选中问题</li>
<li>vuex用户名取值修正</li>
<li>表格树模板去掉多余的)</li>
<li>代码生成序号修正</li>
<li>全屏情况下不调整上外边距</li>
<li>代码生成Date字段添加默认格式</li>
<li>用户管理角色选择权限控制</li>
<li>修复路由懒加载报错问题</li>
<li>模板sql.vm添加菜单状态</li>
<li>设置用户名称不能修改</li>
<li>dialog添加append-to-body属性,防止ie遮罩</li>
<li>菜单区分状态和显示隐藏功能</li>
<li>升级fastjson到最新版1.2.68 修复安全加固</li>
<li>修复代码生成如果选择字典类型缺失逗号问题</li>
<li>登录请求params更换为data,防止暴露url</li>
<li>日志返回时间格式处理</li>
<li>添加handle控制允许拖动的元素</li>
<li>布局设置点击扩大范围</li>
<li>代码生成列属性排序查询</li>
<li>代码生成列支持拖动排序</li>
<li>修复时间格式不支持ios问题</li>
<li>表单构建添加父级class,防止冲突</li>
<li>定时任务并发属性修正</li>
<li>角色禁用&菜单隐藏不查询权限</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.2.0 - 2020-03-18">
<ol>
<li>系统监控新增定时任务功能</li>
<li>添加一个打包Web工程bat</li>
<li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>
<li>修复点击退出登录有时会无提示问题</li>
<li>修复防重复提交注解无效问题</li>
<li>修复通知公告批量删除异常问题</li>
<li>添加菜单时路由地址必填限制</li>
<li>代码生成字段描述可编辑</li>
<li>修复用户修改个人信息导致缓存不过期问题</li>
<li>个人信息创建时间获取正确属性值</li>
<li>操作日志详细显示正确类型</li>
<li>导入表单击行数据时选中对应的复选框</li>
<li>批量替换表前缀逻辑调整</li>
<li>固定重定向路径表达式</li>
<li>升级element-ui版本到2.13.0</li>
<li>操作日志排序调整</li>
<li>修复charts切换侧边栏或者缩放窗口显示bug</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.1.0 - 2020-02-24">
<ol>
<li>新增表单构建</li>
<li>代码生成支持树表结构</li>
<li>新增用户导入</li>
<li>修复动态加载路由页面刷新问题</li>
<li>修复地址开关无效问题</li>
<li>汉化错误提示页面</li>
<li>代码生成已知问题修改</li>
<li>修复多数据源下配置关闭出现异常处理</li>
<li>添加HTML过滤器,用于去除XSS漏洞隐患</li>
<li>修复上传头像控制台出现异常</li>
<li>修改用户管理分页不正确的问题</li>
<li>修复验证码记录提示错误</li>
<li>修复request.js缺少Message引用</li>
<li>修复表格时间为空出现的异常</li>
<li>添加Jackson日期反序列化时区配置</li>
<li>调整根据用户权限加载菜单数据树形结构</li>
<li>调整成功登录不恢复按钮,防止多次点击</li>
<li>修改用户个人资料同步缓存信息</li>
<li>修复页面同时出现el-upload和Editor不显示处理</li>
<li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
<li>配置文件新增redis密码属性</li>
<li>设置mybatis全局的配置文件</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.0.0 - 2019-12-02">
<ol>
<li>新增代码生成</li>
<li>新增@RepeatSubmit注解,防止重复提交</li>
<li>新增菜单主目录添加/删除操作</li>
<li>日志记录过滤特殊对象,防止转换异常</li>
<li>修改代码生成路由脚本错误</li>
<li>用户上传头像实时同步缓存,无需重新登录</li>
<li>调整切换页签后不重新加载数据</li>
<li>添加jsencrypt实现参数的前端加密</li>
<li>系统退出删除用户缓存记录</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.1.0 - 2019-11-11">
<ol>
<li>新增在线用户管理</li>
<li>新增按钮组功能实现(批量删除、导出、清空)</li>
<li>新增查询条件重置按钮</li>
<li>新增Swagger全局Token配置</li>
<li>新增后端参数校验</li>
<li>修复字典管理页面的日期查询异常</li>
<li>修改时间函数命名防止冲突</li>
<li>去除菜单上级校验,默认为顶级</li>
<li>修复用户密码无法修改问题</li>
<li>修复菜单类型为按钮时不显示权限标识</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.0.0 - 2019-10-08">
<ol>
<li>若依前后端分离系统正式发布</li>
</ol>
</el-collapse-item>
</el-collapse>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>捐赠支持</span>
</div>
<div class="body">
<img
src="@/assets/images/pay.png"
alt="donate"
width="100%"
/>
<span style="display: inline-block; height: 30px; line-height: 30px"
>你可以请作者喝杯咖啡表示鼓励</span
>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: "Index",
data() {
return {
// 版本号
version: "3.8.9"
}
},
methods: {
goTarget(href) {
window.open(href, "_blank")
}
}
}
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul {
padding: 0;
margin: 0;
}
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
ul {
list-style-type: none;
}
h4 {
margin-top: 0px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
p {
margin-top: 10px;
b {
font-weight: 700;
}
}
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
}
}
}
</style>
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">{{title}}</h3>
<h3 class="title">{{ title }}</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
placeholder="账号"
>
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
>
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码"
@keyup.enter.native="handleLogin">
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
@keyup.enter.native="handleLogin">
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
<img :src="codeUrl" @click="getCode" class="login-code-img" />
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<el-button :loading="loading" size="medium" type="primary" style="width:100%;"
@click.native.prevent="handleLogin">
<span v-if="!loading">登 录</span>
<span v-else>登 录 中...</span>
</el-button>
......@@ -84,7 +64,13 @@ export default {
{ required: true, trigger: "blur", message: "请输入您的账号" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" }
{ required: true, trigger: "blur", message: "请输入您的密码" },
{
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/,
message:
'用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号',
trigger: 'blur',
},
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
......@@ -98,7 +84,7 @@ export default {
},
watch: {
$route: {
handler: function(route) {
handler: function (route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
......@@ -142,7 +128,7 @@ export default {
Cookies.remove('rememberMe')
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
this.$router.push({ path: this.redirect || "/" }).catch(() => { })
}).catch(() => {
this.loading = false
if (this.captchaEnabled) {
......@@ -165,6 +151,7 @@ export default {
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
......@@ -177,32 +164,39 @@ export default {
width: 400px;
padding: 25px 25px 5px 25px;
z-index: 1;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
......@@ -215,6 +209,7 @@ export default {
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
......
<template>
<div class="register">
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">{{title}}</h3>
<h3 class="title">{{ title }}</h3>
<el-form-item prop="username">
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="registerForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleRegister"
>
<el-input v-model="registerForm.password" type="password" auto-complete="off" placeholder="密码"
@keyup.enter.native="handleRegister">
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
auto-complete="off"
placeholder="确认密码"
@keyup.enter.native="handleRegister"
>
<el-input v-model="registerForm.confirmPassword" type="password" auto-complete="off" placeholder="确认密码"
@keyup.enter.native="handleRegister">
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="registerForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleRegister"
>
<el-input v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
@keyup.enter.native="handleRegister">
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="register-code">
<img :src="codeUrl" @click="getCode" class="register-code-img"/>
<img :src="codeUrl" @click="getCode" class="register-code-img" />
</div>
</el-form-item>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleRegister"
>
<el-button :loading="loading" size="medium" type="primary" style="width:100%;"
@click.native.prevent="handleRegister">
<span v-if="!loading">注 册</span>
<span v-else>注 册 中...</span>
</el-button>
......@@ -96,8 +76,8 @@ export default {
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
{ pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/, message: '用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号', trigger: 'blur' }
// { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
......@@ -133,7 +113,7 @@ export default {
type: 'success'
}).then(() => {
this.$router.push("/login")
}).catch(() => {})
}).catch(() => { })
}).catch(() => {
this.loading = false
if (this.captchaEnabled) {
......@@ -156,6 +136,7 @@ export default {
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
......@@ -167,32 +148,39 @@ export default {
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.register-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.register-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-register-footer {
height: 40px;
line-height: 40px;
......@@ -205,6 +193,7 @@ export default {
font-size: 12px;
letter-spacing: 1px;
}
.register-code-img {
height: 38px;
}
......
......@@ -6,30 +6,38 @@
<pane size="16">
<el-col>
<div class="head-container">
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search"
style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" />
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false"
:filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
@node-click="handleNodeClick" />
</div>
</el-col>
</pane>
<!--用户数据-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
......@@ -39,19 +47,24 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:user:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
v-hasPermi="['system:user:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport"
v-hasPermi="['system:user:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['system:user:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
......@@ -59,13 +72,18 @@
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible"
:show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible"
:show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible"
:show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber"
v-if="columns[4].visible" width="120" />
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
......@@ -75,20 +93,26 @@
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.userId !== 1">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']">删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
<el-dropdown-item command="handleResetPwd" icon="el-icon-key"
v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList" />
</el-col>
</pane>
</splitpanes>
......@@ -105,7 +129,8 @@
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true"
placeholder="请选择归属部门" />
</el-form-item>
</el-col>
</el-row>
......@@ -137,14 +162,17 @@
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{
dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
......@@ -153,14 +181,16 @@
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择岗位">
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option>
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId"
:disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId"
:disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
......@@ -181,7 +211,9 @@
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
......@@ -189,7 +221,8 @@
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
</div>
<span>仅允许导入xls、xlsx格式文件。</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"
@click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
......@@ -335,10 +368,10 @@ export default {
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
/** 查询部门下拉树结构 */
......@@ -373,11 +406,11 @@ export default {
// 用户状态修改
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
}).catch(function () {
row.status = row.status === "0" ? "1" : "0"
})
},
......@@ -468,26 +501,26 @@ export default {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
inputPattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/,
inputErrorMessage: "用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => { })
},
/** 分配角色操作 */
handleAuthRole: function(row) {
handleAuthRole: function (row) {
const userId = row.userId
this.$router.push("/system/user-auth/role/" + userId)
},
/** 提交按钮 */
submitForm: function() {
submitForm: function () {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
......@@ -509,12 +542,12 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
return delUser(userIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
}).catch(() => { })
},
/** 导出按钮操作 */
handleExport() {
......
<template>
<el-form ref="form" :model="user" :rules="rules" label-width="80px">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password/>
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password/>
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" size="mini" @click="submit">保存</el-button>
......@@ -37,16 +37,16 @@ export default {
// 表单校验
rules: {
oldPassword: [
{ required: true, message: "旧密码不能为空", trigger: "blur" }
{ required: true, message: "旧密码不能为空", trigger: "blur" },
{ pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/, message: '用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号', trigger: 'blur' }
],
newPassword: [
{ required: true, message: "新密码不能为空", trigger: "blur" },
{ min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
{ pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/, message: '用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: "确认密码不能为空", trigger: "blur" },
{ required: true, validator: equalToPassword, trigger: "blur" }
{ pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])\S{6,20}$/, message: '用户密码长度为 6 到 20 个字符,且必须包含字母、数字以及特殊符号', trigger: 'blur' }
]
}
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
'use strict'
const path = require('path')
"use strict";
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir)
return path.join(__dirname, dir);
}
const CompressionPlugin = require('compression-webpack-plugin')
const CompressionPlugin = require("compression-webpack-plugin");
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
const name = process.env.VUE_APP_TITLE || "系统"; // 网页标题
const baseUrl = 'http://localhost:8080' // 后端接口
const baseUrl = "http://localhost:8080"; // 后端接口
const port = process.env.port || process.env.npm_config_port || 80 // 端口
const port = process.env.port || process.env.npm_config_port || 80; // 端口
// vue.config.js 配置说明
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
......@@ -22,117 +22,116 @@ module.exports = {
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
// 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
outputDir: 'dist',
outputDir: "dist",
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
assetsDir: 'static',
assetsDir: "static",
// 是否开启eslint保存检测,有效值:ture | false | 'error'
lintOnSave: process.env.NODE_ENV === 'development',
lintOnSave: process.env.NODE_ENV === "development",
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
transpileDependencies: ['quill'],
transpileDependencies: ["quill"],
// webpack-dev-server 相关配置
devServer: {
host: '0.0.0.0',
host: "0.0.0.0",
port: port,
open: true,
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: baseUrl,
target: `http://192.168.31.108:8999`, //井测试
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
["^" + process.env.VUE_APP_BASE_API]: "",
},
},
// springdoc proxy
'^/v3/api-docs/(.*)': {
"^/v3/api-docs/(.*)": {
target: baseUrl,
changeOrigin: true
}
changeOrigin: true,
},
},
disableHostCheck: true
disableHostCheck: true,
},
css: {
loaderOptions: {
sass: {
sassOptions: { outputStyle: "expanded" }
}
}
sassOptions: { outputStyle: "expanded" },
},
},
},
configureWebpack: {
name: name,
resolve: {
alias: {
'@': resolve('src')
}
"@": resolve("src"),
},
},
plugins: [
// http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
new CompressionPlugin({
cache: false, // 不启用文件缓存
test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式
filename: '[path][base].gz[query]', // 压缩后的文件名
algorithm: 'gzip', // 使用gzip压缩
minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩
deleteOriginalAssets: false // 压缩后删除原文件
})
cache: false, // 不启用文件缓存
test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式
filename: "[path][base].gz[query]", // 压缩后的文件名
algorithm: "gzip", // 使用gzip压缩
minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩
deleteOriginalAssets: false, // 压缩后删除原文件
}),
],
},
chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test
config.plugins.delete('prefetch') // TODO: need test
config.plugins.delete("preload"); // TODO: need test
config.plugins.delete("prefetch"); // TODO: need test
// set svg-sprite-loader
config.module.rule("svg").exclude.add(resolve("src/assets/icons")).end();
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module
.rule('icons')
.rule("icons")
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.include.add(resolve("src/assets/icons"))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: 'icon-[name]'
symbolId: "icon-[name]",
})
.end()
.end();
config.when(process.env.NODE_ENV !== 'development', config => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
config.when(process.env.NODE_ENV !== "development", (config) => {
config
.plugin("ScriptExtHtmlWebpackPlugin")
.after("html")
.use("script-ext-html-webpack-plugin", [
{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
inline: /runtime\..*\.js$/,
},
])
.end();
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single')
})
}
}
config.optimization.splitChunks({
chunks: "all",
cacheGroups: {
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: "initial", // only package third parties that are initially dependent
},
elementUI: {
name: "chunk-elementUI", // split elementUI into a single package
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
},
commons: {
name: "chunk-commons",
test: resolve("src/components"), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true,
},
},
});
config.optimization.runtimeChunk("single");
});
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment