Merge branch '2.0' into 2.0
This commit is contained in:
commit
0b4d60744e
|
|
@ -0,0 +1 @@
|
|||
routers.js
|
||||
|
|
@ -9,6 +9,7 @@ module.exports = {
|
|||
'generator-star-spacing': 'off',
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }]
|
||||
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
|
||||
'no-undef': 'off'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,3 +22,5 @@ yarn-error.log*
|
|||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
|
||||
build/env.js
|
||||
|
|
|
|||
|
|
@ -3402,6 +3402,19 @@
|
|||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"dev": true
|
||||
},
|
||||
"codemirror": {
|
||||
"version": "5.38.0",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.38.0.tgz",
|
||||
"integrity": "sha512-PEPnDg8U3DTGFB/Dn2T/INiRNC9CB5k2vLAQJidYCsHvAgtXbklqnuidEwx7yGrMrdGhl0L0P3iNKW9I07J6tQ=="
|
||||
},
|
||||
"codemirror-spell-checker": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz",
|
||||
"integrity": "sha1-HGYPkIlIPMtRE7m6nKGcP0mTNx4=",
|
||||
"requires": {
|
||||
"typo-js": "1.0.3"
|
||||
}
|
||||
},
|
||||
"collection-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||
|
|
@ -8177,24 +8190,29 @@
|
|||
"dev": true
|
||||
},
|
||||
"iview": {
|
||||
"version": "2.14.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/iview/-/iview-2.14.0-rc.2.tgz",
|
||||
"integrity": "sha512-uednXFP3yH+ow8UDJTMbq6S+5fIxkjXh5Jap2W9zp2JvmunwMmntQmF7R44ZYjq9puB5yZJVYJudNlOTHQT1lw==",
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/iview/-/iview-2.14.1.tgz",
|
||||
"integrity": "sha512-0ykE0nN+uFSpIBqJAwUPotfamajxkYIk5U/Z/SzzQdzl1++byDF/+HDL0w/ShEvHV4h1zJJP6D9jyyK+Qu08Xg==",
|
||||
"requires": {
|
||||
"async-validator": "1.8.2",
|
||||
"deepmerge": "2.1.0",
|
||||
"deepmerge": "2.1.1",
|
||||
"element-resize-detector": "1.1.14",
|
||||
"js-calendar": "1.2.3",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"popper.js": "1.14.3",
|
||||
"tinycolor2": "1.4.1",
|
||||
"v-click-outside-x": "2.4.0"
|
||||
"v-click-outside-x": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"deepmerge": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.0.tgz",
|
||||
"integrity": "sha512-Q89Z26KAfA3lpPGhbF6XMfYAm3jIV3avViy6KOJ2JLzFbeWHOvPQUu5aSJIWXap3gDZC2y1eF5HXEPI2wGqgvw=="
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz",
|
||||
"integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w=="
|
||||
},
|
||||
"v-click-outside-x": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/v-click-outside-x/-/v-click-outside-x-3.0.0.tgz",
|
||||
"integrity": "sha512-VKm35tQ1tlZFXZc527v05sRXbyoQ8KKT1aeefZrcRCW+mPU4KuTiPy4pe1AH8Pibjzx80iU3pNJ4gNUFSXekUQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -9381,6 +9399,11 @@
|
|||
"object-visit": "1.0.1"
|
||||
}
|
||||
},
|
||||
"marked": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz",
|
||||
"integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw=="
|
||||
},
|
||||
"math-expression-evaluator": {
|
||||
"version": "1.2.17",
|
||||
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
|
||||
|
|
@ -13476,6 +13499,16 @@
|
|||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"dev": true
|
||||
},
|
||||
"simplemde": {
|
||||
"version": "1.11.2",
|
||||
"resolved": "https://registry.npmjs.org/simplemde/-/simplemde-1.11.2.tgz",
|
||||
"integrity": "sha1-ojo12XjSxA7wfewAjJLwcNjggOM=",
|
||||
"requires": {
|
||||
"codemirror": "5.38.0",
|
||||
"codemirror-spell-checker": "1.1.2",
|
||||
"marked": "0.4.0"
|
||||
}
|
||||
},
|
||||
"slash": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
||||
|
|
@ -14428,6 +14461,11 @@
|
|||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
},
|
||||
"typo-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.0.3.tgz",
|
||||
"integrity": "sha1-VNjrx5SfGngQkItgAsaEFSbJnVo="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.3.25",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.25.tgz",
|
||||
|
|
@ -14800,11 +14838,6 @@
|
|||
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
|
||||
"dev": true
|
||||
},
|
||||
"v-click-outside-x": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/v-click-outside-x/-/v-click-outside-x-2.4.0.tgz",
|
||||
"integrity": "sha512-xAouyFRaMDD074px+J3PoxhU5nGQsIj8yxXRYyFd0/PRhY1ob3F55L9mGsd35KzXkQteajEhap6SClaMB0MENg=="
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
|
||||
|
|
@ -14881,9 +14914,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"vue-i18n": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-7.6.0.tgz",
|
||||
"integrity": "sha512-IqyGj4nOFrGopCCpRucfMPJSgp5WauuI8HTaAQc7XIpHT7iOH4flndy1g09FiUzidi0lRVKJME+S7sPJny/t/A=="
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-7.8.0.tgz",
|
||||
"integrity": "sha512-06lw8q6+hWhcCq1O5hw7pZ0CYKcY8CFV4iUjKctz5VRXTVvYC/soEfEQyWrQ3qjYHNCtePv/YieArm3pF70JVg=="
|
||||
},
|
||||
"vue-loader": {
|
||||
"version": "15.0.11",
|
||||
|
|
@ -14943,6 +14976,11 @@
|
|||
"browser-process-hrtime": "0.1.2"
|
||||
}
|
||||
},
|
||||
"wangeditor": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-3.1.1.tgz",
|
||||
"integrity": "sha1-+9PB1JdpI8nt67hbKdMLNVEq0Dk="
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
|
||||
|
|
|
|||
|
|
@ -13,19 +13,22 @@
|
|||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"clipboard": "^2.0.0",
|
||||
"codemirror": "^5.38.0",
|
||||
"countup": "^1.8.2",
|
||||
"cropperjs": "^1.3.5",
|
||||
"echarts": "^4.0.4",
|
||||
"html2canvas": "^1.0.0-alpha.12",
|
||||
"iview": "^2.14.0-rc.1",
|
||||
"iview": "^2.14.1",
|
||||
"iview-area": "^1.5.17",
|
||||
"js-cookie": "^2.2.0",
|
||||
"simplemde": "^1.11.2",
|
||||
"sortablejs": "^1.7.0",
|
||||
"tinymce": "^4.7.11",
|
||||
"vue": "^2.5.10",
|
||||
"vue-i18n": "^7.6.0",
|
||||
"vue-i18n": "^7.8.0",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1"
|
||||
"vuex": "^3.0.1",
|
||||
"wangeditor": "^3.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.0.0-beta.10",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import axios from '@/libs/api.request'
|
||||
|
||||
export const getTableData = () => {
|
||||
return axios.request({
|
||||
url: 'get_table_data',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
@font-face {font-family: "iconfont";
|
||||
src: url('iconfont.eot?t=1528361751996'); /* IE9*/
|
||||
src: url('iconfont.eot?t=1528361751996#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAgQAAsAAAAADXAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7knUY21hcAAAAYAAAACXAAACCuRxddRnbHlmAAACGAAAA7cAAAaA6QCNLmhlYWQAAAXQAAAAMQAAADYRnGwraGhlYQAABgQAAAAgAAAAJAfdA4pobXR4AAAGJAAAABkAAAAkI+n//2xvY2EAAAZAAAAAFAAAABQGrAiKbWF4cAAABlQAAAAfAAAAIAEaAG5uYW1lAAAGdAAAAUUAAAJtPlT+fXBvc3QAAAe8AAAAUwAAAGh5QjWjeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/ss4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDx/ytzwv4EhhrmBoQEozAiSAwA2Dg1XeJzFkTsKwzAQRJ/8iwkpQs6Rg6VM6SoYfAVXuY5vYrD3GM5I60YkdTziCTRiV2IWqIFS3EUF4U0gapQbkl9yTn7FQ+cbVzkF3Yq9rLfBJptt2Tbd/fJyBdXnK3qFetc06nuildF81f1N4binc13S/txPSoVuR19ccZScEnfi9Kx34lRtcJQrNjlx0jY7yhpbHNoPwhozgQB4nLVUz2/cRBSeZ3s8zjbrxb+T3fVudjdrp93G2dreH2pCkoamSRGgVEkktkqQIlR1VQlOSO0BVeaAGgECJC6IA1SAhFT+hFalF5Qb4lAJKRwqVP4AjhyyDs+7CSRFcAjCGr/3PPP8/H3vGw+hhOz/wj/gR4hGJsg5cpGsEAJiDcoyZ0PJDT2uBkaJGpYu827FLbFK2eOfB6ss6qbfDB1LZGIGZChAUPKbrse50AhnuWnwTRtgNJddVat5lf8YUiNu4d34Re5LMIqVfGZ2Mr58dk73xzTp5rCqjqrqB5JIqcRxQkaGNyxziA6lxPhrmskaD4qnuSIMj7rZlzrpsZy6tR2+aVetIYAoAi03Jn8zp2QVHG9nTU0dZc+lpZFsujKuw81fT41ow7bzlOBF9/f3PxcI/zqpkiZZIq+SLeSqM9PQZa7scY2w5STYA9+0ZqFvAr/AgT/LYRuwIfq/PVDf1MWyEzYF4nkr799/fP+9K56Xn5ofry1b3rXuNW9kqVadm8rv/ZBSZMZkRVPTkpRWYbqxeWli4tLmjYGD6yk1zVha1RRZkmQl/mmi3V5pt7lvl4JOd+ve7eXl2/e2up1gyVkI8tWiomlKsZoPFuJpo1pv1ccNYxxd1Ygf5yZnFmcmcwcOzh5fH9NtTbN1wuEeiLAvETlFjER9wkxiNUnLIXzA3ECptKwKR3bjJ5RCaXcXSpTGTz6bj6L55OYjfNo9stpbRFmiKEp6zrD2I/4RP4/xEEnhLiuSNnkZv1IpQLJ/yiL9M+JlYAXAtrc80HBflV0PXCds4UTTt3DF1JlYxSTdCpqtvkQmRg0PYKUOuYkcDvjoMHrnYY/S3sO+vRwuLH66+ML1vG3nu3+F8fcLHSrVGQiNVxoCsLpEO/Cznryd0wcOrhzWQNubDezjFQbhd9z6BQYgOr7viADswvo/c7/4H7i7JZEZplVqthrOCSl/Ff+ISBkgaTgJ1S+wS0mBOvsftHUrIpOh7LgORsYgPTwp0eOyLqDSJ5L2qKpconP/f/md3+YlPEfOJWz7ogTMg8rgKMBjoRE6biuZRalCB5ArUkFCMvA39igAvbvjdOrnu6u12mr3LXQFewdom4ISl67e4rhbV/uWl/qTO3bhIA3d+XrH2bmb1NhLK72Zw1S0qEOC7Tf+E14jp0kDsblOpn+LRfg7Psucg+YUCnAM34dnRHFjTaQ1QVjffhbknTVRPCMIaxtCLz6Ck3uK2ZvrgoDvrt15Fu32wcKG2HvtONw/AMgISb8AeJxjYGRgYADiXSzz7sXz23xl4GZhAIHr9iLiMPr///8NLAzMDUAuBwMTSBQAJlsKewAAAHicY2BkYGBu+N/AEMPC8P8/AwMLAwNQBAVwAgB14ARweJxjYWBgYH7JwMDC8P8/CwOIxsQAUdgDCwAAAAAAAAAAdgECATABrgIeApoC6ANAeJxjYGRgYOBkSGJgZwABJiDmAkIGhv9gPgMAE3ABiQB4nGWPTU7DMBCFX/oHpBKqqGCH5AViASj9EatuWFRq911036ZOmyqJI8et1ANwHo7ACTgC3IA78EgnmzaWx9+8eWNPANzgBx6O3y33kT1cMjtyDRe4F65TfxBukF+Em2jjVbhF/U3YxzOmwm10YXmD17hi9oR3YQ8dfAjXcI1P4Tr1L+EG+Vu4iTv8CrfQ8erCPuZeV7iNRy/2x1YvnF6p5UHFockikzm/gple75KFrdLqnGtbxCZTg6BfSVOdaVvdU+zXQ+ciFVmTqgmrOkmMyq3Z6tAFG+fyUa8XiR6EJuVYY/62xgKOcQWFJQ6MMUIYZIjK6Og7VWb0r7FDwl57Vj3N53RbFNT/c4UBAvTPXFO6stJ5Ok+BPV8bUnV0K27LnpQ0kV7NSRKyQl7WtlRC6gE2ZVeOEXpc0Yk/KGdI/wAJWm7IAAAAeJxtxE0KgCAQBtD5UivddJIOZTGR4A+MkdHpC9r2Fo86+jj6Z9FBQcOgx4ARFo5w6YW9TMI13DyfLEdYfTSblJZV4t3UFCKr5LNp5Z3oAd4+EYcA') format('woff'),
|
||||
url('iconfont.ttf?t=1528361751996') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
url('iconfont.svg?t=1528361751996#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family:"iconfont" !important;
|
||||
font-size:16px;
|
||||
font-style:normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-bear:before { content: "\e600"; }
|
||||
|
||||
.icon-resize-vertical:before { content: "\e7c3"; }
|
||||
|
||||
.icon-frown:before { content: "\e77e"; }
|
||||
|
||||
.icon-meh:before { content: "\e780"; }
|
||||
|
||||
.icon-smile:before { content: "\e783"; }
|
||||
|
||||
.icon-man:before { content: "\e7e2"; }
|
||||
|
||||
.icon-woman:before { content: "\e7e5"; }
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<!--
|
||||
2013-9-30: Created.
|
||||
-->
|
||||
<svg>
|
||||
<metadata>
|
||||
Created by iconfont
|
||||
</metadata>
|
||||
<defs>
|
||||
|
||||
<font id="iconfont" horiz-adv-x="1024" >
|
||||
<font-face
|
||||
font-family="iconfont"
|
||||
font-weight="500"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
|
||||
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
|
||||
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
|
||||
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
|
||||
|
||||
|
||||
|
||||
<glyph glyph-name="bear" unicode="" d="M1024 683.008q0-70.656-46.08-121.856 46.08-89.088 46.08-193.536 0-96.256-39.936-181.248t-109.568-147.968-162.816-99.328-199.68-36.352-199.68 36.352-162.304 99.328-109.568 147.968-40.448 181.248q0 104.448 46.08 193.536-46.08 51.2-46.08 121.856 0 37.888 13.824 71.168t37.376 58.368 55.808 39.424 68.096 14.336q43.008 0 78.848-18.432t59.392-50.176q46.08 17.408 96.256 26.624t102.4 9.216 102.4-9.216 96.256-26.624q24.576 31.744 59.904 50.176t78.336 18.432q36.864 0 68.608-14.336t55.296-39.424 37.376-58.368 13.824-71.168zM205.824 268.288q10.24 0 18.944 10.24t15.36 28.672 10.24 42.496 3.584 51.712-3.584 51.712-10.24 41.984-15.36 28.16-18.944 10.24q-9.216 0-17.92-10.24t-15.36-28.16-10.752-41.984-4.096-51.712 4.096-51.712 10.752-42.496 15.36-28.672 17.92-10.24zM512-31.744000000000028q53.248 0 99.84 13.312t81.408 35.84 54.784 52.736 19.968 65.024q0 33.792-19.968 64t-54.784 52.736-81.408 35.84-99.84 13.312-99.84-13.312-81.408-35.84-54.784-52.736-19.968-64q0-34.816 19.968-65.024t54.784-52.736 81.408-35.84 99.84-13.312zM818.176 268.288q10.24 0 18.944 10.24t15.36 28.672 10.24 42.496 3.584 51.712-3.584 51.712-10.24 41.984-15.36 28.16-18.944 10.24q-9.216 0-17.92-10.24t-15.36-28.16-10.752-41.984-4.096-51.712 4.096-51.712 10.752-42.496 15.36-28.672 17.92-10.24zM512 235.51999999999998q39.936 0 68.096-9.728t28.16-24.064-28.16-24.064-68.096-9.728-68.096 9.728-28.16 24.064 28.16 24.064 68.096 9.728z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="resize-vertical" unicode="" d="M512 896C229.248 896 0 666.752 0 384s229.248-512 512-512 512 229.248 512 512S794.752 896 512 896zM576 192l64 0-128-128-128 128 64 0L448 576l-64 0 128 128 128-128-64 0L576 192z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="frown" unicode="" d="M336 475m-48 0a48 48 0 1 1 96 0 48 48 0 1 1-96 0ZM688 475m-48 0a48 48 0 1 1 96 0 48 48 0 1 1-96 0ZM512 832C264.6 832 64 631.4 64 384s200.6-448 448-448 448 200.6 448 448S759.4 832 512 832z m263-711c-34.2-34.2-74-61-118.3-79.8C611 21.8 562.3 12 512 12c-50.3 0-99 9.8-144.8 29.2-44.3 18.7-84.1 45.6-118.3 79.8-34.2 34.2-61 74-79.8 118.3C149.8 285 140 333.7 140 384s9.8 99 29.2 144.8c18.7 44.3 45.6 84.1 79.8 118.3 34.2 34.2 74 61 118.3 79.8C413 746.2 461.7 756 512 756c50.3 0 99-9.8 144.8-29.2 44.3-18.7 84.1-45.6 118.3-79.8 34.2-34.2 61-74 79.8-118.3C874.2 483 884 434.3 884 384s-9.8-99-29.2-144.8c-18.7-44.3-45.6-84.1-79.8-118.2zM512 363c-85.5 0-155.6-67.3-160-151.6-0.2-4.6 3.4-8.4 8-8.4h48.1c4.2 0 7.8 3.2 8.1 7.4C420 259.9 461.5 299 512 299s92.1-39.1 95.8-88.6c0.3-4.2 3.9-7.4 8.1-7.4H664c4.6 0 8.2 3.8 8 8.4-4.4 84.3-74.5 151.6-160 151.6z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="meh" unicode="" d="M336 475m-48 0a48 48 0 1 1 96 0 48 48 0 1 1-96 0ZM688 475m-48 0a48 48 0 1 1 96 0 48 48 0 1 1-96 0ZM512 832C264.6 832 64 631.4 64 384s200.6-448 448-448 448 200.6 448 448S759.4 832 512 832z m263-711c-34.2-34.2-74-61-118.3-79.8C611 21.8 562.3 12 512 12c-50.3 0-99 9.8-144.8 29.2-44.3 18.7-84.1 45.6-118.3 79.8-34.2 34.2-61 74-79.8 118.3C149.8 285 140 333.7 140 384s9.8 99 29.2 144.8c18.7 44.3 45.6 84.1 79.8 118.3 34.2 34.2 74 61 118.3 79.8C413 746.2 461.7 756 512 756c50.3 0 99-9.8 144.8-29.2 44.3-18.7 84.1-45.6 118.3-79.8 34.2-34.2 61-74 79.8-118.3C874.2 483 884 434.3 884 384s-9.8-99-29.2-144.8c-18.7-44.3-45.6-84.1-79.8-118.2zM664 331H360c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h304c4.4 0 8 3.6 8 8v48c0 4.4-3.6 8-8 8z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="smile" unicode="" d="M336 475m-48 0a48 48 0 1 1 96 0 48 48 0 1 1-96 0ZM688 475m-48 0a48 48 0 1 1 96 0 48 48 0 1 1-96 0ZM512 832C264.6 832 64 631.4 64 384s200.6-448 448-448 448 200.6 448 448S759.4 832 512 832z m263-711c-34.2-34.2-74-61-118.3-79.8C611 21.8 562.3 12 512 12c-50.3 0-99 9.8-144.8 29.2-44.3 18.7-84.1 45.6-118.3 79.8-34.2 34.2-61 74-79.8 118.3C149.8 285 140 333.7 140 384s9.8 99 29.2 144.8c18.7 44.3 45.6 84.1 79.8 118.3 34.2 34.2 74 61 118.3 79.8C413 746.2 461.7 756 512 756c50.3 0 99-9.8 144.8-29.2 44.3-18.7 84.1-45.6 118.3-79.8 34.2-34.2 61-74 79.8-118.3C874.2 483 884 434.3 884 384s-9.8-99-29.2-144.8c-18.7-44.3-45.6-84.1-79.8-118.2zM664 363h-48.1c-4.2 0-7.8-3.2-8.1-7.4C604 306.1 562.5 267 512 267s-92.1 39.1-95.8 88.6c-0.3 4.2-3.9 7.4-8.1 7.4H360c-4.6 0-8.2-3.8-8-8.4 4.4-84.3 74.5-151.6 160-151.6s155.6 67.3 160 151.6c0.2 4.6-3.4 8.4-8 8.4z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="man" unicode="" d="M874 776H622c-3.3 0-6-2.7-6-6v-56c0-3.3 2.7-6 6-6h160.4L583.1 508.7c-50 38.5-111 59.3-175.1 59.3-76.9 0-149.3-30-203.6-84.4S120 356.9 120 280s30-149.3 84.4-203.6C258.7 22 331.1-8 408-8s149.3 30 203.6 84.4C666 130.7 696 203.1 696 280c0 64.1-20.8 124.9-59.2 174.9L836 654.1V494c0-3.3 2.7-6 6-6h56c3.3 0 6 2.7 6 6V746c0 16.5-13.5 30-30 30zM408 68c-116.9 0-212 95.1-212 212s95.1 212 212 212 212-95.1 212-212-95.1-212-212-212z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="woman" unicode="" d="M909.7 739.4l-42.2 42.2c-3.1 3.1-8.2 3.1-11.3 0L764 689.4l-84.2 84.2c-3.1 3.1-8.2 3.1-11.3 0l-42.1-42.1c-3.1-3.1-3.1-8.1 0-11.3l84.2-84.2-135.5-135.3c-50 38.5-111 59.3-175.1 59.3-76.9 0-149.3-30-203.6-84.4S112 348.9 112 272s30-149.3 84.4-203.6C250.7 14 323.1-16 400-16s149.3 30 203.6 84.4C658 122.7 688 195.1 688 272c0 64.2-20.9 125.1-59.3 175.1l135.4 135.4 84.2-84.2c3.1-3.1 8.2-3.1 11.3 0l42.1 42.1c3.1 3.1 3.1 8.1 0 11.3l-84.2 84.2 92.2 92.2c3.1 3.1 3.1 8.2 0 11.3zM400 60c-116.9 0-212 95.1-212 212s95.1 212 212 212 212-95.1 212-212-95.1-212-212-212z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
||||
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<component :is="iconType" :type="iconName" :color="iconColor" :size="iconSize"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Icons from '_c/icons'
|
||||
export default {
|
||||
name: 'CommonIcon',
|
||||
components: {Icons},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
color: String,
|
||||
size: Number
|
||||
},
|
||||
computed: {
|
||||
iconType () {
|
||||
return this.type.indexOf('_') === 0 ? 'Icons' : 'Icon'
|
||||
},
|
||||
iconName () {
|
||||
return this.iconType === 'Icons' ? this.getCustomIconName(this.type) : this.type
|
||||
},
|
||||
iconSize () {
|
||||
return this.size || (this.iconType === 'Icons' ? 12 : undefined)
|
||||
},
|
||||
iconColor () {
|
||||
return this.color || ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCustomIconName (iconName) {
|
||||
return iconName.slice(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import CommonIcon from './common-icon.vue'
|
||||
export default CommonIcon
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
<template>
|
||||
<div class="count-to-wrapper">
|
||||
<slot name="left"/>
|
||||
<p class="content-outer"><span :class="['count-to-count-text', countClass]" :id="counterId">{{ init }}</span><i :class="['count-to-unit-text', unitClass]">{{ unitText }}</i></p>
|
||||
<slot name="right"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CountUp from 'countup'
|
||||
import './index.less'
|
||||
export default {
|
||||
name: 'CountTo',
|
||||
props: {
|
||||
init: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* @description 起始值,即动画开始前显示的数值
|
||||
*/
|
||||
startVal: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* @description 结束值,即动画结束后显示的数值
|
||||
*/
|
||||
end: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
/**
|
||||
* @description 保留几位小数
|
||||
*/
|
||||
decimals: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* @description 分隔整数和小数的符号,默认是小数点
|
||||
*/
|
||||
decimal: {
|
||||
type: String,
|
||||
default: '.'
|
||||
},
|
||||
/**
|
||||
* @description 动画持续的时间,单位是秒
|
||||
*/
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
/**
|
||||
* @description 动画持续的时间,单位是秒
|
||||
*/
|
||||
delay: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* @description 是否禁用easing动画效果
|
||||
*/
|
||||
uneasing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* @description 是否使用分组,分组后每三位会用一个符号分隔
|
||||
*/
|
||||
usegroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* @description 用于分组(usegroup)的符号
|
||||
*/
|
||||
separator: {
|
||||
type: String,
|
||||
default: ','
|
||||
},
|
||||
/**
|
||||
* @description 是否简化显示,设为true后会使用unit单位来做相关省略
|
||||
*/
|
||||
simplify: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* @description 自定义单位,如[3, 'K+'], [6, 'M+']即大于3位数小于6位数的用k+来做省略
|
||||
* 1000即显示为1K+
|
||||
*/
|
||||
unit: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [[3, 'K+'], [6, 'M+'], [9, 'B+']]
|
||||
}
|
||||
},
|
||||
countClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
unitClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
counter: null,
|
||||
unitText: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
counterId () {
|
||||
return `count_to_${this._uid}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getHandleVal (val, len) {
|
||||
return {
|
||||
endVal: parseInt(val / Math.pow(10, this.unit[len - 1][0])),
|
||||
unitText: this.unit[len - 1][1]
|
||||
}
|
||||
},
|
||||
transformValue (val) {
|
||||
let len = this.unit.length
|
||||
let res = {
|
||||
endVal: 0,
|
||||
unitText: ''
|
||||
}
|
||||
if (val < Math.pow(10, this.unit[0][0])) res.endVal = val
|
||||
else {
|
||||
for (let i = 1; i < len; i++) {
|
||||
if (val >= Math.pow(10, this.unit[i - 1][0]) && val < Math.pow(10, this.unit[i][0])) res = this.getHandleVal(val, i)
|
||||
}
|
||||
}
|
||||
if (val > Math.pow(10, this.unit[len - 1][0])) res = this.getHandleVal(val, len)
|
||||
return res
|
||||
},
|
||||
getValue (val) {
|
||||
let res = 0
|
||||
if (this.simplify) {
|
||||
let { endVal, unitText } = this.transformValue(val)
|
||||
this.unitText = unitText
|
||||
res = endVal
|
||||
} else {
|
||||
res = val
|
||||
}
|
||||
return res
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
let endVal = this.getValue(this.end)
|
||||
this.counter = new CountUp(this.counterId, this.startVal, endVal, this.decimals, this.duration, {
|
||||
useEasing: !this.uneasing,
|
||||
useGrouping: this.useGroup,
|
||||
separator: this.separator,
|
||||
decimal: this.decimal
|
||||
})
|
||||
if (!this.counter.error) this.counter.start()
|
||||
}, this.delay)
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
end (newVal) {
|
||||
let endVal = this.getValue(newVal)
|
||||
this.counter.update(endVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import countTo from './count-to.vue'
|
||||
export default countTo
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
@prefix: ~"count-to";
|
||||
|
||||
.@{prefix}-wrapper{
|
||||
.content-outer{
|
||||
display: inline-block;
|
||||
.@{prefix}-unit-text{
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<template>
|
||||
<div class="editor-wrapper">
|
||||
<div :id="editorId"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Editor from 'wangeditor'
|
||||
import 'wangeditor/release/wangEditor.min.css'
|
||||
import { oneOf } from '@/libs/tools'
|
||||
export default {
|
||||
name: 'Editor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/**
|
||||
* 绑定的值的类型, enum: ['html', 'text']
|
||||
*/
|
||||
valueType: {
|
||||
type: String,
|
||||
default: 'html',
|
||||
validator: (val) => {
|
||||
return oneOf(val, ['html', 'text'])
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 设置change事件触发时间间隔
|
||||
*/
|
||||
changeInterval: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
/**
|
||||
* @description 是否开启本地存储
|
||||
*/
|
||||
cache: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editorId () {
|
||||
return `editor${this._uid}`
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.editor = new Editor(`#${this.editorId}`)
|
||||
this.editor.customConfig.onchange = (html) => {
|
||||
let text = this.editor.txt.text()
|
||||
if (this.cache) localStorage.editorCache = html
|
||||
this.$emit('input', this.valueType === 'html' ? html : text)
|
||||
this.$emit('on-change', html, text)
|
||||
}
|
||||
this.editor.customConfig.onchangeTimeout = this.changeInterval
|
||||
// create这个方法一定要在所有配置项之后调用
|
||||
this.editor.create()
|
||||
// 如果本地有存储加载本地存储内容
|
||||
let html = localStorage.editorCache
|
||||
if (html) this.editor.txt.html(html)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import Editor from './editor.vue'
|
||||
export default Editor
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<i :class="`iconfont icon-${type}`" :style="styles"></i>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Icons',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#5c6b77'
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 16
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styles () {
|
||||
return {
|
||||
fontSize: `${this.size}px`,
|
||||
color: this.color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import Icons from './icons.vue'
|
||||
export default Icons
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
import loginForm from './login-form.vue'
|
||||
export default loginForm
|
||||
import LoginForm from './login-form.vue'
|
||||
export default LoginForm
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'loginForm',
|
||||
name: 'LoginForm',
|
||||
props: {
|
||||
userNameRules: {
|
||||
type: Array,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
import MarkdownEditor from './markdown.vue'
|
||||
export default MarkdownEditor
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div class="markdown-wrapper">
|
||||
<textarea ref="editor"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Simplemde from 'simplemde'
|
||||
import 'simplemde/dist/simplemde.min.css'
|
||||
export default {
|
||||
naem: 'MarkdownEditor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
localCache: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
editor: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addEvents () {
|
||||
this.editor.codemirror.on('change', () => {
|
||||
let value = this.editor.value()
|
||||
if (this.localCache) localStorage.markdownContent = value
|
||||
this.$emit('input', value)
|
||||
this.$emit('on-change', value)
|
||||
})
|
||||
this.editor.codemirror.on('focus', () => {
|
||||
this.$emit('on-focus', this.editor.value())
|
||||
})
|
||||
this.editor.codemirror.on('blur', () => {
|
||||
this.$emit('on-blur', this.editor.value())
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.editor = new Simplemde(Object.assign(this.options, {
|
||||
element: this.$refs.editor
|
||||
}))
|
||||
/**
|
||||
* 事件列表为Codemirror编辑器的事件,更多事件类型,请参考:
|
||||
* https://codemirror.net/doc/manual.html#events
|
||||
*/
|
||||
this.addEvents()
|
||||
let content = localStorage.markdownContent
|
||||
if (content) this.editor.value(content)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.markdown-wrapper{
|
||||
.editor-toolbar.fullscreen{
|
||||
z-index: 9999;
|
||||
}
|
||||
.CodeMirror-fullscreen{
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
import parentView from './parent-view.vue'
|
||||
export default parentView
|
||||
import ParentView from './parent-view.vue'
|
||||
export default ParentView
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'parentView'
|
||||
name: 'ParentView'
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
import PasteEditor from './paste-editor.vue'
|
||||
export default PasteEditor
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
.paste-editor-wrapper{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px dashed gainsboro;
|
||||
textarea.textarea-el{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror{
|
||||
height: 100%;
|
||||
.CodeMirror-code div .CodeMirror-line > span > span.cm-tab{
|
||||
&::after{
|
||||
content: '→';
|
||||
color: #BFBFBF;
|
||||
}
|
||||
}
|
||||
}
|
||||
.first-row{
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
}
|
||||
.incorrect-row{
|
||||
background: #F5CBD1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<div class="paste-editor-wrapper">
|
||||
<textarea ref="codemirror" class="textarea-el"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import CodeMirror from 'codemirror'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import { forEach } from '@/libs/tools'
|
||||
import createPlaceholder from './plugins/placeholder'
|
||||
export default {
|
||||
name: 'PasteEditor',
|
||||
props: {
|
||||
value: Array,
|
||||
pasteData: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
pasteDataArr: [],
|
||||
rowArrLength: 0,
|
||||
editor: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pasteData (val) {
|
||||
if (val === '') {
|
||||
this.editor.setValue('')
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rowNum () {
|
||||
return this.pasteDataArr.length
|
||||
},
|
||||
colNum () {
|
||||
return this.pasteDataArr[0] ? this.pasteDataArr[0].length : 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleKeyup (e) {
|
||||
this.handleAreaData()
|
||||
},
|
||||
/**
|
||||
* @description 处理粘贴操作
|
||||
*/
|
||||
handleContentChanged (content) {
|
||||
let pasteData = content.trim()
|
||||
this.$emit('on-content-change', pasteData)
|
||||
let rows = pasteData.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(row => {
|
||||
return row.split('\t')
|
||||
})
|
||||
if (content === '') rows = []
|
||||
this.pasteDataArr = rows
|
||||
this.clearLineClass()
|
||||
this.checkColNumInEveryRow()
|
||||
this.$emit('input', this.pasteDataArr)
|
||||
},
|
||||
/**
|
||||
* @description 检查除第一行的每一行列数是否与第一行相同
|
||||
*/
|
||||
checkColNumInEveryRow () {
|
||||
let i = 0
|
||||
const len = this.rowNum
|
||||
if (len === 0) return
|
||||
while (++i < len) {
|
||||
let item = this.pasteDataArr[i]
|
||||
if (item.length !== this.colNum && (!(i === len - 1 && item.length === 1 && item[0] === '') || i !== len - 1)) {
|
||||
this.markIncorrectRow(i)
|
||||
this.$emit('on-error', i)
|
||||
return false
|
||||
}
|
||||
}
|
||||
this.$emit('on-success', this.pasteDataArr)
|
||||
return true
|
||||
},
|
||||
/**
|
||||
* @description 标记不符合格式的一行
|
||||
*/
|
||||
markIncorrectRow (index) {
|
||||
this.editor.addLineClass(index, 'text', 'incorrect-row')
|
||||
},
|
||||
/**
|
||||
* @description 标记不符合格式的一行
|
||||
*/
|
||||
clearLineClass () {
|
||||
forEach(this.pasteDataArr, (item, index) => {
|
||||
this.editor.removeLineClass(index, 'text', 'incorrect-row')
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
createPlaceholder(CodeMirror)
|
||||
this.editor = CodeMirror.fromTextArea(this.$refs.codemirror, {
|
||||
lineNumbers: true,
|
||||
tabSize: 1,
|
||||
lineWrapping: true,
|
||||
placeholder: '从网页或其他应用软件复制表格数据,粘贴到这里 。默认第一行是表头,使用回车键添加新行,使用Tab键区分列。'
|
||||
})
|
||||
this.editor.on('change', (editor) => {
|
||||
this.handleContentChanged(editor.getValue())
|
||||
})
|
||||
this.editor.addLineClass(0, 'text', 'first-row')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import './paste-editor.less';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
export default (codemirror) => {
|
||||
(function (mod) {
|
||||
mod(codemirror)
|
||||
})(function (CodeMirror) {
|
||||
CodeMirror.defineOption('placeholder', '', function (cm, val, old) {
|
||||
var prev = old && old !== CodeMirror.Init
|
||||
if (val && !prev) {
|
||||
cm.on('blur', onBlur)
|
||||
cm.on('change', onChange)
|
||||
cm.on('swapDoc', onChange)
|
||||
onChange(cm)
|
||||
} else if (!val && prev) {
|
||||
cm.off('blur', onBlur)
|
||||
cm.off('change', onChange)
|
||||
cm.off('swapDoc', onChange)
|
||||
clearPlaceholder(cm)
|
||||
var wrapper = cm.getWrapperElement()
|
||||
wrapper.className = wrapper.className.replace(' CodeMirror-empty', '')
|
||||
}
|
||||
|
||||
if (val && !cm.hasFocus()) onBlur(cm)
|
||||
})
|
||||
|
||||
function clearPlaceholder (cm) {
|
||||
if (cm.state.placeholder) {
|
||||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder)
|
||||
cm.state.placeholder = null
|
||||
}
|
||||
}
|
||||
function setPlaceholder (cm) {
|
||||
clearPlaceholder(cm)
|
||||
var elt = cm.state.placeholder = document.createElement('pre')
|
||||
elt.style.cssText = 'height: 0; overflow: visible; color: #80848f;'
|
||||
elt.style.direction = cm.getOption('direction')
|
||||
elt.className = 'CodeMirror-placeholder'
|
||||
var placeHolder = cm.getOption('placeholder')
|
||||
if (typeof placeHolder === 'string') placeHolder = document.createTextNode(placeHolder)
|
||||
elt.appendChild(placeHolder)
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild)
|
||||
}
|
||||
|
||||
function onBlur (cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm)
|
||||
}
|
||||
function onChange (cm) {
|
||||
let wrapper = cm.getWrapperElement()
|
||||
let empty = isEmpty(cm)
|
||||
wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') + (empty ? ' CodeMirror-empty' : '')
|
||||
|
||||
if (empty) setPlaceholder(cm)
|
||||
else clearPlaceholder(cm)
|
||||
}
|
||||
|
||||
function isEmpty (cm) {
|
||||
return (cm.lineCount() === 1) && (cm.getLine(0) === '')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import Split from './split.vue'
|
||||
export default Split
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
@split-prefix-cls: ~"ivu-split";
|
||||
@box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.4);
|
||||
@trigger-bar-background: rgba(23, 35, 61, 0.25);
|
||||
@trigger-background: #F8F8F9;
|
||||
@trigger-width: 6px;
|
||||
@trigger-bar-width: 4px;
|
||||
@trigger-bar-offset: (@trigger-width - @trigger-bar-width) / 2;
|
||||
@trigger-bar-interval: 3px;
|
||||
@trigger-bar-weight: 1px;
|
||||
@trigger-bar-con-height: (@trigger-bar-weight + @trigger-bar-interval) * 8;
|
||||
|
||||
.@{split-prefix-cls}{
|
||||
&-wrapper{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&-pane{
|
||||
position: absolute;
|
||||
&.left-pane, &.right-pane{
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
&.left-pane{
|
||||
left: 0px;
|
||||
}
|
||||
&.right-pane{
|
||||
right: 0px;
|
||||
}
|
||||
&.top-pane, &.bottom-pane{
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
&.top-pane{
|
||||
top: 0px;
|
||||
}
|
||||
&.bottom-pane{
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
&-trigger{
|
||||
&-con{
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
}
|
||||
&-bar-con{
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
&.vertical{
|
||||
left: @trigger-bar-offset;
|
||||
top: 50%;
|
||||
height: @trigger-bar-con-height;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
&.horizontal{
|
||||
left: 50%;
|
||||
top: @trigger-bar-offset;
|
||||
width: @trigger-bar-con-height;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
}
|
||||
&-vertical{
|
||||
width: @trigger-width;
|
||||
height: 100%;
|
||||
background: @trigger-background;
|
||||
box-shadow: @box-shadow;
|
||||
cursor: col-resize;
|
||||
.@{split-prefix-cls}-trigger-bar{
|
||||
width: @trigger-bar-width;
|
||||
height: 1px;
|
||||
background: @trigger-bar-background;
|
||||
float: left;
|
||||
margin-top: @trigger-bar-interval;
|
||||
}
|
||||
}
|
||||
&-horizontal{
|
||||
height: @trigger-width;
|
||||
width: 100%;
|
||||
background: @trigger-background;
|
||||
box-shadow: @box-shadow;
|
||||
cursor: row-resize;
|
||||
.@{split-prefix-cls}-trigger-bar{
|
||||
height: @trigger-bar-width;
|
||||
width: 1px;
|
||||
background: @trigger-bar-background;
|
||||
float: left;
|
||||
margin-right: @trigger-bar-interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-horizontal{
|
||||
.@{split-prefix-cls}-trigger-con{
|
||||
top: 50%;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
&-vertical{
|
||||
.@{split-prefix-cls}-trigger-con{
|
||||
left: 50%;
|
||||
height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.no-select{
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
<template>
|
||||
<div ref="outerWrapper" :class="wrapperClasses">
|
||||
<div v-if="isHorizontal" :class="`${prefix}-horizontal`">
|
||||
<div :style="{right: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'left-pane']"><slot name="left"/></div>
|
||||
<div :class="`${prefix}-trigger-con`" :style="{left: `${offset}%`}" @mousedown="handleMousedown">
|
||||
<slot name="trigger">
|
||||
<trigger mode="vertical"/>
|
||||
</slot>
|
||||
</div>
|
||||
<div :style="{left: `${offset}%`}" :class="[`${prefix}-pane`, 'right-pane']"><slot name="right"/></div>
|
||||
</div>
|
||||
<div v-else :class="`${prefix}-vertical`">
|
||||
<div :style="{bottom: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'top-pane']"><slot name="top"/></div>
|
||||
<div :class="`${prefix}-trigger-con`" :style="{top: `${offset}%`}" @mousedown="handleMousedown">
|
||||
<slot name="trigger">
|
||||
<trigger mode="horizontal"/>
|
||||
</slot>
|
||||
</div>
|
||||
<div :style="{top: `${offset}%`}" :class="[`${prefix}-pane`, 'bottom-pane']"><slot name="bottom"/></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { oneOf, on, off } from '@/libs/tools'
|
||||
import Trigger from './trigger.vue'
|
||||
export default {
|
||||
name: 'SplitPane',
|
||||
components: {
|
||||
Trigger
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: 0.5
|
||||
},
|
||||
mode: {
|
||||
validator (value) {
|
||||
return oneOf(value, ['horizontal', 'vertical'])
|
||||
},
|
||||
default: 'horizontal'
|
||||
},
|
||||
min: {
|
||||
type: [Number, String],
|
||||
default: '40px'
|
||||
},
|
||||
max: {
|
||||
type: [Number, String],
|
||||
default: '40px'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Events
|
||||
* @on-move-start
|
||||
* @on-moving 返回值:事件对象,但是在事件对象中加入了两个参数:atMin(当前是否在最小值处), atMax(当前是否在最大值处)
|
||||
* @on-move-end
|
||||
*/
|
||||
data () {
|
||||
return {
|
||||
prefix: 'ivu-split',
|
||||
offset: 0,
|
||||
oldOffset: 0,
|
||||
isMoving: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
wrapperClasses () {
|
||||
return [
|
||||
`${this.prefix}-wrapper`,
|
||||
this.isMoving ? 'no-select' : ''
|
||||
]
|
||||
},
|
||||
isHorizontal () {
|
||||
return this.mode === 'horizontal'
|
||||
},
|
||||
anotherOffset () {
|
||||
return 100 - this.offset
|
||||
},
|
||||
valueIsPx () {
|
||||
return typeof this.value === 'string'
|
||||
},
|
||||
offsetSize () {
|
||||
return this.isHorizontal ? 'offsetWidth' : 'offsetHeight'
|
||||
},
|
||||
computedMin () {
|
||||
return this.getComputedThresholdValue('min')
|
||||
},
|
||||
computedMax () {
|
||||
return this.getComputedThresholdValue('max')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
px2percent (numerator, denominator) {
|
||||
return parseFloat(numerator) / parseFloat(denominator)
|
||||
},
|
||||
getComputedThresholdValue (type) {
|
||||
let size = this.$refs.outerWrapper[this.offsetSize]
|
||||
if (this.valueIsPx) return typeof this[type] === 'string' ? this[type] : size * this[type]
|
||||
else return typeof this[type] === 'string' ? this.px2percent(this[type], size) : this[type]
|
||||
},
|
||||
getMin (value1, value2) {
|
||||
if (this.valueIsPx) return `${Math.min(parseFloat(value1), parseFloat(value2))}px`
|
||||
else return Math.min(value1, value2)
|
||||
},
|
||||
getMax (value1, value2) {
|
||||
if (this.valueIsPx) return `${Math.max(parseFloat(value1), parseFloat(value2))}px`
|
||||
else return Math.max(value1, value2)
|
||||
},
|
||||
getAnotherOffset (value) {
|
||||
let res = 0
|
||||
if (this.valueIsPx) res = `${this.$refs.outerWrapper[this.offsetSize] - parseFloat(value)}px`
|
||||
else res = 1 - value
|
||||
return res
|
||||
},
|
||||
handleMove (e) {
|
||||
let pageOffset = this.isHorizontal ? e.pageX : e.pageY
|
||||
let offset = pageOffset - this.initOffset
|
||||
let outerWidth = this.$refs.outerWrapper[this.offsetSize]
|
||||
let value = this.valueIsPx ? `${parseFloat(this.oldOffset) + offset}px` : (this.px2percent(outerWidth * this.oldOffset + offset, outerWidth))
|
||||
let anotherValue = this.getAnotherOffset(value)
|
||||
if (parseFloat(value) <= parseFloat(this.computedMin)) value = this.getMax(value, this.computedMin)
|
||||
if (parseFloat(anotherValue) <= parseFloat(this.computedMax)) value = this.getAnotherOffset(this.getMax(anotherValue, this.computedMax))
|
||||
e.atMin = this.value === this.computedMin
|
||||
e.atMax = this.valueIsPx ? this.getAnotherOffset(this.value) === this.computedMax : this.getAnotherOffset(this.value).toFixed(5) === this.computedMax.toFixed(5)
|
||||
this.$emit('input', value)
|
||||
this.$emit('on-moving', e)
|
||||
},
|
||||
handleUp () {
|
||||
this.isMoving = false
|
||||
off(document, 'mousemove', this.handleMove)
|
||||
off(document, 'mouseup', this.handleUp)
|
||||
this.$emit('on-move-end')
|
||||
},
|
||||
handleMousedown (e) {
|
||||
this.initOffset = this.isHorizontal ? e.pageX : e.pageY
|
||||
this.oldOffset = this.value
|
||||
this.isMoving = true
|
||||
on(document, 'mousemove', this.handleMove)
|
||||
on(document, 'mouseup', this.handleUp)
|
||||
this.$emit('on-move-start')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value () {
|
||||
this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import './index.less';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div :class="classes">
|
||||
<div :class="barConClasses">
|
||||
<i :class="`${prefix}-bar`" v-once v-for="i in 8" :key="`trigger-${i}`"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Trigger',
|
||||
props: {
|
||||
mode: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
prefix: 'ivu-split-trigger',
|
||||
initOffset: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isVertical () {
|
||||
return this.mode === 'vertical'
|
||||
},
|
||||
classes () {
|
||||
return [
|
||||
this.prefix,
|
||||
this.isVertical ? `${this.prefix}-vertical` : `${this.prefix}-horizontal`
|
||||
]
|
||||
},
|
||||
barConClasses () {
|
||||
return [
|
||||
`${this.prefix}-bar-con`,
|
||||
this.isVertical ? 'vertical' : 'horizontal'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import './index.less';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div class="tables-edit-outer">
|
||||
<div v-if="!isEditting" class="tables-edit-con">
|
||||
<span class="value-con">{{ value }}</span>
|
||||
<Button v-if="editable" @click="startEdit" class="tables-edit-btn" style="padding: 2px 4px;" type="text"><Icon type="edit"></Icon></Button>
|
||||
</div>
|
||||
<div v-else class="tables-editting-con">
|
||||
<Input :value="value" @input="handleInput" class="tables-edit-input"/>
|
||||
<Button @click="saveEdit" style="padding: 6px 4px;" type="text"><Icon type="checkmark-round"></Icon></Button>
|
||||
<Button @click="canceltEdit" style="padding: 6px 4px;" type="text"><Icon type="close-round"></Icon></Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TablesEdit',
|
||||
props: {
|
||||
value: [String, Number],
|
||||
edittingCellId: String,
|
||||
params: Object,
|
||||
editable: Boolean
|
||||
},
|
||||
computed: {
|
||||
isEditting () {
|
||||
return this.edittingCellId === `editting-${this.params.index}-${this.params.column.key}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleInput (val) {
|
||||
this.$emit('input', val)
|
||||
},
|
||||
startEdit () {
|
||||
this.$emit('on-start-edit', this.params)
|
||||
},
|
||||
saveEdit () {
|
||||
this.$emit('on-save-edit', this.params)
|
||||
},
|
||||
canceltEdit () {
|
||||
this.$emit('on-cancel-edit', this.params)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.tables-edit-outer{
|
||||
height: 100%;
|
||||
.tables-edit-con{
|
||||
position: relative;
|
||||
height: 100%;
|
||||
.value-con{
|
||||
vertical-align: middle;
|
||||
}
|
||||
.tables-edit-btn{
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 0;
|
||||
display: none;
|
||||
}
|
||||
&:hover{
|
||||
.tables-edit-btn{
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tables-editting-con{
|
||||
.tables-edit-input{
|
||||
width: ~"calc(100% - 50px)";
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
const btns = {
|
||||
delete: (h, params, vm) => {
|
||||
return h('Poptip', {
|
||||
props: {
|
||||
confirm: true,
|
||||
title: '你确定要删除吗?'
|
||||
},
|
||||
on: {
|
||||
'on-ok': () => {
|
||||
vm.$emit('on-delete', params)
|
||||
vm.$emit('input', params.tableData.filter((item, index) => index !== params.row.initRowIndex))
|
||||
}
|
||||
}
|
||||
}, [
|
||||
h('Button', {
|
||||
props: {
|
||||
type: 'text'
|
||||
}
|
||||
}, [
|
||||
h('Icon', {
|
||||
props: {
|
||||
type: 'trash-b',
|
||||
size: 18
|
||||
}
|
||||
})
|
||||
])
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
export default btns
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import Tables from './tables.vue'
|
||||
export default Tables
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
.search-con{
|
||||
padding: 10px 0;
|
||||
.search{
|
||||
&-col{
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
&-input{
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
&-btn{
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="searchable && searchPlace === 'top'" class="search-con search-con-top">
|
||||
<Select v-model="searchKey" class="search-col">
|
||||
<Option v-for="item in columns" v-if="item.key !== 'handle'" :value="item.key" :key="`search-col-${item.key}`">{{ item.title }}</Option>
|
||||
</Select>
|
||||
<Input @on-change="handleClear" clearable placeholder="输入关键字搜索" class="search-input" v-model="searchValue"/>
|
||||
<Button @click="handleSearch" class="search-btn" type="primary"><Icon type="search"/> 搜索</Button>
|
||||
</div>
|
||||
<Table
|
||||
ref="tablesMain"
|
||||
:data="insideTableData"
|
||||
:columns="insideColumns"
|
||||
:stripe="stripe"
|
||||
:border="border"
|
||||
:show-header="showHeader"
|
||||
:width="width"
|
||||
:height="height"
|
||||
:loading="loading"
|
||||
:disabled-hover="disabledHover"
|
||||
:highlight-row="highlightRow"
|
||||
:row-class-name="rowClassName"
|
||||
:size="size"
|
||||
:no-data-text="noDataText"
|
||||
:no-filtered-data-text="noFilteredDataText"
|
||||
@on-current-change="onCurrentChange"
|
||||
@on-select="onSelect"
|
||||
@on-select-cancel="onSelectCancel"
|
||||
@on-select-all="onSelectAll"
|
||||
@on-selection-change="onSelectionChange"
|
||||
@on-sort-change="onSortChange"
|
||||
@on-filter-change="onFilterChange"
|
||||
@on-row-click="onRowClick"
|
||||
@on-row-dblclick="onRowDblclick"
|
||||
@on-expand="onExpand"
|
||||
>
|
||||
<slot name="header" slot="header"></slot>
|
||||
<slot name="footer" slot="footer"></slot>
|
||||
<slot name="loading" slot="loading"></slot>
|
||||
</Table>
|
||||
<div v-if="searchable && searchPlace === 'bottom'" class="search-con search-con-top">
|
||||
<Select v-model="searchKey" class="search-col">
|
||||
<Option v-for="item in columns" v-if="item.key !== 'handle'" :value="item.key" :key="`search-col-${item.key}`">{{ item.title }}</Option>
|
||||
</Select>
|
||||
<Input placeholder="输入关键字搜索" class="search-input" v-model="searchValue"/>
|
||||
<Button class="search-btn" type="primary"><Icon type="search"/> 搜索</Button>
|
||||
</div>
|
||||
<a id="hrefToExportTable" style="display: none;width: 0px;height: 0px;"></a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TablesEdit from './edit.vue'
|
||||
import handleBtns from './handle-btns'
|
||||
import './index.less'
|
||||
export default {
|
||||
name: 'Tables',
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
size: String,
|
||||
width: {
|
||||
type: [Number, String]
|
||||
},
|
||||
height: {
|
||||
type: [Number, String]
|
||||
},
|
||||
stripe: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
highlightRow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
rowClassName: {
|
||||
type: Function,
|
||||
default () {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
context: {
|
||||
type: Object
|
||||
},
|
||||
noDataText: {
|
||||
type: String
|
||||
},
|
||||
noFilteredDataText: {
|
||||
type: String
|
||||
},
|
||||
disabledHover: {
|
||||
type: Boolean
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* @description 全局设置是否可编辑
|
||||
*/
|
||||
editable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* @description 是否可搜索
|
||||
*/
|
||||
searchable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* @description 搜索控件所在位置,'top' / 'bottom'
|
||||
*/
|
||||
searchPlace: {
|
||||
type: String,
|
||||
default: 'top'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Events
|
||||
* @on-start-edit 返回值 {Object} :同iview中render函数中的params对象 { row, index, column }
|
||||
* @on-cancel-edit 返回值 {Object} 同上
|
||||
* @on-save-edit 返回值 {Object} :除上面三个参数外,还有一个value: 修改后的数据
|
||||
*/
|
||||
data () {
|
||||
return {
|
||||
insideColumns: [],
|
||||
insideTableData: [],
|
||||
edittingCellId: '',
|
||||
edittingText: '',
|
||||
searchValue: '',
|
||||
searchKey: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
suportEdit (item, index) {
|
||||
item.render = (h, params) => {
|
||||
return h(TablesEdit, {
|
||||
props: {
|
||||
params: params,
|
||||
value: this.insideTableData[params.index][params.column.key],
|
||||
edittingCellId: this.edittingCellId,
|
||||
editable: this.editable
|
||||
},
|
||||
on: {
|
||||
'input': val => {
|
||||
this.edittingText = val
|
||||
},
|
||||
'on-start-edit': (params) => {
|
||||
this.edittingCellId = `editting-${params.index}-${params.column.key}`
|
||||
this.$emit('on-start-edit', params)
|
||||
},
|
||||
'on-cancel-edit': (params) => {
|
||||
this.edittingCellId = ''
|
||||
this.$emit('on-cancel-edit', params)
|
||||
},
|
||||
'on-save-edit': (params) => {
|
||||
this.value[params.index][params.column.key] = this.edittingText
|
||||
this.$emit('input', this.value)
|
||||
this.$emit('on-save-edit', Object.assign(params, {value: this.edittingText}))
|
||||
this.edittingCellId = ''
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return item
|
||||
},
|
||||
surportHandle (item) {
|
||||
let options = item.options || []
|
||||
let insideBtns = []
|
||||
options.forEach(item => {
|
||||
if (handleBtns[item]) insideBtns.push(handleBtns[item])
|
||||
})
|
||||
let btns = item.button ? [].concat(insideBtns, item.button) : insideBtns
|
||||
item.render = (h, params) => {
|
||||
params.tableData = this.value
|
||||
return h('div', btns.map(item => item(h, params, this)))
|
||||
}
|
||||
return item
|
||||
},
|
||||
handleColumns (columns) {
|
||||
this.insideColumns = columns.map((item, index) => {
|
||||
let res = item
|
||||
if (res.editable) res = this.suportEdit(res, index)
|
||||
if (res.key === 'handle') res = this.surportHandle(res)
|
||||
return res
|
||||
})
|
||||
},
|
||||
setDefaultSearchKey () {
|
||||
this.searchKey = this.columns[0].key !== 'handle' ? this.columns[0].key : (this.columns.length > 1 ? this.columns[1].key : '')
|
||||
},
|
||||
handleClear (e) {
|
||||
if (e.target.value === '') this.insideTableData = this.value
|
||||
},
|
||||
handleSearch () {
|
||||
this.insideTableData = this.value.filter(item => item[this.searchKey].indexOf(this.searchValue) > -1)
|
||||
},
|
||||
handleTableData () {
|
||||
this.insideTableData = this.value.map((item, index) => {
|
||||
let res = item
|
||||
res.initRowIndex = index
|
||||
return res
|
||||
})
|
||||
},
|
||||
exportCsv (params) {
|
||||
this.$refs.tablesMain.exportCsv(params)
|
||||
},
|
||||
clearCurrentRow () {
|
||||
this.$refs.talbesMain.clearCurrentRow()
|
||||
},
|
||||
onCurrentChange (currentRow, oldCurrentRow) {
|
||||
this.$emit('on-current-change', currentRow, oldCurrentRow)
|
||||
},
|
||||
onSelect (selection, row) {
|
||||
this.$emit('on-select', selection, row)
|
||||
},
|
||||
onSelectCancel (selection, row) {
|
||||
this.$emit('on-select-cancel', selection, row)
|
||||
},
|
||||
onSelectAll (selection) {
|
||||
this.$emit('on-select-all', selection)
|
||||
},
|
||||
onSelectionChange (selection) {
|
||||
this.$emit('on-selection-change', selection)
|
||||
},
|
||||
onSortChange (column, key, order) {
|
||||
this.$emit('on-sort-change', column, key, order)
|
||||
},
|
||||
onFilterChange (row) {
|
||||
this.$emit('on-filter-change', row)
|
||||
},
|
||||
onRowClick (row, index) {
|
||||
this.$emit('on-row-click', row, index)
|
||||
},
|
||||
onRowDblclick (row, index) {
|
||||
this.$emit('on-row-dblclick', row, index)
|
||||
},
|
||||
onExpand (row, status) {
|
||||
this.$emit('on-expand', row, status)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
columns (columns) {
|
||||
this.handleColumns(columns)
|
||||
this.setDefaultSearchKey()
|
||||
},
|
||||
value (val) {
|
||||
this.handleTableData()
|
||||
this.handleSearch()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.handleColumns(this.columns)
|
||||
this.setDefaultSearchKey()
|
||||
this.handleTableData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { on } from '@/libs/tools'
|
||||
const directives = {
|
||||
draggable: {
|
||||
inserted: (el, binding, vnode) => {
|
||||
let triggerDom = document.querySelector(binding.value.trigger)
|
||||
triggerDom.style.cursor = 'move'
|
||||
let bodyDom = document.querySelector(binding.value.body)
|
||||
let pageX = 0
|
||||
let pageY = 0
|
||||
let transformX = 0
|
||||
let transformY = 0
|
||||
let canMove = false
|
||||
const handleMousedown = e => {
|
||||
let transform = /\(.*\)/.exec(bodyDom.style.transform)
|
||||
if (transform) {
|
||||
transform = transform[0].slice(1, transform[0].length - 1)
|
||||
let splitxy = transform.split('px, ')
|
||||
transformX = parseFloat(splitxy[0])
|
||||
transformY = parseFloat(splitxy[1].split('px')[0])
|
||||
}
|
||||
pageX = e.pageX
|
||||
pageY = e.pageY
|
||||
canMove = true
|
||||
}
|
||||
const handleMousemove = e => {
|
||||
let xOffset = e.pageX - pageX + transformX
|
||||
let yOffset = e.pageY - pageY + transformY
|
||||
if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`
|
||||
}
|
||||
const handleMouseup = e => {
|
||||
canMove = false
|
||||
}
|
||||
on(triggerDom, 'mousedown', handleMousedown)
|
||||
on(document, 'mousemove', handleMousemove)
|
||||
on(document, 'mouseup', handleMouseup)
|
||||
},
|
||||
update: (el, binding, vnode) => {
|
||||
if (!binding.value.recover) return
|
||||
let bodyDom = document.querySelector(binding.value.body)
|
||||
bodyDom.style.transform = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default directives
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import directive from './directives'
|
||||
|
||||
const importDirective = Vue => {
|
||||
/**
|
||||
* 拖拽指令 v-draggable="options"
|
||||
* options = {
|
||||
* trigger: /这里传入作为拖拽触发器的CSS选择器/,
|
||||
* body: /这里传入需要移动容器的CSS选择器/,
|
||||
* recover: /拖动结束之后是否恢复到原来的位置/
|
||||
* }
|
||||
*/
|
||||
Vue.directive('draggable', directive.draggable)
|
||||
}
|
||||
|
||||
export default importDirective
|
||||
|
|
@ -42,6 +42,19 @@ export const hasOneOf = (target, arr) => {
|
|||
return target.some(_ => arr.indexOf(_) > -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String|Number} value 要验证的字符串或数值
|
||||
* @param {*} validList 用来验证的列表
|
||||
*/
|
||||
export function oneOf (value, validList) {
|
||||
for (let i = 0; i < validList.length; i++) {
|
||||
if (value === validList[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 判断时间戳格式是否是毫秒
|
||||
* @returns {Boolean}
|
||||
|
|
@ -121,3 +134,56 @@ export const getRelativeTime = timeStamp => {
|
|||
else resStr = getDate(timeStamp, 'year')
|
||||
return resStr
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String} 当前浏览器名称
|
||||
*/
|
||||
export const getExplorer = () => {
|
||||
const ua = window.navigator.userAgent
|
||||
const isExplorer = (exp) => {
|
||||
return ua.indexOf(exp) > -1
|
||||
}
|
||||
if (isExplorer('MSIE')) return 'IE'
|
||||
else if (isExplorer('Firefox')) return 'Firefox'
|
||||
else if (isExplorer('Chrome')) return 'Chrome'
|
||||
else if (isExplorer('Opera')) return 'Opera'
|
||||
else if (isExplorer('Safari')) return 'Safari'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 绑定事件 on(element, event, handler)
|
||||
*/
|
||||
export const on = (function () {
|
||||
if (document.addEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.addEventListener(event, handler, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.attachEvent('on' + event, handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* @description 解绑事件 off(element, event, handler)
|
||||
*/
|
||||
export const off = (function () {
|
||||
if (document.removeEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.removeEventListener(event, handler, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.detachEvent('on' + event, handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ export const getMenuByRouter = (list, access) => {
|
|||
* @returns {Array}
|
||||
*/
|
||||
export const getBreadCrumbList = (routeMetched) => {
|
||||
let res = routeMetched.map(item => {
|
||||
let res = routeMetched.filter(item => {
|
||||
return item.meta === undefined || !item.meta.hide
|
||||
}).map(item => {
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
|
|
@ -164,6 +166,10 @@ export const canTurnTo = (name, access, routes) => {
|
|||
return canTurnToNames.indexOf(name) > -1
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} url
|
||||
* @description 从URL中解析参数
|
||||
*/
|
||||
export const getParams = url => {
|
||||
const keyValueArr = url.split('?')[1].split('&')
|
||||
let paramObj = {}
|
||||
|
|
@ -173,3 +179,85 @@ export const getParams = url => {
|
|||
})
|
||||
return paramObj
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} list 标签列表
|
||||
* @param {String} name 当前关闭的标签的name
|
||||
*/
|
||||
export const getNextName = (list, name) => {
|
||||
let res = ''
|
||||
if (list.length === 2) {
|
||||
res = 'home'
|
||||
} else {
|
||||
if (list.findIndex(item => item.name === name) === list.length - 1) res = list[list.length - 2].name
|
||||
else res = list[list.findIndex(item => item.name === name) + 1].name
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} times 回调函数需要执行的次数
|
||||
* @param {Function} callback 回调函数
|
||||
*/
|
||||
export const doCustomTimes = (times, callback) => {
|
||||
let i = -1
|
||||
while (++i < times) {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} file 从上传组件得到的文件对象
|
||||
* @returns {Promise} resolve参数是解析后的二维数组
|
||||
* @description 从Csv文件中解析出表格,解析成二维数组
|
||||
*/
|
||||
export const getArrayFromFile = (file) => {
|
||||
let nameSplit = file.name.split('.')
|
||||
let format = nameSplit[nameSplit.length - 1]
|
||||
return new Promise((resolve, reject) => {
|
||||
let reader = new FileReader()
|
||||
reader.readAsText(file) // 以文本格式读取
|
||||
let arr = []
|
||||
reader.onload = function (evt) {
|
||||
let data = evt.target.result // 读到的数据
|
||||
let pasteData = data.trim()
|
||||
arr = pasteData.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(row => {
|
||||
return row.split('\t')
|
||||
}).map(item => {
|
||||
return item[0].split(',')
|
||||
})
|
||||
if (format === 'csv') resolve(arr)
|
||||
else reject(new Error('[Format Error]:你上传的不是Csv文件'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} array 表格数据二维数组
|
||||
* @returns {Object} { columns, tableData }
|
||||
* @description 从二维数组中获取表头和表格数据,将第一行作为表头,用于在iView的表格中展示数据
|
||||
*/
|
||||
export const getTableDataFromArray = (array) => {
|
||||
let columns = []
|
||||
let tableData = []
|
||||
if (array.length > 1) {
|
||||
let titles = array.shift()
|
||||
columns = titles.map(item => {
|
||||
return {
|
||||
title: item,
|
||||
key: item
|
||||
}
|
||||
})
|
||||
tableData = array.map(item => {
|
||||
let res = {}
|
||||
item.forEach((col, i) => {
|
||||
res[titles[i]] = col
|
||||
})
|
||||
return res
|
||||
})
|
||||
}
|
||||
return {
|
||||
columns,
|
||||
tableData
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,17 +16,22 @@ Vue.use(VueI18n)
|
|||
let lang = 'zh-CN'
|
||||
|
||||
Vue.config.lang = lang
|
||||
Vue.locale = () => {}
|
||||
|
||||
// vue-i18n 6.x+写法
|
||||
Vue.locale = () => {}
|
||||
const messages = {
|
||||
'zh-CN': Object.assign(zhCnLocale, customZhCn),
|
||||
'zh-TW': Object.assign(zhTwLocale, customZhTw),
|
||||
'en-US': Object.assign(enUsLocale, customEnUs)
|
||||
}
|
||||
|
||||
const i18n = new VueI18n({
|
||||
locale: lang,
|
||||
messages
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
||||
// vue-i18n 5.x写法
|
||||
// Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn))
|
||||
// Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw))
|
||||
// Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs))
|
||||
|
|
|
|||
11
src/main.js
11
src/main.js
|
|
@ -7,22 +7,29 @@ import store from './store'
|
|||
import iView from 'iview'
|
||||
import i18n from '@/locale'
|
||||
import config from '@/config'
|
||||
import importDirective from '@/directive'
|
||||
import 'iview/dist/styles/iview.css'
|
||||
import '@/assets/icons/iconfont.css'
|
||||
import env from '../config/env'
|
||||
if (env === 'development') require('@/mock')
|
||||
|
||||
Vue.use(iView)
|
||||
Vue.use(iView, {
|
||||
i18n: (key, value) => i18n.t(key, value)
|
||||
})
|
||||
Vue.config.productionTip = false
|
||||
/**
|
||||
* @description 全局注册应用配置
|
||||
*/
|
||||
Vue.prototype.$config = config
|
||||
/**
|
||||
* 注册指令
|
||||
*/
|
||||
importDirective(Vue)
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import Mock from 'mockjs'
|
||||
import { doCustomTimes } from '@/libs/util'
|
||||
|
||||
export const getTableData = req => {
|
||||
let tableData = []
|
||||
doCustomTimes(5, () => {
|
||||
tableData.push(Mock.mock({
|
||||
name: '@name',
|
||||
email: '@email',
|
||||
createTime: '@date'
|
||||
}))
|
||||
})
|
||||
return {
|
||||
code: 200,
|
||||
data: tableData,
|
||||
msg: ''
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
import Mock from 'mockjs'
|
||||
import { login, logout, getUserInfo } from './login'
|
||||
import { getTableData } from './data'
|
||||
|
||||
// 登录相关和获取用户信息
|
||||
Mock.mock(/\/login/, login)
|
||||
Mock.mock(/\/get_info/, getUserInfo)
|
||||
Mock.mock(/\/logout/, logout)
|
||||
Mock.mock(/\/get_table_data/, getTableData)
|
||||
|
||||
export default Mock
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
import Main from '@/view/main'
|
||||
import parentView from '@/components/main/parent-view'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
meta: {
|
||||
title: 'Login - 登录'
|
||||
},
|
||||
component: () => import('@/view/login/login.vue')
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'index',
|
||||
// redirect: '/home',
|
||||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
name: 'home',
|
||||
component: () => import('@/view/single-page/home')
|
||||
},
|
||||
{
|
||||
path: 'multilevel',
|
||||
name: 'multilevel',
|
||||
component: parentView,
|
||||
children: [
|
||||
{
|
||||
path: 'level_1',
|
||||
name: 'level_1',
|
||||
component: () => import('@/view/multilevel/level-1.vue')
|
||||
},
|
||||
{
|
||||
path: 'level_2',
|
||||
name: 'level_2',
|
||||
component: parentView,
|
||||
children: [
|
||||
{
|
||||
path: 'level_2_1',
|
||||
name: 'level_2_1',
|
||||
component: () => import('@/view/multilevel/level-2/level-2-1.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -13,7 +13,7 @@ export default [
|
|||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'index',
|
||||
name: 'home',
|
||||
redirect: '/home',
|
||||
component: Main,
|
||||
meta: {
|
||||
|
|
@ -42,13 +42,106 @@ export default [
|
|||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: 'count_to',
|
||||
name: 'count_to',
|
||||
path: 'count_to_page',
|
||||
name: 'count_to_page',
|
||||
meta: {
|
||||
icon: 'arrow-graph-up-right',
|
||||
title: '数字渐变'
|
||||
},
|
||||
component: () => import('@/view/components/count-to/count-to.vue')
|
||||
},
|
||||
{
|
||||
path: 'tables_page',
|
||||
name: 'tables_page',
|
||||
meta: {
|
||||
icon: 'ios-grid-view',
|
||||
title: '多功能表格'
|
||||
},
|
||||
component: () => import('@/view/components/tables/tables.vue')
|
||||
},
|
||||
{
|
||||
path: 'split_pane_page',
|
||||
name: 'split_pane_page',
|
||||
meta: {
|
||||
icon: 'pause',
|
||||
title: '分割窗口'
|
||||
},
|
||||
component: () => import('@/view/components/split-pane/split-pane.vue')
|
||||
},
|
||||
{
|
||||
path: 'markdown_page',
|
||||
name: 'markdown_page',
|
||||
meta: {
|
||||
icon: 'social-markdown',
|
||||
title: 'Markdown编辑器'
|
||||
},
|
||||
component: () => import('@/view/components/markdown/markdown.vue')
|
||||
},
|
||||
{
|
||||
path: 'editor_page',
|
||||
name: 'editor_page',
|
||||
meta: {
|
||||
icon: 'compose',
|
||||
title: '富文本编辑器'
|
||||
},
|
||||
component: () => import('@/view/components/editor/editor.vue')
|
||||
},
|
||||
{
|
||||
path: 'icons_page',
|
||||
name: 'icons_page',
|
||||
meta: {
|
||||
icon: '_bear',
|
||||
title: '自定义图标'
|
||||
},
|
||||
component: () => import('@/view/components/icons/icons.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/update',
|
||||
name: 'update',
|
||||
meta: {
|
||||
icon: 'upload',
|
||||
title: '数据上传'
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: 'update_table_page',
|
||||
name: 'update_table_page',
|
||||
meta: {
|
||||
icon: 'document-text',
|
||||
title: '上传Csv'
|
||||
},
|
||||
component: () => import('@/view/update/update-table.vue')
|
||||
},
|
||||
{
|
||||
path: 'update_paste_page',
|
||||
name: 'update_paste_page',
|
||||
meta: {
|
||||
icon: 'clipboard',
|
||||
title: '粘贴表格数据'
|
||||
},
|
||||
component: () => import('@/view/update/update-paste.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/directive',
|
||||
name: 'directive',
|
||||
meta: {
|
||||
hide: true
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: '/directive_page',
|
||||
name: 'directive_page',
|
||||
meta: {
|
||||
icon: 'ios-navigate',
|
||||
title: '指令'
|
||||
},
|
||||
component: () => import('@/view/directive/directive.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,13 +1,193 @@
|
|||
<template>
|
||||
<div>count to</div>
|
||||
<div>
|
||||
<Row :gutter="14">
|
||||
<i-col span="3">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="waterdrop"></Icon>
|
||||
count-to组件基础用法
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :end="2534"/>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="5" class="padding-left-10">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="code"></Icon>
|
||||
可添加左右文字
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :end="2534">
|
||||
<span slot="left">Total: </span>
|
||||
<span slot="right"> times</span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="8" class="padding-left-10">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="paintbucket"></Icon>
|
||||
自定义样式
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :end="2534" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">Total: </span>
|
||||
<span class="slot-text" slot="right"> times</span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="8" class="padding-left-10">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="settings"></Icon>
|
||||
设置数据格式
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :end="2534" count-class="count-text" unit-class="unit-class" :decimals="2">
|
||||
<span class="slot-text" slot="left">Total: </span>
|
||||
<span class="slot-text" slot="right"> times</span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
<Row :gutter="14" style="margin-top: 14px;">
|
||||
<i-col span="8">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="ios-color-wand"></Icon>
|
||||
转换单位简化数据
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :simplify="true" :end="2534" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">Total: </span>
|
||||
<span class="slot-text" slot="right"> times</span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="8" class="padding-left-10">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="ios-shuffle-strong"></Icon>
|
||||
自定义单位
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :simplify="true" :unit="unit" :end="253" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">原始数据:253 => </span>
|
||||
</count-to>
|
||||
<count-to :simplify="true" :unit="unit" :end="2534" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">原始数据:2534 => </span>
|
||||
</count-to>
|
||||
<count-to :simplify="true" :unit="unit" :end="257678" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">原始数据:257678 => </span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="8" class="padding-left-10">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="android-stopwatch"></Icon>
|
||||
可异步更新数据
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :end="asynEndVal" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">Total: </span>
|
||||
<span class="slot-text" slot="right"> times</span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
<Row :gutter="14" style="margin-top: 14px;">
|
||||
<i-col>
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="ios-analytics"></Icon>
|
||||
综合实例
|
||||
</p>
|
||||
<Row type="flex" justify="center" align="middle" class="countto-page-row">
|
||||
<div class="count-to-con">
|
||||
<count-to :delay="500" :simplify="true" :unit="unit2" :end="integratedEndVal" count-class="count-text" unit-class="unit-class">
|
||||
<span class="slot-text" slot="left">原始数据: {{ integratedEndVal }} => </span>
|
||||
<span class="slot-text" slot="right"> times</span>
|
||||
</count-to>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CountTo from '_c/count-to'
|
||||
export default {
|
||||
name: 'countTo'
|
||||
name: 'count_to_page',
|
||||
components: {
|
||||
CountTo
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
end: 0,
|
||||
unit: [[3, '千多'], [4, '万多'], [5, '十万多']],
|
||||
unit2: [[1, '十多'], [2, '百多'], [3, '千多'], [4, '万多'], [5, '十万多'], [6, '百万多'], [7, '千万多'], [8, '亿多']],
|
||||
asynEndVal: 487,
|
||||
integratedEndVal: 3
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
setInterval(() => {
|
||||
this.asynEndVal += parseInt(Math.random() * 20)
|
||||
this.integratedEndVal += parseInt(Math.random() * 30)
|
||||
}, 2000)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
<style lang="less">
|
||||
@baseColor: ~"#dc9387";
|
||||
.countto-page-row{
|
||||
height: 200px;
|
||||
}
|
||||
.count-to-con{
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.count-text{
|
||||
font-size: 50px;
|
||||
color: @baseColor;
|
||||
}
|
||||
.slot-text{
|
||||
font-size: 22px;
|
||||
}
|
||||
.unit-class{
|
||||
font-size: 30px;
|
||||
color: @baseColor;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div>
|
||||
<editor v-model="content" @on-change="handleChange"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Editor from '_c/editor'
|
||||
export default {
|
||||
name: 'editor_page',
|
||||
components: {
|
||||
Editor
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange (html, text) {
|
||||
console.log(html, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<Row>
|
||||
<i-col span="16">
|
||||
<Row v-for="i in (customIconList.length / 3)" :key="`custom-icon-row-${i}`">
|
||||
<i-col span="8" v-for="item in customIconList.slice((i - 1) * 3, i * 3)" :key="`custom-icon-${item}`">
|
||||
<Card style="margin: 0 5px 5px; text-align: center;">
|
||||
<icons :size="30" :type="item"/>
|
||||
<p class="icon-code"><Icons :size="30" type="{{ item }}"></p>
|
||||
<p><CommonIcon :size="30" type="_{{ item }}"></p>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
<Row>
|
||||
<i-col>
|
||||
<Card style="margin: 0 5px 5px; text-align: center;">
|
||||
<common-icon :size="30" type="ionic"/>
|
||||
<p class="icon-code">iView内置图标</p>
|
||||
<p><CommonIcon :size="30" type="ionic"></p>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
</i-col>
|
||||
<i-col span="8">
|
||||
<Card>
|
||||
<p class="intro-p"><Icon style="margin-right: 10px;" :size="10" type="heart"/>Icons组件支持自定义图标的显示,具体自定义图标字体文件的制作请参考文档。</p>
|
||||
<p class="intro-p"><Icon style="margin-right: 10px;" :size="10" type="heart"/>CommonIcon组件同时支持iView内置图标类型和自定义图标类型,为了区别这两种类型,需要在自定义图标名称前加下划线"_"</p>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Icons from '_c/icons'
|
||||
import CommonIcon from '_c/common-icon'
|
||||
export default {
|
||||
name: 'icons_pages',
|
||||
components: {
|
||||
Icons,
|
||||
CommonIcon
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
customIconList: [
|
||||
'woman',
|
||||
'man',
|
||||
'smile',
|
||||
'meh',
|
||||
'frown',
|
||||
'bear'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.icon-code{
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
.intro-p{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<div>
|
||||
<markdown-editor v-model="content"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MarkdownEditor from '_c/markdown'
|
||||
export default {
|
||||
name: 'markdown_page',
|
||||
components: {
|
||||
MarkdownEditor
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
content: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<div class="split-pane-page-wrapper">
|
||||
<split-pane v-model="offset" @on-moving="handleMoving">
|
||||
<div slot="left" class="pane left-pane">
|
||||
<split-pane v-model="offsetVertical" mode="vertical" @on-moving="handleMoving">
|
||||
<div slot="top" class="pane top-pane"></div>
|
||||
<div slot="bottom" class="pane bottom-pane"></div>
|
||||
<div slot="trigger" class="custom-trigger">
|
||||
<icons class="trigger-icon" :size="22" type="resize-vertical" color="#fff"/>
|
||||
</div>
|
||||
</split-pane>
|
||||
</div>
|
||||
<div slot="right" class="pane right-pane"></div>
|
||||
</split-pane>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SplitPane from '_c/split-pane'
|
||||
import Icons from '_c/icons'
|
||||
export default {
|
||||
name: 'split_pane_page',
|
||||
components: {
|
||||
SplitPane,
|
||||
Icons
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
offset: 0.6,
|
||||
offsetVertical: '250px'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleMoving (e) {
|
||||
console.log(e.atMin, e.atMax)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.center-middle{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.split-pane-page-wrapper{
|
||||
height: 600px;
|
||||
.pane{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
&.left-pane{
|
||||
background: sandybrown;
|
||||
}
|
||||
&.right-pane{
|
||||
background: palevioletred;
|
||||
}
|
||||
&.top-pane{
|
||||
background: sandybrown;
|
||||
}
|
||||
&.bottom-pane{
|
||||
background: palevioletred;
|
||||
}
|
||||
}
|
||||
.custom-trigger{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: #000000;
|
||||
position: absolute;
|
||||
.center-middle;
|
||||
box-shadow: 0 0 6px 0 rgba(28, 36, 56, 0.4);
|
||||
i.trigger-icon{
|
||||
.center-middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div>
|
||||
<Card>
|
||||
<tables ref="tables" editable searchable search-place="top" v-model="tableData" :columns="columns" @on-delete="handleDelete"/>
|
||||
<Button style="margin: 10px 0;" type="primary" @click="exportExcel">导出为Csv文件</Button>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tables from '_c/tables'
|
||||
import { getTableData } from '@/api/data'
|
||||
export default {
|
||||
name: 'tables_page',
|
||||
components: {
|
||||
Tables
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns: [
|
||||
{title: 'Name', key: 'name', sortable: true},
|
||||
{title: 'Email', key: 'email', editable: true},
|
||||
{title: 'Create-Time', key: 'createTime'},
|
||||
{
|
||||
title: 'Handle',
|
||||
key: 'handle',
|
||||
options: ['delete'],
|
||||
button: [
|
||||
(h, params, vm) => {
|
||||
return h('Poptip', {
|
||||
props: {
|
||||
confirm: true,
|
||||
title: '你确定要删除吗?'
|
||||
},
|
||||
on: {
|
||||
'on-ok': () => {
|
||||
vm.$emit('on-delete', params)
|
||||
vm.$emit('input', params.tableData.filter((item, index) => index !== params.row.initRowIndex))
|
||||
}
|
||||
}
|
||||
}, [
|
||||
h('Button', '自定义删除')
|
||||
])
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDelete (params) {
|
||||
console.log(params)
|
||||
},
|
||||
exportExcel () {
|
||||
this.$refs.tables.exportCsv({
|
||||
filename: `table-${(new Date()).valueOf()}.csv`
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
getTableData().then(res => {
|
||||
this.tableData = res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<div>
|
||||
<Row>
|
||||
<i-col>
|
||||
<Card>
|
||||
<Row>
|
||||
<i-col span="4">
|
||||
<Button type="primary" @click="showModal">显示可拖动弹窗</Button>
|
||||
<Button v-draggable="buttonOptions" class="draggable-btn">这个按钮也是可以拖动的</Button>
|
||||
</i-col>
|
||||
<i-col span="20">
|
||||
<div class="intro-con">
|
||||
<Modal v-draggable="options" v-model="visible">标题</Modal>
|
||||
<pre class="code-con">
|
||||
options = {
|
||||
trigger: '.ivu-modal-body',
|
||||
body: '.ivu-modal'
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</i-col>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
<Modal v-draggable="options" v-model="modalVisible">
|
||||
拖动这里即可拖动整个弹窗
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'directive_page',
|
||||
data () {
|
||||
return {
|
||||
modalVisible: false,
|
||||
options: {
|
||||
trigger: '.ivu-modal-body',
|
||||
body: '.ivu-modal',
|
||||
recover: true
|
||||
},
|
||||
buttonOptions: {
|
||||
trigger: '.draggable-btn',
|
||||
body: '.draggable-btn'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showModal () {
|
||||
this.modalVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.intro-con{
|
||||
height: 140px;
|
||||
}
|
||||
.draggable-btn{
|
||||
margin-top: 20px;
|
||||
}
|
||||
.code-con{
|
||||
width: 400px;
|
||||
background: #F9F9F9;
|
||||
padding-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -16,11 +16,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import loginForm from '_c/login-form'
|
||||
import LoginForm from '_c/login-form'
|
||||
import { mapActions } from 'vuex'
|
||||
export default {
|
||||
components: {
|
||||
loginForm
|
||||
LoginForm
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
<template>
|
||||
<div class="custom-bread-crumb">
|
||||
<Breadcrumb :style="{fontSize: `${fontSize}px`}">
|
||||
<BreadcrumbItem v-for="item in list" :to="item.to" :key="`bread-crumb-${item.name}`"><Icon v-if="showIcon" :type="item.icon" style="margin-right: 4px;" />{{ showTitle(item) }}</BreadcrumbItem>
|
||||
<BreadcrumbItem v-for="item in list" :to="item.to" :key="`bread-crumb-${item.name}`">
|
||||
<common-icon style="margin-right: 4px;" :type="item.icon || ''"/>
|
||||
{{ showTitle(item) }}
|
||||
</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { showTitle } from '_c/common/util'
|
||||
import CommonIcon from '_c/common-icon'
|
||||
import './custom-bread-crumb.less'
|
||||
export default {
|
||||
name: 'customBreadCrumb',
|
||||
components: {
|
||||
CommonIcon
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
|
|
@ -27,6 +34,13 @@ export default {
|
|||
methods: {
|
||||
showTitle (item) {
|
||||
return showTitle(item, this)
|
||||
},
|
||||
isCustomIcon (iconName) {
|
||||
return iconName.indexOf('_') === 0
|
||||
},
|
||||
getCustomIconName (iconName) {
|
||||
console.log(iconName)
|
||||
return iconName.slice(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import siderTrigger from './sider-trigger'
|
|||
import customBreadCrumb from './custom-bread-crumb'
|
||||
import './header-bar.less'
|
||||
export default {
|
||||
name: 'headerBar',
|
||||
name: 'HeaderBar',
|
||||
components: {
|
||||
siderTrigger,
|
||||
customBreadCrumb
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
import headerBar from './header-bar'
|
||||
export default headerBar
|
||||
import HeaderBar from './header-bar'
|
||||
export default HeaderBar
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
import mixin from './mixin'
|
||||
import itemMixin from './item-mixin'
|
||||
export default {
|
||||
name: 'collapsedMenu',
|
||||
name: 'CollapsedMenu',
|
||||
mixins: [ mixin, itemMixin ],
|
||||
props: {
|
||||
hideTitle: {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
import sideMenu from './side-menu.vue'
|
||||
export default sideMenu
|
||||
import SideMenu from './side-menu.vue'
|
||||
export default SideMenu
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import CommonIcon from '_c/common-icon'
|
||||
export default {
|
||||
components: {
|
||||
CommonIcon
|
||||
},
|
||||
methods: {
|
||||
showTitle (item) {
|
||||
return this.$config.useI18n ? this.$t(item.name) : ((item.meta && item.meta.title) || item.name)
|
||||
},
|
||||
showChildren (item) {
|
||||
return item.children && item.children.length !== 0
|
||||
return item.children && item.children.length > 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,14 @@
|
|||
<span>{{ showTitle(parentItem) }}</span>
|
||||
</template>
|
||||
<template v-for="item in children">
|
||||
<side-menu-item v-if="item.children && item.children.length !== 0" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
|
||||
<menu-item v-else :name="`${item.name}`" :key="`menu-${item.name}`"><Icon :type="item.icon"/><span>{{ showTitle(item) }}</span></menu-item>
|
||||
<template v-if="item.children && item.children.length === 1">
|
||||
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
|
||||
<menu-item v-else :name="`${item.children[0].name}`" :key="`menu-${item.children[0].name}`"><common-icon :type="item.children[0].icon || ''"/><span>{{ showTitle(item.children[0]) }}</span></menu-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
|
||||
<menu-item v-else :name="`${item.name}`" :key="`menu-${item.name}`"><common-icon :type="item.icon || ''"/><span>{{ showTitle(item) }}</span></menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</Submenu>
|
||||
</template>
|
||||
|
|
@ -14,7 +20,7 @@
|
|||
import mixin from './mixin'
|
||||
import itemMixin from './item-mixin'
|
||||
export default {
|
||||
name: 'sideMenuItem',
|
||||
name: 'SideMenuItem',
|
||||
mixins: [ mixin, itemMixin ]
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -7,19 +7,28 @@
|
|||
user-select: none;
|
||||
.menu-collapsed{
|
||||
padding-top: 10px;
|
||||
a.drop-menu-a{
|
||||
display: inline-block;
|
||||
padding: 6px 15px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #495060;
|
||||
}
|
||||
|
||||
.ivu-dropdown{
|
||||
width: 100%;
|
||||
.ivu-dropdown-rel button{
|
||||
.ivu-dropdown-rel a{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.ivu-tooltip{
|
||||
width: 100%;
|
||||
.ivu-tooltip-rel{
|
||||
width: 100%;
|
||||
}
|
||||
.ivu-tooltip-popper .ivu-tooltip-content{
|
||||
.ivu-tooltip-arrow{
|
||||
border-right-color: #fff;
|
||||
}
|
||||
.ivu-tooltip-inner{
|
||||
background: #fff;
|
||||
color: #495060;
|
||||
}
|
||||
}
|
||||
}
|
||||
.menu-title{
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
|
@ -28,4 +37,11 @@
|
|||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
a.drop-menu-a{
|
||||
display: inline-block;
|
||||
padding: 6px 15px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #495060;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,23 @@
|
|||
<slot></slot>
|
||||
<Menu ref="menu" v-show="!collapsed" :active-name="activeName" :open-names="openedNames" :accordion="accordion" :theme="theme" width="auto" @on-select="handleSelect">
|
||||
<template v-for="item in menuList">
|
||||
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
|
||||
<menu-item v-else :name="`${item.name}`" :key="`menu-${item.name}`"><Icon :type="item.icon"/><span>{{ showTitle(item) }}</span></menu-item>
|
||||
<template v-if="item.children && item.children.length === 1">
|
||||
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
|
||||
<menu-item v-else :name="`${item.children[0].name}`" :key="`menu-${item.children[0].name}`"><common-icon :type="item.children[0].icon || ''"/><span>{{ showTitle(item.children[0]) }}</span></menu-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
|
||||
<menu-item v-else :name="`${item.name}`" :key="`menu-${item.name}`"><common-icon :type="item.icon || ''"/><span>{{ showTitle(item) }}</span></menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</Menu>
|
||||
<div class="menu-collapsed" v-show="collapsed" :list="menuList">
|
||||
<collapsed-menu @on-click="handleSelect" hide-title :root-icon-size="rootIconSize" :icon-size="iconSize" :theme="theme" v-for="item in menuList" :parent-item="item" :key="`drop-menu-${item.name}`"></collapsed-menu>
|
||||
<template v-for="item in menuList">
|
||||
<collapsed-menu v-if="item.children && item.children.length > 1" @on-click="handleSelect" hide-title :root-icon-size="rootIconSize" :icon-size="iconSize" :theme="theme" :parent-item="item" :key="`drop-menu-${item.name}`"></collapsed-menu>
|
||||
<Tooltip v-else :content="item.children[0].meta.title" placement="right" :key="`drop-menu-${item.children[0].name}`">
|
||||
<a @click="handleSelect(item.children[0].name)" class="drop-menu-a" :style="{textAlign: 'center'}"><Icon :size="rootIconSize" :color="textColor" :type="item.children[0].icon"/></a>
|
||||
</Tooltip>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -17,12 +28,13 @@ import sideMenuItem from './side-menu-item.vue'
|
|||
import collapsedMenu from './collapsed-menu.vue'
|
||||
import { getUnion } from '@/libs/tools'
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'sideMenu',
|
||||
name: 'SideMenu',
|
||||
mixins: [ mixin ],
|
||||
components: {
|
||||
sideMenuItem,
|
||||
collapsedMenu
|
||||
SideMenuItem,
|
||||
CollapsedMenu
|
||||
},
|
||||
props: {
|
||||
menuList: {
|
||||
|
|
@ -69,6 +81,11 @@ export default {
|
|||
return this.$route.matched.map(item => item.name).filter(item => item !== name)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
textColor () {
|
||||
return this.theme === 'dark' ? '#fff' : '#495060'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeName (name) {
|
||||
if (this.accordion) this.openedNames = this.getOpenedNamesByActiveName(name)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
import tagsNav from './tags-nav.vue'
|
||||
export default tagsNav
|
||||
import TagsNav from './tags-nav.vue'
|
||||
export default TagsNav
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
:name="item.name"
|
||||
@on-close="handleClose"
|
||||
@click.native="handleClick(item)"
|
||||
:closable="item.name==='home_index'?false:true"
|
||||
:closable="item.name !== 'home'"
|
||||
:color="item.name === value.name ? 'blue' : 'default'"
|
||||
>{{ showTitleInside(item) }}</Tag>
|
||||
</transition-group>
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
<script>
|
||||
import { showTitle } from '@/libs/util'
|
||||
export default {
|
||||
name: 'tagsNav',
|
||||
name: 'TagsNav',
|
||||
props: {
|
||||
value: Object,
|
||||
list: {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
import user from './user.vue'
|
||||
export default user
|
||||
import User from './user.vue'
|
||||
export default User
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
import './user.less'
|
||||
import { mapActions } from 'vuex'
|
||||
export default {
|
||||
name: 'user',
|
||||
name: 'User',
|
||||
props: {
|
||||
userAvator: {
|
||||
type: String,
|
||||
|
|
|
|||
|
|
@ -19,4 +19,13 @@
|
|||
background:#F0F0F0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.content-wrapper{
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
.ivu-menu-item > i{
|
||||
margin-right: 12px !important;
|
||||
}
|
||||
.ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<div class="tag-nav-wrapper">
|
||||
<tags-nav :value="$route" @input="handleClick" :list="tagNavList" @on-close="handleCloseTag"/>
|
||||
</div>
|
||||
<Content>
|
||||
<Content class="content-wrapper">
|
||||
<keep-alive :include="cacheList">
|
||||
<router-view/>
|
||||
</keep-alive>
|
||||
|
|
@ -31,22 +31,22 @@
|
|||
</Layout>
|
||||
</template>
|
||||
<script>
|
||||
import sideMenu from './components/side-menu'
|
||||
import headerBar from './components/header-bar'
|
||||
import tagsNav from './components/tags-nav'
|
||||
import user from './components/user'
|
||||
import SideMenu from './components/side-menu'
|
||||
import HeaderBar from './components/header-bar'
|
||||
import TagsNav from './components/tags-nav'
|
||||
import User from './components/user'
|
||||
import { mapMutations, mapActions } from 'vuex'
|
||||
import { getNewTagList } from '@/libs/util'
|
||||
import { getNewTagList, getNextName } from '@/libs/util'
|
||||
import minLogo from '@/assets/images/logo-min.jpg'
|
||||
import maxLogo from '@/assets/images/logo.jpg'
|
||||
import './main.less'
|
||||
export default {
|
||||
name: 'Main',
|
||||
components: {
|
||||
sideMenu,
|
||||
headerBar,
|
||||
tagsNav,
|
||||
user
|
||||
SideMenu,
|
||||
HeaderBar,
|
||||
TagsNav,
|
||||
User
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
@ -59,11 +59,14 @@ export default {
|
|||
tagNavList () {
|
||||
return this.$store.state.app.tagNavList
|
||||
},
|
||||
tagRouter () {
|
||||
return this.$store.state.app.tagRouter
|
||||
},
|
||||
userAvator () {
|
||||
return this.$store.state.user.avatorImgPath
|
||||
},
|
||||
cacheList () {
|
||||
return this.tagNavList.length ? this.tagNavList.filter(item => !(item.meta && item.meta.notCache)) : []
|
||||
return this.tagNavList.length ? this.tagNavList.filter(item => !(item.meta && item.meta.notCache)).map(item => item.name) : []
|
||||
},
|
||||
menuList () {
|
||||
return this.$store.getters.menuList
|
||||
|
|
@ -86,9 +89,11 @@ export default {
|
|||
handleCollapsedChange (state) {
|
||||
this.collapsed = state
|
||||
},
|
||||
handleCloseTag (res, type) {
|
||||
handleCloseTag (res, type, name) {
|
||||
const nextName = getNextName(this.tagNavList, name)
|
||||
this.setTagNavList(res)
|
||||
if (type === 'all') this.turnToPage('home')
|
||||
else if (this.$route.name === name) this.$router.push({ name: nextName })
|
||||
},
|
||||
handleClick (item) {
|
||||
this.turnToPage(item.name)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<Row :gutter="10">
|
||||
<i-col span="12">
|
||||
<Card>
|
||||
<div class="update-paste-con">
|
||||
<paste-editor v-model="pasteDataArr" @on-success="handleSuccess" @on-error="handleError"/>
|
||||
</div>
|
||||
<div class="update-paste-btn-con">
|
||||
<span class="paste-tip">使用Tab键换列,使用回车键换行</span>
|
||||
<Button type="primary" style="float: right;" @click="handleShow">显示表格数据</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="12">
|
||||
<Card>
|
||||
<Table :height="400" :columns="columns" :data="tableData"/>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PasteEditor from '_c/paste-editor'
|
||||
import { getTableDataFromArray } from '@/libs/util'
|
||||
export default {
|
||||
name: 'update_paste_page',
|
||||
components: {
|
||||
PasteEditor
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
pasteDataArr: [],
|
||||
columns: [],
|
||||
tableData: [],
|
||||
validated: true,
|
||||
errorIndex: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSuccess () {
|
||||
this.validated = true
|
||||
},
|
||||
handleError (index) {
|
||||
this.validated = false
|
||||
this.errorIndex = index
|
||||
},
|
||||
handleShow () {
|
||||
if (!this.validated) {
|
||||
this.$Notice.error({
|
||||
title: '您的内容不规范',
|
||||
desc: `您的第${this.errorIndex + 1}行数据不规范,请修改`
|
||||
})
|
||||
} else {
|
||||
let { columns, tableData } = getTableDataFromArray(this.pasteDataArr)
|
||||
this.columns = columns
|
||||
this.tableData = tableData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.update-paste{
|
||||
&-con{
|
||||
height: 350px;
|
||||
}
|
||||
&-btn-con{
|
||||
box-sizing: content-box;
|
||||
height: 30px;
|
||||
padding: 15px 0 5px;
|
||||
}
|
||||
}
|
||||
.paste-tip{
|
||||
color: #19be6b;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<Row :gutter="10">
|
||||
<i-col span="6">
|
||||
<Card>
|
||||
<Upload action="" :before-upload="beforeUpload">
|
||||
<Button type="ghost" icon="ios-cloud-upload-outline">上传Csv文件</Button>
|
||||
点击上传Csv文件
|
||||
</Upload>
|
||||
<p>util.js提供两个方法用来实现这个功能:</p>
|
||||
<p class="update-table-intro"><Icon style="margin-right: 10px;" :size="10" type="heart"/><span class="code-high-line">getArrayFromFile</span>:将Csv文件解析为二维数组</p>
|
||||
<p class="update-table-intro"><Icon style="margin-right: 10px;" :size="10" type="heart"/><span class="code-high-line">getTableDataFromArray</span>:将二维数组转为表格数据,具体请看文档</p>
|
||||
</Card>
|
||||
</i-col>
|
||||
<i-col span="18">
|
||||
<Table :height="500" :columns="columns" :data="tableData"/>
|
||||
</i-col>
|
||||
</Row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getArrayFromFile, getTableDataFromArray } from '@/libs/util'
|
||||
export default {
|
||||
name: 'update_table_page',
|
||||
data () {
|
||||
return {
|
||||
columns: [],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
beforeUpload (file) {
|
||||
getArrayFromFile(file).then(data => {
|
||||
let {columns, tableData} = getTableDataFromArray(data)
|
||||
this.columns = columns
|
||||
this.tableData = tableData
|
||||
}).catch(() => {
|
||||
this.$Notice.warning({
|
||||
title: '只能上传Csv文件',
|
||||
desc: '只能上传Csv文件,请重新上传'
|
||||
})
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.update-table-intro{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.code-high-line{
|
||||
color: #2d8cf0;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue