init
3
.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
VUE_APP_API_HOST=10.0.235.4:9000
|
||||||
|
VUE_APP_TITLE=包管理系统
|
||||||
|
VUE_APP_TITLE_EN=PROJECT PACKAGE MANAGER
|
3
.env.production
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
VUE_APP_API_HOST=127.0.0.1:8000
|
||||||
|
VUE_APP_TITLE=包管理系统
|
||||||
|
VUE_APP_TITLE_EN=PROJECT PACKAGE MANAGER
|
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/node_modules/
|
||||||
|
.idea
|
||||||
|
dist/
|
||||||
|
/package-lock.json
|
||||||
|
/.env.development
|
19
README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# project package manager
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
5
babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/app'
|
||||||
|
]
|
||||||
|
}
|
63
package.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"name": "hola_admin",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"build:dev": "vue-cli-service build --mode=test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"autoprefixer": "^9.8.6",
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"ckeditor4-vue": "^1.2.0",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
|
"echarts": "^5.2.1",
|
||||||
|
"element-ui": "^2.14.1",
|
||||||
|
"js-sha512": "^0.8.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"postcss": "^7.0.36",
|
||||||
|
"sprintf-js": "^1.1.2",
|
||||||
|
"tailwindcss": "npm:@tailwindcss/postcss7-compat@2.1.0",
|
||||||
|
"vant": "^2.12.10",
|
||||||
|
"view-design": "^4.5.0",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-class-component": "^7.2.3",
|
||||||
|
"vue-i18n": "^8.22.2",
|
||||||
|
"vue-property-decorator": "^8.4.2",
|
||||||
|
"vue-router": "^3.2.0",
|
||||||
|
"vuedraggable": "2.20.0",
|
||||||
|
"vuex": "^3.4.0",
|
||||||
|
"vuex-class": "^0.3.2",
|
||||||
|
"vuex-persistedstate": "^4.0.0-beta.1",
|
||||||
|
"web3": "^1.7.4",
|
||||||
|
"weixin-js-sdk": "^1.6.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss7-compat": "^2.2.6",
|
||||||
|
"@types/echarts": "^4.9.10",
|
||||||
|
"@types/lodash": "^4.14.171",
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"babel-plugin-component": "^1.1.1",
|
||||||
|
"less": "^3.0.4",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"svg-sprite-loader": "4.1.3",
|
||||||
|
"svgo": "^2.3.1",
|
||||||
|
"typescript": "~3.9.3",
|
||||||
|
"vue-cli-plugin-iview": "^2.0.0",
|
||||||
|
"vue-template-compiler": "^2.6.11",
|
||||||
|
"vuex-module-decorators": "^1.0.1"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"last 2 version",
|
||||||
|
"> 1%",
|
||||||
|
"iOS >= 7",
|
||||||
|
"Android > 4.1",
|
||||||
|
"Firefox > 20"
|
||||||
|
]
|
||||||
|
}
|
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
10
public/.htaccess
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
Options +FollowSymlinks -Multiviews
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
|
||||||
|
RewriteRule ^(.*)$ index.html [QSA,PT,L]
|
||||||
|
|
||||||
|
</IfModule>
|
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
16
public/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title><%= VUE_APP_TITLE %></title>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-800">
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app" ></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
16
public/wap.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title><%= VUE_APP_TITLE %></title>
|
||||||
|
</head>
|
||||||
|
<body style="background:#f2f2f2">
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
21
src/app.d.ts
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import VueRouter from 'vue-router'
|
||||||
|
import { Toast } from "vant";
|
||||||
|
import * as _ from 'lodash'
|
||||||
|
|
||||||
|
declare module "vue/types/vue" {
|
||||||
|
import { Route } from "vue-router";
|
||||||
|
import {RequestInterface} from "@/views/admin/types/Types";
|
||||||
|
import VueI18n from "vue-i18n";
|
||||||
|
|
||||||
|
interface Vue {
|
||||||
|
$router : VueRouter;
|
||||||
|
$route : Route;
|
||||||
|
$http : RequestInterface,
|
||||||
|
$lang: Function,
|
||||||
|
$sprintf: Function,
|
||||||
|
$toast : Toast,
|
||||||
|
$_ : _,
|
||||||
|
$bus: any,
|
||||||
|
$isDev: boolean
|
||||||
|
}
|
||||||
|
}
|
1
src/assets/image/dashboard/script.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972646504" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11330" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M868.836693 520.02816V173.622613h-148.241066V28.603733H127.665493c-27.293013 0-49.411413 21.64736-49.411413 48.339627v870.11328c0 26.70592 22.1184 48.346453 49.411413 48.346453h33.355094l485.915306-475.374933h221.9008zM178.121387 745.424213c-20.473173 0.013653-37.0688-16.19968-37.082454-36.22912-0.013653-20.015787 16.56832-36.27008 37.034667-36.276906h0.047787c20.45952 0.013653 37.04832 16.267947 37.034666 36.276906s-16.5888 36.215467-37.034666 36.22912z m0-233.424213c-20.473173 0.013653-37.0688-16.213333-37.082454-36.235947s16.56832-36.263253 37.034667-36.276906h0.047787c20.45952 0.02048 37.04832 16.26112 37.034666 36.276906-0.013653 20.015787-16.5888 36.22912-37.034666 36.235947z m0-233.424213c-20.473173 0-37.055147-16.233813-37.055147-36.256427s16.5888-36.256427 37.055147-36.256427c20.45952 0 37.061973 16.233813 37.061973 36.256427s-16.602453 36.256427-37.061973 36.256427z" fill="#F27151" p-id="11331"></path><path d="M646.935893 520.02816l-485.915306 475.374933h658.404693c27.293013 0 49.411413-21.640533 49.411413-48.346453V520.02816H646.935893z" fill="#D56649" p-id="11332"></path><path d="M720.602453 173.622613h148.241067L720.602453 28.603733v145.01888z" fill="#F4C2BC" p-id="11333"></path><path d="M868.836693 318.641493V173.622613h-148.241066l148.241066 145.01888z" fill="#D66648" p-id="11334"></path><path d="M275.92704 253.699413h494.114133v48.339627h-494.114133v-48.339627z m0 152.55552h494.114133v48.339627h-494.114133V406.254933z m0 152.582827v48.346453h281.914027l49.411413-48.346453H275.92704zM275.92704 711.400107v48.3328h125.97248l49.411413-48.3328H275.92704z" fill="#C9C5DD" p-id="11335"></path><path d="M914.814293 674.829653c27.450027-39.478613 27.450027-134.22592 27.450027-134.22592H667.736747s-7.5776 94.76096 19.838293 134.22592c24.08448 34.6112 61.016747 54.59968 61.016747 80.909654v0.34816c0 26.344107-36.94592 44.455253-61.016747 79.0528-27.450027 39.478613-19.838293 131.679573-19.838293 131.679573h274.527573s0-92.03712-27.450027-131.52256c-24.08448-34.6112-68.642133-52.57216-68.642133-78.895787 0-26.29632 44.557653-46.96064 68.642133-81.57184z" fill="#FFFFFF" p-id="11336"></path><path d="M791.258453 540.596907h-96.085333s0 55.296 13.748907 94.747306c17.885867 51.452587 82.343253 67.106133 82.343253 119.74656 0 52.61312 0 171.677013 13.714773 171.677014 13.735253 0 13.735253-118.0672 13.735254-170.693974 0-52.61312 64.477867-69.440853 82.35008-120.907093 13.735253-39.46496 13.735253-94.59712 13.735253-94.59712h-123.528533v0.027307z" fill="#F9C82D" p-id="11337"></path><path d="M940.48256 943.158613H668.719787c-13.63968 0-24.705707 10.601813-24.705707 23.681707s11.066027 23.681707 24.705707 23.681707h271.762773c13.653333 0 24.705707-10.601813 24.705707-23.681707s-11.052373-23.681707-24.705707-23.681707z m0-426.236586H668.719787c-9.09312 0.08192-17.38752 4.983467-21.531307 12.731733h314.866347c-4.164267-7.76192-12.465493-12.670293-21.572267-12.731733z m-293.29408 12.731733a22.309547 22.309547 0 0 0-3.1744 10.949973c0 13.079893 11.066027 23.681707 24.705707 23.681707h271.762773c13.653333 0 24.705707-10.601813 24.705707-23.681707a22.65088 22.65088 0 0 0-3.13344-10.949973H647.18848z" fill="#3BAFDA" p-id="11338"></path></svg>
|
After Width: | Height: | Size: 3.5 KiB |
1
src/assets/image/dashboard/任务.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972631189" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10965" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M190.57142832 174.5h642.85714336c70.71428584 0 128.57142832 57.85714248 128.57142832 128.57142832V865.57142832c0 45-35.35714248 80.35714248-80.35714248 80.35714336H190.57142832c-70.71428584 0-128.57142832-57.85714248-128.57142832-128.5714292v-514.28571416c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#FFBB96" p-id="10966"></path><path d="M190.57142832 174.5h642.85714336c70.71428584 0 128.57142832 57.85714248 128.57142832 128.57142832V704.85714248l-128.57142832 115.71428584-3.21428584 3.21428584-128.57142832 122.14285752H190.57142832c-70.71428584 0-128.57142832-57.85714248-128.57142832-128.5714292v-514.28571416c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#CF5A1A" p-id="10967"></path><path d="M190.57142832 174.5h642.85714336c70.71428584 0 128.57142832 57.85714248 128.57142832 128.57142832V704.85714248h-176.78571416c-45 0-80.35714248 35.35714248-80.35714336 80.35714336v160.71428584H190.57142832c-70.71428584 0-128.57142832-57.85714248-128.57142832-128.5714292v-514.28571416c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#FF7A45" p-id="10968"></path><path d="M351.28571416 78.07142832c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752v147.85714248c0 19.28571416-12.85714248 32.14285752-32.14285752 32.14285752s-32.14285752-12.85714248-32.14285664-32.14285752V110.21428584c0-19.28571416 12.85714248-32.14285752 32.14285664-32.14285752zM672.71428584 78.07142832c19.28571416 0 32.14285752 12.85714248 32.14285664 32.14285752v147.85714248c0 19.28571416-12.85714248 32.14285752-32.14285664 32.14285752s-32.14285752-12.85714248-32.14285752-32.14285752V110.21428584c0-19.28571416 12.85714248-32.14285752 32.14285752-32.14285752z" fill="#FFBB96" p-id="10969"></path><path d="M335.21428584 495.92857168m-48.21428584-1e-8a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#FFBB96" p-id="10970"></path><path d="M512 463.78571416h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752s-12.85714248 32.14285752-32.14285752 32.14285665h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285665s12.85714248-32.14285752 32.14285752-32.14285752zM512 624.5h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752s-12.85714248 32.14285752-32.14285752 32.14285664h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285664s12.85714248-32.14285752 32.14285752-32.14285752z" fill="#FFBB96" p-id="10971"></path><path d="M335.21428584 656.64285752m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#FFBB96" p-id="10972"></path></svg>
|
After Width: | Height: | Size: 3.0 KiB |
1
src/assets/image/dashboard/心-男手机.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972704033" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15193" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M295.55 926.53c-30.12 0-54.59-24.5-54.59-54.59V144c0-30.1 24.47-54.59 54.59-54.59H732.3c30.09 0 54.59 24.5 54.59 54.59v727.93c0 30.09-24.5 54.59-54.59 54.59H295.55z" fill="#48CFAD" p-id="15194"></path><path d="M710.31 676.69l-1.52-0.48c-25.75-6.98-44.65-13.62-56.03-18.02-40.28-15.49-50.81-26.69-53.47-31.96-0.08-0.19-0.16-0.4-0.26-0.59l-0.35-49.29-172.15 1.97-0.35 47.32c-0.08 0.19-0.16 0.4-0.24 0.59-2.69 5.28-13.17 16.47-53.47 31.99-11.36 4.37-30.28 11.01-55.82 17.94l-1.73 0.53c-23.25 7.76-38.87 29.54-38.87 54.11v68.32h473.14V730.8c-0.01-24.57-15.63-46.35-38.88-54.11z" fill="#5D9CEC" p-id="15195"></path><path d="M646.68 486.31c0 87.12-83.06 170.87-134.09 170.87-51.02 0-134.06-83.76-134.06-170.87s60.03-144.59 134.06-144.59c74.06 0 134.09 57.47 134.09 144.59z" fill="#EAC6BB" p-id="15196"></path><path d="M598.99 325.97c-22.82-20.66-99.25-46.01-175.48 0-38.6 23.27-66.7 126.17-66.7 126.17s75.31 42.68 173.32-3.44c58.67-27.62 57.37-13.14 74.11 11.99 9.94 14.9 42.44 25.62 42.44 25.62s25.27-94.32-47.69-160.34z" fill="#A85D5D" p-id="15197"></path><path d="M732.31 71.23H295.55c-40.23 0-72.8 32.57-72.8 72.77v727.93c0 40.2 32.57 72.8 72.8 72.8H732.3c40.2 0 72.77-32.6 72.77-72.8V144c0.01-40.2-32.57-72.77-72.76-72.77z m36.38 800.7c0 20.07-16.34 36.39-36.39 36.39H295.55c-20.07 0-36.41-16.32-36.41-36.39V144c0-20.07 16.34-36.39 36.41-36.39H732.3c20.05 0 36.39 16.31 36.39 36.39v727.93z" fill="#434A54" p-id="15198"></path><path d="M690.05 144c-11.97 0-22.79 4.93-30.55 12.85-7.76-7.92-18.58-12.85-30.58-12.85-23.62 0-42.79 19.17-42.79 42.79 0 48.91 73.36 91.7 73.36 91.7s73.33-42.79 73.33-91.7c0.02-23.62-19.12-42.79-42.77-42.79z" fill="#ED5564" p-id="15199"></path><path d="M240.96 762.74v109.19c0 30.09 24.47 54.59 54.59 54.59H732.3c30.09 0 54.59-24.5 54.59-54.59V762.74H240.96z" fill="#434A54" p-id="15200"></path><path d="M513.93 799.13c-30.18 0-54.59 24.44-54.59 54.59 0 30.15 24.42 54.59 54.59 54.59 30.15 0 54.59-24.44 54.59-54.59 0-30.14-24.44-54.59-54.59-54.59z m0 72.8c-10.05 0-18.21-8.16-18.21-18.21 0-10.02 8.16-18.18 18.21-18.18 10.02 0 18.18 8.16 18.18 18.18 0 10.05-8.16 18.21-18.18 18.21z" fill="#656D78" p-id="15201"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
1
src/assets/image/dashboard/项目信息.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972602532" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8591" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M287 62h530.35714248C862.35714248 62 897.71428584 97.35714248 897.71428584 142.35714248V447.71428584H158.42857168V190.57142832c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#B5F5EC" p-id="8592"></path><path d="M647 62H238.78571416C193.78571416 62 158.42857168 97.35714248 158.42857168 142.35714248v739.28571504C158.42857168 926.64285752 193.78571416 962 238.78571416 962h575.35714336c45 0 80.35714248-35.35714248 80.35714248-80.35714248V309.5L647 62z" fill="#36CFC9" p-id="8593"></path><path d="M650.21428584 62v186.42857168c0 32.14285752 25.71428584 61.07142832 61.07142832 61.07142832H897.71428584L650.21428584 62z" fill="#08979C" p-id="8594"></path><path d="M335.21428584 415.57142832m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#B5F5EC" p-id="8595"></path><path d="M512 383.42857168h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285664s-12.85714248 32.14285752-32.14285752 32.14285752h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285752s12.85714248-32.14285752 32.14285752-32.14285664zM512 544.14285752h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285664s-12.85714248 32.14285752-32.14285752 32.14285752h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285752s12.85714248-32.14285752 32.14285752-32.14285664zM512 704.85714248h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752s-12.85714248 32.14285752-32.14285752 32.14285752h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285752s12.85714248-32.14285752 32.14285752-32.14285752z" fill="#B5F5EC" p-id="8596"></path><path d="M335.21428584 576.28571416m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#B5F5EC" p-id="8597"></path><path d="M335.21428584 737m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#B5F5EC" p-id="8598"></path></svg>
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/image/del.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src/assets/image/edit.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
src/assets/image/loginBg.jpg
Normal file
After Width: | Height: | Size: 468 KiB |
17
src/assets/js/wwlogin.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
! function (a, b, c) {
|
||||||
|
function d(c) {
|
||||||
|
var d = b.createElement("iframe"),
|
||||||
|
e = c.goto;
|
||||||
|
e += c.style ? "&style=" + c.style : "", e += c.href ? "&href=" + c.href : "", d.src = e, d.frameBorder = "0", d.allowTransparency = "true", d.scrolling = "no", d.width = "300px", d.height = "320px", d.style.transform = 'scale(0.8) translateY(-10%)';
|
||||||
|
var f = b.getElementById(c.id);
|
||||||
|
f.innerHTML = "", f.appendChild(d), d.onload = function () {
|
||||||
|
a.addEventListener("message", function (b) {
|
||||||
|
if(b.data && typeof b.data == "string" && b.data.substring(0,4) != 'http'){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
b.data && b.origin.indexOf("work.weixin.qq.com") > -1 && (a.location.href = b.data)
|
||||||
|
}), d.contentWindow.postMessage("ask_usePostMessage", "*")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.WwLogin = d
|
||||||
|
}(window, document);
|
13
src/assets/style/main.less
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-family: arial;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
33
src/assets/style/tailwind.css
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
@import "tailwindcss/base";
|
||||||
|
@import "tailwindcss/components";
|
||||||
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
|
.max-w-8xl {
|
||||||
|
max-width: 90rem;
|
||||||
|
}
|
||||||
|
.max-w-4xl {
|
||||||
|
max-width: 45rem;
|
||||||
|
}
|
||||||
|
.max-w-2xl {
|
||||||
|
max-width: 22.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.lg\:h-\(screen-14\) {
|
||||||
|
height: calc(100vh - 3.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@supports ((position: -webkit-sticky) or (position:sticky)) {
|
||||||
|
@media (min-width:1024px) {
|
||||||
|
.sticky\?lg\:h-screen {
|
||||||
|
height:100vh!important
|
||||||
|
}
|
||||||
|
lg\:.h-\(screen-14\) {
|
||||||
|
height: calc(100vh - 3.5rem);
|
||||||
|
}
|
||||||
|
.sticky\?lg\:h-\(screen-18\) {
|
||||||
|
height: calc(100vh - 4.5rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
166
src/components/DndList/index.vue
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dndList">
|
||||||
|
<div :style="{width:width1}" class="dndList-list">
|
||||||
|
<h3>{{ list1Title }}</h3>
|
||||||
|
<draggable :set-data="setData" :list="list1" group="article" class="dragArea">
|
||||||
|
<div v-for="element in list1" :key="element.id" class="list-complete-item" >
|
||||||
|
<div class="list-complete-item-handle">
|
||||||
|
{{ element.scriptName }}
|
||||||
|
</div>
|
||||||
|
<div style="position:absolute;right:0px;">
|
||||||
|
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
|
||||||
|
<i style="color:#ff4949" class="el-icon-delete" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
<div :style="{width:width2}" class="dndList-list">
|
||||||
|
<h3>{{ list2Title }}</h3>
|
||||||
|
<draggable :list="list2" group="article" class="dragArea">
|
||||||
|
<div v-for="element in list2" :key="element.id" class="list-complete-item">
|
||||||
|
<div class="list-complete-item-handle2" @click="pushEle(element)">
|
||||||
|
{{ element.scriptName }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DndList',
|
||||||
|
components: { draggable },
|
||||||
|
props: {
|
||||||
|
list1: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list2: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list1Title: {
|
||||||
|
type: String,
|
||||||
|
default: 'list1'
|
||||||
|
},
|
||||||
|
list2Title: {
|
||||||
|
type: String,
|
||||||
|
default: 'list2'
|
||||||
|
},
|
||||||
|
width1: {
|
||||||
|
type: String,
|
||||||
|
default: '48%'
|
||||||
|
},
|
||||||
|
width2: {
|
||||||
|
type: String,
|
||||||
|
default: '48%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isNotInList1(v) {
|
||||||
|
return this.list1.every(k => v.id !== k.id)
|
||||||
|
},
|
||||||
|
isNotInList2(v) {
|
||||||
|
return this.list2.every(k => v.id !== k.id)
|
||||||
|
},
|
||||||
|
deleteEle(ele) {
|
||||||
|
for (const item of this.list1) {
|
||||||
|
if (item.id === ele.id) {
|
||||||
|
const index = this.list1.indexOf(item)
|
||||||
|
this.list1.splice(index, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isNotInList2(ele)) {
|
||||||
|
this.list2.unshift(ele)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pushEle(ele) {
|
||||||
|
for (const item of this.list2) {
|
||||||
|
if (item.id === ele.id) {
|
||||||
|
const index = this.list2.indexOf(item)
|
||||||
|
this.list2.splice(index, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isNotInList1(ele)) {
|
||||||
|
this.list1.push(ele)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setData(dataTransfer) {
|
||||||
|
// to avoid Firefox bug
|
||||||
|
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
||||||
|
dataTransfer.setData('Text', '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.dndList {
|
||||||
|
background: #fff;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.dndList-list {
|
||||||
|
float: left;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
&:first-of-type {
|
||||||
|
margin-right: 2%;
|
||||||
|
}
|
||||||
|
.dragArea {
|
||||||
|
margin-top: 15px;
|
||||||
|
min-height: 50px;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item {
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 5px 12px;
|
||||||
|
margin-top: 4px;
|
||||||
|
border: 1px solid #bfcbd9;
|
||||||
|
transition: all 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item-handle {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item-handle2 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item.sortable-chosen {
|
||||||
|
background: #4AB7BD;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item.sortable-ghost {
|
||||||
|
background: #30B08F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-enter,
|
||||||
|
.list-complete-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
109
src/components/Kanban/index.vue
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<div class="board-column">
|
||||||
|
<div class="board-column-header">
|
||||||
|
{{ headerText }}
|
||||||
|
</div>
|
||||||
|
<draggable
|
||||||
|
:list="list"
|
||||||
|
v-bind="$attrs"
|
||||||
|
class="board-column-content"
|
||||||
|
:set-data="setData"
|
||||||
|
@start="start"
|
||||||
|
@end="end"
|
||||||
|
>
|
||||||
|
<div v-for="element in list" :key="element.id" class="board-item">
|
||||||
|
{{ element.name }} - {{element.user.name}}
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DragKanbanDemo',
|
||||||
|
components: {
|
||||||
|
draggable
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
headerText: {
|
||||||
|
type: String,
|
||||||
|
default: 'Header'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setData(dataTransfer) {
|
||||||
|
// to avoid Firefox bug
|
||||||
|
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
||||||
|
dataTransfer.setData('Text', '')
|
||||||
|
},
|
||||||
|
start(e){
|
||||||
|
this.$emit('start')
|
||||||
|
},
|
||||||
|
end(){
|
||||||
|
this.$emit('end')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.board-column {
|
||||||
|
min-width: 145px;
|
||||||
|
min-height: 100px;
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f0f0f0;
|
||||||
|
/*background: black;*/
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
|
||||||
|
.board-column-header {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 20px;
|
||||||
|
text-align: center;
|
||||||
|
background: #374151;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-column-content {
|
||||||
|
height: 660px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 10px solid transparent;
|
||||||
|
min-height: 660px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.board-item {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 36px;
|
||||||
|
margin: 5px 0;
|
||||||
|
background-color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
42
src/components/SvgIcon.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<svg :class="svgClass" aria-hidden="true">
|
||||||
|
<use :xlink:href="iconName"></use>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'svg-icon',
|
||||||
|
props: {
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iconName() {
|
||||||
|
return `#icon-${this.iconClass}`
|
||||||
|
},
|
||||||
|
svgClass() {
|
||||||
|
if (this.className) {
|
||||||
|
return 'svg-icon ' + this.className
|
||||||
|
} else {
|
||||||
|
return 'svg-icon'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
0
src/components/page.less
Normal file
72
src/components/page.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Component, Vue, Watch, Prop, Emit, PropSync } from 'vue-property-decorator'
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import { Table, TableColumn } from "view-design";
|
||||||
|
import Events from "@/utils/Events";
|
||||||
|
import { TableExportCsvParams } from "view-design/types/table";
|
||||||
|
import { stringify } from "postcss";
|
||||||
|
import Project from "@/views/home/pages/project/project";
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class page extends Vue {
|
||||||
|
name : string = "CustomPage"
|
||||||
|
|
||||||
|
@Prop({type : Number, default : 0})
|
||||||
|
total : number;
|
||||||
|
|
||||||
|
@Prop({default : true})
|
||||||
|
showPaginate : boolean
|
||||||
|
|
||||||
|
@PropSync('page', {type : Number}) currentPage! : Number
|
||||||
|
|
||||||
|
@Prop({type : Number, default : 10})
|
||||||
|
pageSize : number;
|
||||||
|
|
||||||
|
@Prop({type : Array, default : () => []})
|
||||||
|
columns : TableColumn[];
|
||||||
|
|
||||||
|
@Prop({type : Array, default : () => []})
|
||||||
|
dataList : Array<any>;
|
||||||
|
@Prop({default : false})
|
||||||
|
rowKey : Boolean | string
|
||||||
|
|
||||||
|
@Prop({type: String, default: "暂无数据"})
|
||||||
|
noDataText: string;
|
||||||
|
|
||||||
|
sizeOpt : number[] = [20, 40, 80, 120];
|
||||||
|
|
||||||
|
get currentPageSize() {
|
||||||
|
return this.pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (!this.sizeOpt.includes(this.pageSize)) {
|
||||||
|
this.sizeOpt.push(this.pageSize);
|
||||||
|
this.sizeOpt = this.sizeOpt.sort((a, b) => a - b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public exportCsv(params : TableExportCsvParams) {
|
||||||
|
let table : Table = this.$refs["table"] as Table;
|
||||||
|
table.exportCsv(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onPageSizeChange(size : number) {
|
||||||
|
this.$emit("update:pageSize", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Emit(Events.ON_PAGE_CHANGE)
|
||||||
|
public onPageChange(page : number) : number {
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Emit(Events.ON_SELECTION_CHANGE)
|
||||||
|
public onSelectionChange(selection : any[]) : any[] {
|
||||||
|
return selection
|
||||||
|
}
|
||||||
|
}
|
19
src/components/page.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div class="custom-page">
|
||||||
|
<Table :columns="columns" :data="dataList" ref="table"
|
||||||
|
@on-selection-change="onSelectionChange" :row-key="rowKey"
|
||||||
|
:no-data-text="noDataText"
|
||||||
|
stripe highlight-row border>
|
||||||
|
<template v-for="column in columns" :slot="column.slot?column.slot:''" slot-scope="params" >
|
||||||
|
<slot :name="column.slot?column.slot:''" v-bind="params" ></slot>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
<Page style="margin-top: 10px;float: right" :current.sync="currentPage" :total="total" :page-size="currentPageSize" show-total
|
||||||
|
show-elevator show-sizer @on-page-size-change="onPageSizeChange"
|
||||||
|
:page-size-opts="sizeOpt" v-if="showPaginate"
|
||||||
|
prev-text="上一页" next-text="下一页"></Page>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./page.ts"></script>
|
||||||
|
<style scoped lang="less" src="./page.less"></style>
|
10
src/icons/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'// svg component
|
||||||
|
|
||||||
|
// register globally
|
||||||
|
Vue.component('svg-icon', SvgIcon)
|
||||||
|
|
||||||
|
const req = require.context('./svg', false, /\.svg$/)
|
||||||
|
const requireAll = requireContext => requireContext.keys().map(requireContext)
|
||||||
|
requireAll(req)
|
||||||
|
|
1
src/icons/svg/device.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972704033" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15193" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M295.55 926.53c-30.12 0-54.59-24.5-54.59-54.59V144c0-30.1 24.47-54.59 54.59-54.59H732.3c30.09 0 54.59 24.5 54.59 54.59v727.93c0 30.09-24.5 54.59-54.59 54.59H295.55z" fill="#48CFAD" p-id="15194"></path><path d="M710.31 676.69l-1.52-0.48c-25.75-6.98-44.65-13.62-56.03-18.02-40.28-15.49-50.81-26.69-53.47-31.96-0.08-0.19-0.16-0.4-0.26-0.59l-0.35-49.29-172.15 1.97-0.35 47.32c-0.08 0.19-0.16 0.4-0.24 0.59-2.69 5.28-13.17 16.47-53.47 31.99-11.36 4.37-30.28 11.01-55.82 17.94l-1.73 0.53c-23.25 7.76-38.87 29.54-38.87 54.11v68.32h473.14V730.8c-0.01-24.57-15.63-46.35-38.88-54.11z" fill="#5D9CEC" p-id="15195"></path><path d="M646.68 486.31c0 87.12-83.06 170.87-134.09 170.87-51.02 0-134.06-83.76-134.06-170.87s60.03-144.59 134.06-144.59c74.06 0 134.09 57.47 134.09 144.59z" fill="#EAC6BB" p-id="15196"></path><path d="M598.99 325.97c-22.82-20.66-99.25-46.01-175.48 0-38.6 23.27-66.7 126.17-66.7 126.17s75.31 42.68 173.32-3.44c58.67-27.62 57.37-13.14 74.11 11.99 9.94 14.9 42.44 25.62 42.44 25.62s25.27-94.32-47.69-160.34z" fill="#A85D5D" p-id="15197"></path><path d="M732.31 71.23H295.55c-40.23 0-72.8 32.57-72.8 72.77v727.93c0 40.2 32.57 72.8 72.8 72.8H732.3c40.2 0 72.77-32.6 72.77-72.8V144c0.01-40.2-32.57-72.77-72.76-72.77z m36.38 800.7c0 20.07-16.34 36.39-36.39 36.39H295.55c-20.07 0-36.41-16.32-36.41-36.39V144c0-20.07 16.34-36.39 36.41-36.39H732.3c20.05 0 36.39 16.31 36.39 36.39v727.93z" fill="#434A54" p-id="15198"></path><path d="M690.05 144c-11.97 0-22.79 4.93-30.55 12.85-7.76-7.92-18.58-12.85-30.58-12.85-23.62 0-42.79 19.17-42.79 42.79 0 48.91 73.36 91.7 73.36 91.7s73.33-42.79 73.33-91.7c0.02-23.62-19.12-42.79-42.77-42.79z" fill="#ED5564" p-id="15199"></path><path d="M240.96 762.74v109.19c0 30.09 24.47 54.59 54.59 54.59H732.3c30.09 0 54.59-24.5 54.59-54.59V762.74H240.96z" fill="#434A54" p-id="15200"></path><path d="M513.93 799.13c-30.18 0-54.59 24.44-54.59 54.59 0 30.15 24.42 54.59 54.59 54.59 30.15 0 54.59-24.44 54.59-54.59 0-30.14-24.44-54.59-54.59-54.59z m0 72.8c-10.05 0-18.21-8.16-18.21-18.21 0-10.02 8.16-18.18 18.21-18.18 10.02 0 18.18 8.16 18.18 18.18 0 10.05-8.16 18.21-18.18 18.21z" fill="#656D78" p-id="15201"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
1
src/icons/svg/device_busy.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1644572465653" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2032" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M511.333 63.333c-247.424 0-448 200.576-448 448s200.576 448 448 448 448-200.576 448-448-200.576-448-448-448z m0 832c-51.868 0-102.15-10.144-149.451-30.15-36.011-15.231-69.123-35.67-98.812-60.897 12.177-31.985 42.226-63.875 84.223-88.903C396.189 686.243 456.222 669.53 512 669.53c55.631 0 115.416 16.658 164.026 45.703 41.762 24.953 71.689 56.812 83.863 88.804-29.764 25.342-62.976 45.865-99.106 61.146-47.299 20.006-97.582 30.15-149.45 30.15z m296.268-139.658c-20.493-35.937-54.353-68.855-98.747-95.381C649.75 624.979 579.839 605.53 512 605.53c-67.964 0-138.094 19.488-197.471 54.875-44.644 26.606-78.656 59.594-99.195 95.586-23.835-28.755-43.234-60.652-57.85-95.208-20.006-47.3-30.15-97.583-30.15-149.451s10.144-102.15 30.15-149.451c19.337-45.719 47.034-86.792 82.321-122.078 35.286-35.287 76.359-62.983 122.078-82.321 47.3-20.006 97.583-30.15 149.451-30.15 51.868 0 102.15 10.144 149.451 30.15 45.719 19.337 86.792 47.034 122.078 82.321 35.287 35.286 62.983 76.359 82.321 122.078 20.006 47.3 30.15 97.583 30.15 149.451s-10.144 102.15-30.15 149.451c-14.563 34.429-33.869 66.22-57.583 94.892z" fill="" p-id="2033"></path><path d="M512 220.223c-88.224 0-160 71.776-160 160s71.776 160 160 160c88.225 0 160-71.775 160-160s-71.775-160-160-160z m0 256c-52.935 0-96-43.065-96-96s43.065-96 96-96 96 43.065 96 96-43.065 96-96 96z" fill="" p-id="2034"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
1
src/icons/svg/device_free.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1644572535996" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2944" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M730.033231 915.692308H236.307692a108.465231 108.465231 0 0 1-108.307692-108.307693v-275.692307a108.465231 108.465231 0 0 1 78.966154-104.369231V216.694154A69.080615 69.080615 0 0 1 276.007385 147.692308h473.757538a69.080615 69.080615 0 0 1 69.001846 69.001846v211.259077A108.465231 108.465231 0 0 1 896 531.692308v275.692307A108.465231 108.465231 0 0 1 787.692308 915.692308zM787.692308 856.615385a49.270154 49.270154 0 0 0 49.230769-49.23077v-275.692307a49.309538 49.309538 0 0 0-43.323077-48.876308 29.774769 29.774769 0 0 1-4.332308 0.315077 29.735385 29.735385 0 0 1-6.301538-0.669539H242.806154a29.617231 29.617231 0 0 1-6.301539 0.669539 29.696 29.696 0 0 1-5.04123-0.433231A49.309538 49.309538 0 0 0 187.076923 531.692308v275.692307A49.270154 49.270154 0 0 0 236.307692 856.615385h168.054154v-128.393847a29.538462 29.538462 0 0 1 29.538462-29.538461h296.132923a29.538462 29.538462 0 0 1 29.538461 29.538461v128.393847z m-87.236923 0v-98.855385h-237.016616v98.855385z m59.076923-433.23077V216.694154a9.924923 9.924923 0 0 0-9.924923-9.924923H275.849846a9.924923 9.924923 0 0 0-9.964308 9.924923v206.690461z m-483.682462 177.23077a29.577846 29.577846 0 0 1-29.577846-29.577847 29.577846 29.577846 0 0 1 29.577846-29.538461h59.076923a29.538462 29.538462 0 0 1 29.538462 29.538461 29.538462 29.538462 0 0 1-29.538462 29.577847z" p-id="2945"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
2
src/icons/svg/login.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?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"><svg t="1657867308126" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1964" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
|
||||||
|
</style></defs><path d="M517.77536 972.8c133.98016-30.19776 211.70176-70.42048 301.2608-156.3136 29.32736-28.11904 174.04928-63.68256 190.4128-100.83328 23.72608-53.8624-58.2144-115.72224-58.2144-178.40128 0-240.54784-194.06848-435.5584-433.4592-435.5584-239.38048 0-433.44896 195.01056-433.44896 435.5584 0 68.21888-86.13888 124.14976-58.3168 181.62688 15.28832 31.56992 164.1472 73.216 189.51168 97.60768C305.08032 902.68672 383.55968 942.60224 517.77536 972.8z" fill="#FFD797" p-id="1965"></path><path d="M908.77952 65.5872c-0.88064 1.40288 79.0528 276.7872 32.68608 379.32032a439.0912 439.0912 0 0 1 9.76896 92.34432c0 62.6688 81.94048 124.54912 58.2144 178.40128-1.71008 3.8912-4.88448 7.74144-9.216 11.55072-146.59584-39.44448-297.6768-4.31104-453.25312 105.41056l-5.64224 4.00384H494.592C336.24064 723.2 182.55872 686.92992 33.536 727.78752c-3.54304-3.0208-6.11328-5.9904-7.5264-8.9088-27.82208-57.47712 58.3168-113.408 58.3168-181.62688 0-27.4944 2.53952-54.39488 7.38304-80.47616-59.62752-90.97216 27.136-389.7344 26.22464-391.18848 81.39776-14.41792 159.06816 8.76544 233.03168 69.5296a430.40768 430.40768 0 0 1 166.8096-33.42336 430.44864 430.44864 0 0 1 160.94208 31.01696C751.77984 73.728 828.4672 51.36384 908.77952 65.5872z" fill="#FF6F24" p-id="1966"></path><path d="M283.1872 315.51488c31.10912-104.9088-23.97184-186.24512-165.25312-244.0192 1.024 1.65888-77.7216 340.93056 28.89728 383.11936-3.51232 2.92864 41.94304-43.42784 136.35584-139.10016z m461.48608 0c-31.10912-104.9088 23.97184-186.24512 165.24288-244.0192-1.024 1.65888 77.7216 340.93056-28.89728 383.11936 3.52256 2.92864-41.9328-43.42784-136.3456-139.10016z" fill="#922101" opacity=".574" p-id="1967"></path><path d="M647.69024 629.00224c-0.21504-60.29312 44.56448-83.94752 134.3488-70.95296-2.78528 3.072 6.78912 44.93312-40.51968 69.15072-11.264 5.76512-42.53696 6.36928-93.82912 1.80224z m-251.46368 0c0.22528-60.29312-44.55424-83.94752-134.33856-70.95296 2.78528 3.072-6.79936 44.93312 40.50944 69.15072 11.264 5.76512 42.53696 6.36928 93.82912 1.80224z" fill="#350000" p-id="1968"></path><path d="M743.10656 565.72928l0.04096 0.1536c0.78848 3.42016 1.20832 6.99392 1.20832 10.6496 0 23.4496-17.14176 42.82368-39.424 46.00832-3.42016 0.1536-7.2192 0.21504-11.39712 0.18432a45.93664 45.93664 0 0 1-36.7104-26.61376c10.25024-24.832 39.0144-34.95936 86.28224-30.38208z m-459.84768 0l-0.04096 0.1536a47.13472 47.13472 0 0 0-1.20832 10.6496c0 23.4496 17.14176 42.82368 39.424 46.00832 3.40992 0.1536 7.2192 0.21504 11.39712 0.18432a45.93664 45.93664 0 0 0 36.7104-26.61376c-10.26048-24.832-39.0144-34.95936-86.28224-30.38208z" fill="#923320" p-id="1969"></path><path d="M328.6528 574.72c-4.12672 10.24-6.25664 17.43872-6.38976 21.58592-0.23552 6.89152 1.8944 12.5952 6.38976 17.1008 0.768 0.54272 6.44096-5.30432 6.144-17.87904-0.1024-3.72736-2.1504-10.6496-6.144-20.80768z m372.72576 0c-4.12672 10.24-6.2464 17.43872-6.38976 21.58592-0.22528 6.89152 1.90464 12.5952 6.38976 17.1008 0.77824 0.54272 6.44096-5.30432 6.144-17.87904-0.09216-3.72736-2.14016-10.6496-6.144-20.80768z" fill="#FFFFFF" opacity=".632" p-id="1970"></path><path d="M520.42752 863.8464c37.24288 0 67.4304-27.81184 67.4304-62.1056 0-34.304-134.8608-34.304-134.8608 0s30.19776 62.1056 67.4304 62.1056z" fill="#040C12" p-id="1971"></path><path d="M520.15104 152.02304c8.86784 146.97472 40.57088 238.83776 95.10912 275.57888l2.19136 1.4336-0.24576 0.07168c-6.42048 2.53952-71.46496 73.5744-96.80896 138.2912-0.0512 0.08192-0.09216 0-0.12288-0.26624-0.04096 0.256-0.08192 0.34816-0.12288 0.26624-25.35424-64.7168-90.38848-135.75168-96.8192-138.2912l-0.24576-0.07168 2.2016-1.4336c53.71904-36.1984 85.1968-125.87008 94.45376-269.03552l0.4096-6.5536z" fill="#C74D22" p-id="1972"></path><path d="M735.15008 721.8688c49.55136 0 89.72288-17.17248 89.72288-38.3488s-40.17152-38.3488-89.72288-38.3488c-49.5616 0-89.72288 17.17248-89.72288 38.3488s40.17152 38.3488 89.72288 38.3488z m-443.89376 0c49.5616 0 89.72288-17.17248 89.72288-38.3488s-40.17152-38.3488-89.72288-38.3488-89.72288 17.17248-89.72288 38.3488 40.17152 38.3488 89.72288 38.3488z" fill="#C53028" fill-opacity=".3" p-id="1973"></path></svg>
|
After Width: | Height: | Size: 4.7 KiB |
1
src/icons/svg/project.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972602532" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8591" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M287 62h530.35714248C862.35714248 62 897.71428584 97.35714248 897.71428584 142.35714248V447.71428584H158.42857168V190.57142832c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#B5F5EC" p-id="8592"></path><path d="M647 62H238.78571416C193.78571416 62 158.42857168 97.35714248 158.42857168 142.35714248v739.28571504C158.42857168 926.64285752 193.78571416 962 238.78571416 962h575.35714336c45 0 80.35714248-35.35714248 80.35714248-80.35714248V309.5L647 62z" fill="#36CFC9" p-id="8593"></path><path d="M650.21428584 62v186.42857168c0 32.14285752 25.71428584 61.07142832 61.07142832 61.07142832H897.71428584L650.21428584 62z" fill="#08979C" p-id="8594"></path><path d="M335.21428584 415.57142832m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#B5F5EC" p-id="8595"></path><path d="M512 383.42857168h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285664s-12.85714248 32.14285752-32.14285752 32.14285752h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285752s12.85714248-32.14285752 32.14285752-32.14285664zM512 544.14285752h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285664s-12.85714248 32.14285752-32.14285752 32.14285752h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285752s12.85714248-32.14285752 32.14285752-32.14285664zM512 704.85714248h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752s-12.85714248 32.14285752-32.14285752 32.14285752h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285752s12.85714248-32.14285752 32.14285752-32.14285752z" fill="#B5F5EC" p-id="8596"></path><path d="M335.21428584 576.28571416m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#B5F5EC" p-id="8597"></path><path d="M335.21428584 737m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#B5F5EC" p-id="8598"></path></svg>
|
After Width: | Height: | Size: 2.4 KiB |
1
src/icons/svg/script.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972646504" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11330" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M868.836693 520.02816V173.622613h-148.241066V28.603733H127.665493c-27.293013 0-49.411413 21.64736-49.411413 48.339627v870.11328c0 26.70592 22.1184 48.346453 49.411413 48.346453h33.355094l485.915306-475.374933h221.9008zM178.121387 745.424213c-20.473173 0.013653-37.0688-16.19968-37.082454-36.22912-0.013653-20.015787 16.56832-36.27008 37.034667-36.276906h0.047787c20.45952 0.013653 37.04832 16.267947 37.034666 36.276906s-16.5888 36.215467-37.034666 36.22912z m0-233.424213c-20.473173 0.013653-37.0688-16.213333-37.082454-36.235947s16.56832-36.263253 37.034667-36.276906h0.047787c20.45952 0.02048 37.04832 16.26112 37.034666 36.276906-0.013653 20.015787-16.5888 36.22912-37.034666 36.235947z m0-233.424213c-20.473173 0-37.055147-16.233813-37.055147-36.256427s16.5888-36.256427 37.055147-36.256427c20.45952 0 37.061973 16.233813 37.061973 36.256427s-16.602453 36.256427-37.061973 36.256427z" fill="#F27151" p-id="11331"></path><path d="M646.935893 520.02816l-485.915306 475.374933h658.404693c27.293013 0 49.411413-21.640533 49.411413-48.346453V520.02816H646.935893z" fill="#D56649" p-id="11332"></path><path d="M720.602453 173.622613h148.241067L720.602453 28.603733v145.01888z" fill="#F4C2BC" p-id="11333"></path><path d="M868.836693 318.641493V173.622613h-148.241066l148.241066 145.01888z" fill="#D66648" p-id="11334"></path><path d="M275.92704 253.699413h494.114133v48.339627h-494.114133v-48.339627z m0 152.55552h494.114133v48.339627h-494.114133V406.254933z m0 152.582827v48.346453h281.914027l49.411413-48.346453H275.92704zM275.92704 711.400107v48.3328h125.97248l49.411413-48.3328H275.92704z" fill="#C9C5DD" p-id="11335"></path><path d="M914.814293 674.829653c27.450027-39.478613 27.450027-134.22592 27.450027-134.22592H667.736747s-7.5776 94.76096 19.838293 134.22592c24.08448 34.6112 61.016747 54.59968 61.016747 80.909654v0.34816c0 26.344107-36.94592 44.455253-61.016747 79.0528-27.450027 39.478613-19.838293 131.679573-19.838293 131.679573h274.527573s0-92.03712-27.450027-131.52256c-24.08448-34.6112-68.642133-52.57216-68.642133-78.895787 0-26.29632 44.557653-46.96064 68.642133-81.57184z" fill="#FFFFFF" p-id="11336"></path><path d="M791.258453 540.596907h-96.085333s0 55.296 13.748907 94.747306c17.885867 51.452587 82.343253 67.106133 82.343253 119.74656 0 52.61312 0 171.677013 13.714773 171.677014 13.735253 0 13.735253-118.0672 13.735254-170.693974 0-52.61312 64.477867-69.440853 82.35008-120.907093 13.735253-39.46496 13.735253-94.59712 13.735253-94.59712h-123.528533v0.027307z" fill="#F9C82D" p-id="11337"></path><path d="M940.48256 943.158613H668.719787c-13.63968 0-24.705707 10.601813-24.705707 23.681707s11.066027 23.681707 24.705707 23.681707h271.762773c13.653333 0 24.705707-10.601813 24.705707-23.681707s-11.052373-23.681707-24.705707-23.681707z m0-426.236586H668.719787c-9.09312 0.08192-17.38752 4.983467-21.531307 12.731733h314.866347c-4.164267-7.76192-12.465493-12.670293-21.572267-12.731733z m-293.29408 12.731733a22.309547 22.309547 0 0 0-3.1744 10.949973c0 13.079893 11.066027 23.681707 24.705707 23.681707h271.762773c13.653333 0 24.705707-10.601813 24.705707-23.681707a22.65088 22.65088 0 0 0-3.13344-10.949973H647.18848z" fill="#3BAFDA" p-id="11338"></path></svg>
|
After Width: | Height: | Size: 3.5 KiB |
1
src/icons/svg/task.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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"><svg t="1632972631189" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10965" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M190.57142832 174.5h642.85714336c70.71428584 0 128.57142832 57.85714248 128.57142832 128.57142832V865.57142832c0 45-35.35714248 80.35714248-80.35714248 80.35714336H190.57142832c-70.71428584 0-128.57142832-57.85714248-128.57142832-128.5714292v-514.28571416c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#FFBB96" p-id="10966"></path><path d="M190.57142832 174.5h642.85714336c70.71428584 0 128.57142832 57.85714248 128.57142832 128.57142832V704.85714248l-128.57142832 115.71428584-3.21428584 3.21428584-128.57142832 122.14285752H190.57142832c-70.71428584 0-128.57142832-57.85714248-128.57142832-128.5714292v-514.28571416c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#CF5A1A" p-id="10967"></path><path d="M190.57142832 174.5h642.85714336c70.71428584 0 128.57142832 57.85714248 128.57142832 128.57142832V704.85714248h-176.78571416c-45 0-80.35714248 35.35714248-80.35714336 80.35714336v160.71428584H190.57142832c-70.71428584 0-128.57142832-57.85714248-128.57142832-128.5714292v-514.28571416c0-70.71428584 57.85714248-128.57142832 128.57142832-128.57142832z" fill="#FF7A45" p-id="10968"></path><path d="M351.28571416 78.07142832c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752v147.85714248c0 19.28571416-12.85714248 32.14285752-32.14285752 32.14285752s-32.14285752-12.85714248-32.14285664-32.14285752V110.21428584c0-19.28571416 12.85714248-32.14285752 32.14285664-32.14285752zM672.71428584 78.07142832c19.28571416 0 32.14285752 12.85714248 32.14285664 32.14285752v147.85714248c0 19.28571416-12.85714248 32.14285752-32.14285664 32.14285752s-32.14285752-12.85714248-32.14285752-32.14285752V110.21428584c0-19.28571416 12.85714248-32.14285752 32.14285752-32.14285752z" fill="#FFBB96" p-id="10969"></path><path d="M335.21428584 495.92857168m-48.21428584-1e-8a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#FFBB96" p-id="10970"></path><path d="M512 463.78571416h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752s-12.85714248 32.14285752-32.14285752 32.14285665h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285665s12.85714248-32.14285752 32.14285752-32.14285752zM512 624.5h192.85714248c19.28571416 0 32.14285752 12.85714248 32.14285752 32.14285752s-12.85714248 32.14285752-32.14285752 32.14285664h-192.85714248c-19.28571416 0-32.14285752-12.85714248-32.14285752-32.14285664s12.85714248-32.14285752 32.14285752-32.14285752z" fill="#FFBB96" p-id="10971"></path><path d="M335.21428584 656.64285752m-48.21428584 0a48.21428584 48.21428584 0 1 0 96.42857168 0 48.21428584 48.21428584 0 1 0-96.42857168 0Z" fill="#FFBB96" p-id="10972"></path></svg>
|
After Width: | Height: | Size: 3.0 KiB |
22
src/icons/svgo.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# replace default config
|
||||||
|
|
||||||
|
# multipass: true
|
||||||
|
# full: true
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
|
||||||
|
# - name
|
||||||
|
#
|
||||||
|
# or:
|
||||||
|
# - name: false
|
||||||
|
# - name: true
|
||||||
|
#
|
||||||
|
# or:
|
||||||
|
# - name:
|
||||||
|
# param1: 1
|
||||||
|
# param2: 2
|
||||||
|
|
||||||
|
- removeAttrs:
|
||||||
|
attrs:
|
||||||
|
- 'fill'
|
||||||
|
- 'fill-rule'
|
9
src/interface/User.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface User {
|
||||||
|
id : number;
|
||||||
|
name : string;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StatusEnum {
|
||||||
|
DISABLED,
|
||||||
|
ENABLED
|
||||||
|
}
|
162
src/metamask/ChainManager.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import store from "@/views/home/store/index";
|
||||||
|
import Web3 from 'web3'
|
||||||
|
import { Message } from 'element-ui';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {Http_getNonce,Http_login} from "@/utils/login-request"
|
||||||
|
// import Cookie from "@u/cookie";
|
||||||
|
interface Window {
|
||||||
|
ethereum: any
|
||||||
|
web3: any
|
||||||
|
celo: any
|
||||||
|
}
|
||||||
|
declare let window: Window
|
||||||
|
|
||||||
|
export default class ChainManager {
|
||||||
|
public provider:any
|
||||||
|
public web3:Web3
|
||||||
|
public chainId:number
|
||||||
|
public account:string
|
||||||
|
public nonce:string
|
||||||
|
|
||||||
|
private async login( account, chainId, nonce ) {
|
||||||
|
nonce += ''
|
||||||
|
// console.log(nonce);return
|
||||||
|
const tips = 'This signature is only used for verify your account'
|
||||||
|
const signMsg = {
|
||||||
|
tips,
|
||||||
|
nonce
|
||||||
|
}
|
||||||
|
const EIP721_DOMAIN_DATA = [
|
||||||
|
{ name: 'name', type: 'string' },
|
||||||
|
{ name: 'version', type: 'string' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const signObj = {
|
||||||
|
types: {
|
||||||
|
EIP712Domain: EIP721_DOMAIN_DATA,
|
||||||
|
set: [
|
||||||
|
{ name: 'tips', type: 'string' },
|
||||||
|
{ name: 'nonce', type: 'string' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
primaryType: 'set',
|
||||||
|
domain: {
|
||||||
|
name: 'Auth',
|
||||||
|
version: '1'
|
||||||
|
},
|
||||||
|
message: signMsg
|
||||||
|
}
|
||||||
|
const signature = await this.signData(signObj, account)
|
||||||
|
const authData = {
|
||||||
|
account,
|
||||||
|
nonce,
|
||||||
|
signature,
|
||||||
|
tips,
|
||||||
|
net_id: chainId
|
||||||
|
}
|
||||||
|
// console.log('login data: ', authData)
|
||||||
|
const res = await Http_login(authData)
|
||||||
|
console.log(res)
|
||||||
|
// if (!res.errcode && res.token) {
|
||||||
|
// store.commit('set_token',res.token)
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
public async checkNance() {
|
||||||
|
try {
|
||||||
|
let nonce = store.getters.nonce
|
||||||
|
// console.log(store.getters);return
|
||||||
|
if (!nonce) {
|
||||||
|
let params = {account:this.account, net_id:this.chainId}
|
||||||
|
const res = await Http_getNonce(params);
|
||||||
|
// store.commit('set_nonce',res.nonce)
|
||||||
|
// this.nonce = res.nonce
|
||||||
|
}
|
||||||
|
// console.log(this.account,this.chainId,this.nonce);return
|
||||||
|
this.login(this.account,this.chainId,this.nonce)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
Promise.reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async connect(){
|
||||||
|
if (!this.hasMetamask()) {
|
||||||
|
Message({
|
||||||
|
message: '请先安装MetaMask插件',
|
||||||
|
type: 'error',
|
||||||
|
duration: 5 * 1000
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.provider = await this.connectMetaMask()
|
||||||
|
if (!this.provider) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(this.provider);return
|
||||||
|
this.web3 = new Web3(this.provider)
|
||||||
|
this.chainId = await this.web3.eth.getChainId()
|
||||||
|
const accounts = await this.web3.eth.getAccounts()
|
||||||
|
if (accounts && accounts.length > 0) {
|
||||||
|
this.account =accounts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async connectMetaMask() {
|
||||||
|
let provider = window.ethereum
|
||||||
|
try {
|
||||||
|
await provider.request({ method: 'eth_requestAccounts' })
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === -32002) {
|
||||||
|
throw new Error('MeatMask not login, Open MeatMask and login first')
|
||||||
|
} else {
|
||||||
|
throw new Error('User Rejected')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
private verifyInjectedProvider(check) {
|
||||||
|
return window.ethereum
|
||||||
|
? window.ethereum[check]
|
||||||
|
: window.web3 &&
|
||||||
|
window.web3.currentProvider &&
|
||||||
|
window.web3.currentProvider[check]
|
||||||
|
}
|
||||||
|
private hasMetamask() {
|
||||||
|
if (typeof window.ethereum !== 'undefined') {
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async signData(signObj, signer) {
|
||||||
|
const msgParams = JSON.stringify(signObj)
|
||||||
|
const from = signer
|
||||||
|
// console.log('clicked, sending personal sign req', 'from', from, msgParams)
|
||||||
|
const params = [from, msgParams]
|
||||||
|
const result = await this.sendCmd({
|
||||||
|
method: 'eth_signTypedData_v4',
|
||||||
|
params,
|
||||||
|
from
|
||||||
|
})
|
||||||
|
console.log(result)
|
||||||
|
// return result.result
|
||||||
|
}
|
||||||
|
private async sendCmd({ method, params, from }) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
this.web3.currentProvider.sendAsync({
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
from
|
||||||
|
}, async function(err, result) {
|
||||||
|
if (err) {
|
||||||
|
reject && reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve && resolve(result)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
3
src/plugins/CKEditor.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import CKEditor from 'ckeditor4-vue'
|
||||||
|
Vue.use(CKEditor);
|
5
src/plugins/element.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'element-ui/lib/theme-chalk/index.css';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import ElementUI from 'element-ui';
|
||||||
|
|
||||||
|
Vue.use(ElementUI);
|
5
src/plugins/iview.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import ViewUI from 'view-design'
|
||||||
|
|
||||||
|
Vue.use(ViewUI)
|
||||||
|
import 'view-design/dist/styles/iview.css'
|
4
src/plugins/vant.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vant from "vant";
|
||||||
|
Vue.use(Vant)
|
||||||
|
import 'vant/lib/index.css';
|
1
src/router/_import_production.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export function _import( file: string) { return import(/* webpackChunkName: "about" */ '../views/About.vue')}
|
13
src/shims-tsx.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import Vue, { VNode } from 'vue'
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace JSX {
|
||||||
|
// tslint:disable no-empty-interface
|
||||||
|
interface Element extends VNode {}
|
||||||
|
// tslint:disable no-empty-interface
|
||||||
|
interface ElementClass extends Vue {}
|
||||||
|
interface IntrinsicElements {
|
||||||
|
[elem: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
src/shims-vue.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue
|
||||||
|
}
|
7
src/utils/Events.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
export default class Events {
|
||||||
|
static readonly ON_PAGE_CHANGE : string = "on-page-change";
|
||||||
|
static readonly ON_PAGE_SIZE_CHANGE : string = "on-page-size-change";
|
||||||
|
static readonly ON_SELECTION_CHANGE : string = 'on-selection-change';
|
||||||
|
static readonly ON_REFRESH_USER: string = 'on-refresh-user'
|
||||||
|
}
|
190
src/utils/Http.ts
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import axios, {AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, Method} from "axios";
|
||||||
|
import {Store} from "vuex";
|
||||||
|
import {VueRouter} from "vue-router/types/router";
|
||||||
|
import {ServerRetEnum} from "@/views/admin/types/Types";
|
||||||
|
|
||||||
|
const sprintf = require('sprintf-js')
|
||||||
|
|
||||||
|
let apiHost = process.env.NODE_ENV !== 'production' ? process.env.VUE_APP_API_HOST : document.location.host;
|
||||||
|
let scheme = document.location.protocol;
|
||||||
|
|
||||||
|
|
||||||
|
class Http {
|
||||||
|
private readonly _handler : AxiosInstance;
|
||||||
|
static _instance : Http;
|
||||||
|
private _store? : Store<any>;
|
||||||
|
private _router : VueRouter | any;
|
||||||
|
private _vue : Vue | any;
|
||||||
|
private _baseUri : string = '';
|
||||||
|
|
||||||
|
static instance() : Http {
|
||||||
|
if (!this._instance) {
|
||||||
|
this._instance = new Http();
|
||||||
|
}
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
set store(store : Store<any>) {
|
||||||
|
this._store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
set router(router : VueRouter) {
|
||||||
|
this._router = router;
|
||||||
|
}
|
||||||
|
|
||||||
|
set vue(vue : Vue) {
|
||||||
|
this._vue = vue;
|
||||||
|
}
|
||||||
|
|
||||||
|
get handler () : AxiosInstance {
|
||||||
|
return this._handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
get uri() {
|
||||||
|
// console.log(this._handler.defaults, 'get_uri');
|
||||||
|
return this._handler.defaults.baseURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
set baseUri(uri : string) {
|
||||||
|
this._baseUri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseUri () : string {
|
||||||
|
return this._baseUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._handler = axios.create({
|
||||||
|
baseURL : scheme + "//" + apiHost,
|
||||||
|
timeout : 50000,
|
||||||
|
});
|
||||||
|
this._handler.interceptors.response.use((response : AxiosResponse) => {
|
||||||
|
// console.log(response, '基本请求结果')
|
||||||
|
if (response.status == 200) {
|
||||||
|
return response.data;
|
||||||
|
} else {
|
||||||
|
// console.log(response, '未知错误')
|
||||||
|
}
|
||||||
|
}, (error : AxiosError) => {
|
||||||
|
let response = error.response;
|
||||||
|
if (response?.status === 401) {
|
||||||
|
this._router.replace("/login");
|
||||||
|
} else {
|
||||||
|
console.error('response error', error.response);
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
})
|
||||||
|
this._handler.interceptors.request.use((config : AxiosRequestConfig) => {
|
||||||
|
config.headers["X-Requested-With"] = "XMLHttpRequest";
|
||||||
|
if (this._store) {
|
||||||
|
config.headers["Authorization"] = "Bearer " + this._store.getters.token;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public sprintf(...params) : string {
|
||||||
|
return sprintf.sprintf(...params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface> {
|
||||||
|
return this.request('GET', url, params, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public post(url : string, data? : object | any, ...args : any[]) : Promise<ResponseInterface> {
|
||||||
|
return this.request('POST', url, data, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public put(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface> {
|
||||||
|
return this.request('PUT', url, params, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface> {
|
||||||
|
return this.request('DELETE', url, params, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public request(method : Method, url : string, data? : object | any, headers? : any) : Promise<ResponseInterface> {
|
||||||
|
url = this._baseUri + url;
|
||||||
|
let params : AxiosRequestConfig = {
|
||||||
|
url, method, headers
|
||||||
|
}
|
||||||
|
if (method.toLocaleUpperCase() === 'GET') {
|
||||||
|
params.params = data;
|
||||||
|
} else {
|
||||||
|
params.data = data;
|
||||||
|
}
|
||||||
|
return new Promise<ResponseInterface>((resolve, reject) => {
|
||||||
|
this._handler.request(params).then((res : any) => {
|
||||||
|
if (res.code === ServerRetEnum.SUCCESS) {
|
||||||
|
resolve(res);
|
||||||
|
} else if(res.code === ServerRetEnum.NO_PERMISSION) {
|
||||||
|
if(this._vue.$Message){
|
||||||
|
this._vue.$Message.error(res.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(res);
|
||||||
|
reject(res.message);
|
||||||
|
}
|
||||||
|
}).catch((err : any) => {
|
||||||
|
reject(err);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public download(method : Method, url: string) : Promise<AxiosResponse> {
|
||||||
|
this._handler.interceptors.response.use((response : AxiosResponse) => {
|
||||||
|
return Promise.resolve(response)
|
||||||
|
});
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
url = this._baseUri + url;
|
||||||
|
let params : AxiosRequestConfig = {
|
||||||
|
url, method, responseType: "blob", timeout: 600e3
|
||||||
|
}
|
||||||
|
this._handler.request(params).then((res : any) => {
|
||||||
|
resolve(res);
|
||||||
|
}).catch((reason) => {
|
||||||
|
console.error(reason);
|
||||||
|
reject(reason);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance : Http = Http.instance();
|
||||||
|
export default instance;
|
||||||
|
export const get = instance.get;
|
||||||
|
export const post = instance.post;
|
||||||
|
|
||||||
|
|
||||||
|
export interface ResponseInterface {
|
||||||
|
data? : Array<any> | object | object[] | any,
|
||||||
|
code : ServerRetEnum,
|
||||||
|
message : string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResponseErrorInterface {
|
||||||
|
result : number,
|
||||||
|
message : string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RequestInterface {
|
||||||
|
store : Store<any>;
|
||||||
|
router : VueRouter;
|
||||||
|
handler : AxiosInstance;
|
||||||
|
baseUri : string;
|
||||||
|
|
||||||
|
instance();
|
||||||
|
|
||||||
|
|
||||||
|
get(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface>;
|
||||||
|
|
||||||
|
post(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface>;
|
||||||
|
|
||||||
|
put(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface>;
|
||||||
|
|
||||||
|
delete(url : string, params? : object | any, ...args : any[]) : Promise<ResponseInterface>;
|
||||||
|
|
||||||
|
request(method : Method, url : string, data? : object | any, headers? : any) : Promise<ResponseInterface>;
|
||||||
|
|
||||||
|
download(method : Method, url : string) : Promise<AxiosResponse>
|
||||||
|
}
|
21
src/utils/Parnet.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import { RawLocation } from "vue-router/types/router";
|
||||||
|
import { Route } from "vue-router";
|
||||||
|
|
||||||
|
export default class Parent extends Vue {
|
||||||
|
protected _push(location : RawLocation, success_cb? : Function, error_cb? : Function) {
|
||||||
|
this.$router.push(location).catch(err => {
|
||||||
|
if (error_cb) {
|
||||||
|
error_cb.apply(this, err);
|
||||||
|
}
|
||||||
|
}).then((value : Route) => {
|
||||||
|
if (success_cb) {
|
||||||
|
success_cb.apply(this, value);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public goPage(name : string, success_cb? : Function, error_cb? : Function) {
|
||||||
|
this._push({name}, success_cb, error_cb);
|
||||||
|
}
|
||||||
|
}
|
110
src/utils/Url.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* 前台地址
|
||||||
|
*/
|
||||||
|
export default class Url {
|
||||||
|
static readonly WORK_LOGIN : string = 'work/login'
|
||||||
|
static readonly LOGIN : string = "login";
|
||||||
|
static readonly LOGOUT : string = "logout";
|
||||||
|
// TODO 菜单
|
||||||
|
static readonly MENUS : string = "menu";
|
||||||
|
static readonly DELETE_MENU : string = "menu/%d";
|
||||||
|
static readonly SHOW_MENU : string = "menu/%d";
|
||||||
|
static readonly UPDATE_MENU : string = "menu/%d";
|
||||||
|
// TODO 用户
|
||||||
|
static readonly USERS : string = "user";
|
||||||
|
static readonly DISABLE_USER : string = 'user/%d';
|
||||||
|
static readonly ENABLE_USER : string = "user/start/%d";
|
||||||
|
static readonly SHOW_USER : string = 'user/%d';
|
||||||
|
static readonly UPDATE_USER : string = 'user/%d';
|
||||||
|
static readonly UPDATE_USERNAME : string = 'user/update_name/%d';
|
||||||
|
|
||||||
|
|
||||||
|
static readonly MY_MENUS : string = "my_menu";
|
||||||
|
static readonly MY_POWER : string = "my_power";
|
||||||
|
static readonly MY_PROJECT : string = "my_project";
|
||||||
|
static readonly UPDATE_MY_NAME : string = "update/my/name";
|
||||||
|
|
||||||
|
|
||||||
|
// TODO 权限
|
||||||
|
static readonly POWER : string = "power";
|
||||||
|
static readonly SHOW_POWER : string = "power/%d";
|
||||||
|
static readonly UPDATE_POWER : string = "power/%d";
|
||||||
|
static readonly DELETE_POWER : string = "power/%d";
|
||||||
|
|
||||||
|
// TODO 权限组
|
||||||
|
static readonly POWER_GROUP : string = "power_group";
|
||||||
|
static readonly SHOW_POWER_GROUP : string = "power_group/%d";
|
||||||
|
static readonly UPDATE_POWER_GROUP : string = "power_group/%d";
|
||||||
|
static readonly DELETE_POWER_GROUP : string = "power_group/%d";
|
||||||
|
|
||||||
|
// TODO 项目
|
||||||
|
static readonly PROJECT : string = 'project';
|
||||||
|
static readonly SHOW_PROJECT : string = "project/%d";
|
||||||
|
static readonly UPDATE_PROJECT : string = "project/%d";
|
||||||
|
static readonly DELETE_PROJECT : string = "project/%d";
|
||||||
|
|
||||||
|
static readonly WATCH_PROJECT : string = "project/watch/%d";
|
||||||
|
static readonly UN_WATCH_PROJECT : string = "project/watch/%d";
|
||||||
|
static readonly SHOW_PROJECT_ITEM : string = "project_item/%d";
|
||||||
|
static readonly DElETE_PROJECT_ITEM : string = "project_item/%d";
|
||||||
|
static readonly DElETE_PROJECT_PRODUCT : string = "project_product/%d";
|
||||||
|
static readonly UPDATE_PROJECT_PRODUCT : string = "project_product/%d";
|
||||||
|
static readonly SHOW_PROJECT_PRODUCT : string = "project_product/%d";
|
||||||
|
static readonly DOWNLOAD_PROJECT_PRODUCT : string = "project_product/download/%d";
|
||||||
|
static readonly SHOW_PRODUCT_Log : string = "show_log/%d";
|
||||||
|
static readonly SHOW_DOWNLOAD_IP : string = "product/download_ip/%d";
|
||||||
|
static readonly DOWNLOAD_IP : string = "download_ip";
|
||||||
|
static readonly DELETE_DOWNLOAD_IP : string = "download_ip/%d";
|
||||||
|
static readonly UPDATE_DOWNLOAD_IP : string = "download_ip/%d";
|
||||||
|
|
||||||
|
|
||||||
|
//TODO 用户分配
|
||||||
|
static readonly ALLOT_MENT : string = 'allot_menu/%d';
|
||||||
|
static readonly ALLOT_POWER : string = 'allot_power/%d';
|
||||||
|
static readonly ALLOT_PROJECT : string = 'allot_project/%d';
|
||||||
|
|
||||||
|
|
||||||
|
//TODO 自动化(设备)
|
||||||
|
static readonly DEVICE : string = 'device';
|
||||||
|
static readonly UPLOAD_IMAGE : string = 'device/upload_pic';
|
||||||
|
static readonly DELETE_DEVICE : string = 'device/%d';
|
||||||
|
static readonly UPDATE_DEVICE : string = 'device/%d';
|
||||||
|
|
||||||
|
//TODO 自动化(脚本)
|
||||||
|
static readonly SCRIPT : string = 'script';
|
||||||
|
static readonly UPLOAD_SCRIPT : string = 'script/upload';
|
||||||
|
static readonly UPDATE_SCRIPT : string = 'script/%d';
|
||||||
|
static readonly DELETE_SCRIPT : string = 'script/%d';
|
||||||
|
static readonly DOWNLOAD_SCRIPT : string = 'script/download/%d';
|
||||||
|
|
||||||
|
//TODO 自动化(脚本集)
|
||||||
|
static readonly SCRIPT_COLLECTION : string = 'collection';
|
||||||
|
static readonly UPDATE_SCRIPT_COLLECTION : string = 'collection/%d';
|
||||||
|
static readonly DELETE_SCRIPT_COLLECTION : string = 'collection/%d';
|
||||||
|
static readonly DOWNLOAD_SCRIPT_COLLECTION : string = 'collection/download/%d';
|
||||||
|
|
||||||
|
//TODO 自动化(任务)
|
||||||
|
static readonly TASK : string = 'task';
|
||||||
|
static readonly UPDATE_TASK : string = 'task/%d';
|
||||||
|
static readonly DELETE_TASK : string = 'task/%d';
|
||||||
|
static readonly TASK_LOG : string = 'task_log';
|
||||||
|
static readonly TASK_DEFAULT_STATUS_CHANGE : string = 'task/set_default/%d'
|
||||||
|
static readonly TASK_REPORT : string = 'task_report/%d'
|
||||||
|
|
||||||
|
//TODO 自动化(数据仓库)
|
||||||
|
static readonly DATA :string = 'data'
|
||||||
|
static readonly DELETE_DATA :string = 'data/%d'
|
||||||
|
|
||||||
|
//TODO 首页
|
||||||
|
static readonly OVERVIEW : string = 'overview'
|
||||||
|
static readonly OVERVIEW_SCRIPT : string = 'overview_scripts'
|
||||||
|
static readonly OVERVIEW_PRODUCT : string = 'overview_products'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台地址
|
||||||
|
*/
|
||||||
|
export class AdminUrl {
|
||||||
|
static readonly LOGIN : string = "login"; // 登陆
|
||||||
|
}
|
52
src/utils/login-request.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import store from "@/views/home/store/index";
|
||||||
|
|
||||||
|
// 创建axios实例,设置配置得默认值
|
||||||
|
// const instance = axios.create({
|
||||||
|
// baseUrl:'https://market.cebg.games', // 这里写接口的http地址,
|
||||||
|
// timeout: 5000, // 设置请求超时的默认值
|
||||||
|
// })
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: 'https://market.cebg.games',
|
||||||
|
timeout: 5000
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置请求拦截器
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
// 判断当前是否有token,有则在请求头上加上token
|
||||||
|
if (store.getters.token) {
|
||||||
|
config.headers.Authorization = "Bearer " + store.getters.token
|
||||||
|
}
|
||||||
|
// console.log(config)
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
// 请求错误进行拦截并返回错误信息
|
||||||
|
// console.log(error)
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// 设置响应拦截
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
response => {
|
||||||
|
const res = response.data
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
export const Http_getNonce = (params) =>
|
||||||
|
instance({
|
||||||
|
url: 'https://market.cebg.games/webapp/index.php?c=Market&a=getNonce',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Http_login = (data) =>
|
||||||
|
instance({
|
||||||
|
url: 'https://market.cebg.games/webapp/index.php?c=Market&a=auth',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
})
|
7
src/views/admin/App.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="less" src="../../assets/style/main.less"></style>
|
||||||
|
|
35
src/views/admin/Common/AdminParent.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import Parent from "@/utils/Parnet";
|
||||||
|
|
||||||
|
export default class AdminParent extends Parent {
|
||||||
|
public success(content? : string, callback? : Function) {
|
||||||
|
this.$Message.success({
|
||||||
|
content : content ? content : "操作成功",
|
||||||
|
onClose : () => {
|
||||||
|
this.$Message.destroy()
|
||||||
|
callback && callback();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public error(content? : string, callback? : Function) {
|
||||||
|
this.$Message.error({
|
||||||
|
content : content ? content : "操作失败",
|
||||||
|
onClose : () => {
|
||||||
|
this.$Message.destroy();
|
||||||
|
callback && callback();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
doDeleteItem(title : string = "", callback : Function) {
|
||||||
|
this.$Modal.confirm({
|
||||||
|
title : "删除",
|
||||||
|
content : title.length > 0 ? title : "确认要删除该数据吗?",
|
||||||
|
loading : true,
|
||||||
|
onOk : () => {
|
||||||
|
this.$Modal.remove();
|
||||||
|
callback.call(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
30
src/views/admin/main.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import App from "./App.vue"
|
||||||
|
import router from './router'
|
||||||
|
import store from './store'
|
||||||
|
import Http, { get, post } from "@/utils/Http";
|
||||||
|
import "../../plugins/iview"
|
||||||
|
import "../../plugins/element";
|
||||||
|
import "@/assets/style/tailwind.css"
|
||||||
|
const sprintf = require('sprintf-js');
|
||||||
|
|
||||||
|
Http.store = store;
|
||||||
|
Http.router = router;
|
||||||
|
Http.baseUri = '/rest/admin/'
|
||||||
|
Vue.prototype.$http = Http;
|
||||||
|
Vue.config.devtools = process.env.NODE_ENV !== 'production';
|
||||||
|
Vue.config.silent = process.env.NODE_ENV === 'production';
|
||||||
|
Vue.config.productionTip = process.env.NODE_ENV !== 'production';
|
||||||
|
Vue.prototype.$isDev = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
|
Vue.prototype.$sprintf = sprintf.sprintf;
|
||||||
|
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render : h => h(App),
|
||||||
|
created() {
|
||||||
|
this.$http.vue = this;
|
||||||
|
}
|
||||||
|
}).$mount('#app')
|
0
src/views/admin/pages/home/home.less
Normal file
17
src/views/admin/pages/home/home.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
|
import Url, {AdminUrl} from "@/utils/Url";
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import AdminParent from "@/views/admin/Common/AdminParent";
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class home extends AdminParent {
|
||||||
|
|
||||||
|
public created() {
|
||||||
|
}
|
||||||
|
}
|
8
src/views/admin/pages/home/home.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
<div class="home">
|
||||||
|
首页
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./home.ts"></script>
|
||||||
|
<style scoped lang="less" src="./home.less"></style>
|
0
src/views/admin/pages/layout/layout.less
Normal file
14
src/views/admin/pages/layout/layout.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import AdminParent from "@/views/admin/Common/AdminParent";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class layout extends AdminParent {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
8
src/views/admin/pages/layout/layout.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout">
|
||||||
|
<router-view></router-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./layout.ts"></script>
|
||||||
|
<style scoped lang="less" src="./layout.less"></style>
|
3
src/views/admin/pages/layout/router.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<router-view></router-view>
|
||||||
|
</template>
|
0
src/views/admin/pages/login/login.less
Normal file
14
src/views/admin/pages/login/login.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
|
import Url from "@/utils/Url";
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import AdminParent from "@/views/admin/Common/AdminParent";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class Login extends AdminParent {
|
||||||
|
|
||||||
|
}
|
9
src/views/admin/pages/login/login.vue
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="justify-center align-middle">
|
||||||
|
登陆
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./login.ts"></script>
|
||||||
|
|
||||||
|
<style scoped lang="less" src="./login.less"></style>
|
33
src/views/admin/router/index.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter, { RouteConfig } from 'vue-router'
|
||||||
|
import Routers from './router'
|
||||||
|
import { LoadingBar } from 'view-design'
|
||||||
|
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
const routes : Array<RouteConfig> = [
|
||||||
|
...Routers
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
base : "/admin/",
|
||||||
|
mode : "history",
|
||||||
|
routes,
|
||||||
|
})
|
||||||
|
|
||||||
|
function setTitle(title : string) : void {
|
||||||
|
window.document.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
LoadingBar.start();
|
||||||
|
let title : string = process.env.VUE_APP_TITLE;
|
||||||
|
setTitle(to.meta.title + '-' + title);
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
LoadingBar.finish();
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
27
src/views/admin/router/router.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { RouteConfig } from "vue-router";
|
||||||
|
import Layout from '../pages/layout/layout.vue'
|
||||||
|
|
||||||
|
const routers : RouteConfig[] = [
|
||||||
|
{
|
||||||
|
path : '/login',
|
||||||
|
name : 'login',
|
||||||
|
component : () => import(/* webpackChunkName: "admin-login" */ '@/views/admin/pages/login/login.vue'),
|
||||||
|
meta : {title : "登陆", isMenu : false}
|
||||||
|
}, {
|
||||||
|
path : "/",
|
||||||
|
name : 'layout',
|
||||||
|
component : Layout,
|
||||||
|
redirect : "/index",
|
||||||
|
meta : {title : "", isMenu : false},
|
||||||
|
children : [{
|
||||||
|
path : "index",
|
||||||
|
name : "index",
|
||||||
|
meta : {title : "首页", isMenu : true, icon : "", path : "/index"},
|
||||||
|
// redirect : "/index/dashboard",
|
||||||
|
component : () => import(/* webpackChunkName: "admin-login" */ '@/views/admin/pages/home/home.vue'),
|
||||||
|
|
||||||
|
},]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default routers
|
37
src/views/admin/store/index.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import user, {UserState} from "@/views/admin/store/user";
|
||||||
|
import createPersistedState from 'vuex-persistedstate'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
interface StateInterface {
|
||||||
|
user : UserState,
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStorage : any = window.localStorage;
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
getters : {
|
||||||
|
token : (state : StateInterface) => state.user.token,
|
||||||
|
},
|
||||||
|
modules : {
|
||||||
|
user,
|
||||||
|
},
|
||||||
|
plugins : [
|
||||||
|
createPersistedState({
|
||||||
|
key : 'admin',
|
||||||
|
storage : {
|
||||||
|
getItem : (key : string) => {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
},
|
||||||
|
setItem : (key : string, value : any) => {
|
||||||
|
return localStorage.setItem(key, value);
|
||||||
|
},
|
||||||
|
removeItem : (key : string) => {
|
||||||
|
return localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
6
src/views/admin/store/types.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default class Types {
|
||||||
|
static readonly SET_USER_INFO : string = 'SET_USER_INFO';
|
||||||
|
static readonly SET_USER_TOKEN : string = 'SET_USER_TOKEN';
|
||||||
|
static readonly SET_LANG : string = 'SET_LANG';
|
||||||
|
static readonly SET_SITE_INFO : string = "SET_SITE_INFO";
|
||||||
|
}
|
41
src/views/admin/store/user.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import {ActionContext} from "vuex";
|
||||||
|
import Http, { ResponseErrorInterface, ResponseInterface } from "@/utils/Http";
|
||||||
|
import {AdminUrl} from "@/utils/Url";
|
||||||
|
import Types from "@/views/admin/store/types";
|
||||||
|
import { User } from "@/interface/User";
|
||||||
|
|
||||||
|
const sprintf = require('sprintf-js');
|
||||||
|
|
||||||
|
export interface UserState {
|
||||||
|
user : User,
|
||||||
|
token : string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name : "user",
|
||||||
|
namespace : true,
|
||||||
|
state : {
|
||||||
|
user : {},
|
||||||
|
token : undefined
|
||||||
|
},
|
||||||
|
actions : {
|
||||||
|
Login(context : ActionContext<UserState, any>, form : any) {
|
||||||
|
return Http.post(AdminUrl.LOGIN, form).then((res : ResponseInterface) => {
|
||||||
|
console.log(res);
|
||||||
|
context.commit(Types.SET_USER_INFO, res.data);
|
||||||
|
context.commit(Types.SET_USER_TOKEN, res.data.access_token);
|
||||||
|
return Promise.resolve(res.data);
|
||||||
|
}).catch((err : ResponseErrorInterface) => {
|
||||||
|
return Promise.reject(err);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations : {
|
||||||
|
[Types.SET_USER_INFO](state : UserState, user : User) {
|
||||||
|
state.user = user;
|
||||||
|
},
|
||||||
|
[Types.SET_USER_TOKEN](state : UserState, token : string) {
|
||||||
|
state.token = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
src/views/admin/types/Types.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export interface MetaInterface {
|
||||||
|
title : string,
|
||||||
|
isMenu : boolean,
|
||||||
|
icon : string,
|
||||||
|
path : string,
|
||||||
|
isHide : boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuInterface {
|
||||||
|
id? : number,
|
||||||
|
title : string,
|
||||||
|
icon : string,
|
||||||
|
name : string,
|
||||||
|
path : string,
|
||||||
|
isHide : boolean,
|
||||||
|
children : MenuInterface[] | any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum ServerRetEnum {
|
||||||
|
SUCCESS,
|
||||||
|
NO_PERMISSION = 1001,
|
||||||
|
NOT_DATA = 1056,
|
||||||
|
}
|
9
src/views/home/App.vue
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./main-app.ts"></script>
|
||||||
|
<style lang="less" src="../../assets/style/main.less"></style>
|
||||||
|
|
28
src/views/home/Common/HomeParent.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import AdminParent from "@/views/admin/Common/AdminParent";
|
||||||
|
import { Route } from "vue-router";
|
||||||
|
import { Location } from "vue-router/types/router";
|
||||||
|
export interface BreadItem {
|
||||||
|
location: Location
|
||||||
|
route: Route
|
||||||
|
href: string
|
||||||
|
normalizedTo: Location
|
||||||
|
resolved: Route
|
||||||
|
name?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default class HomeParent extends AdminParent {
|
||||||
|
|
||||||
|
public loading: boolean = false;
|
||||||
|
public startLoading() : void {
|
||||||
|
this.loading = true;
|
||||||
|
}
|
||||||
|
public stopLoading() : void {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
80
src/views/home/Common/Types.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
export interface MenuInterface {
|
||||||
|
name : string;
|
||||||
|
url : string;
|
||||||
|
pid ?: number;
|
||||||
|
state ?: number;
|
||||||
|
id? : number;
|
||||||
|
children? : MenuInterface[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PowerInterface {
|
||||||
|
id? : number;
|
||||||
|
name : string;
|
||||||
|
pid : number;
|
||||||
|
controller : string;
|
||||||
|
action : string;
|
||||||
|
children? : PowerInterface[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PowerGroupInterface {
|
||||||
|
id? : number;
|
||||||
|
name : string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProjectInterface {
|
||||||
|
name : string;
|
||||||
|
tapd_id : any;
|
||||||
|
id? : number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProjectItemInterface {
|
||||||
|
id? : number;
|
||||||
|
name : string;
|
||||||
|
type : string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProjectProductInterface {
|
||||||
|
id? : number;
|
||||||
|
name : string;
|
||||||
|
commit_message : string;
|
||||||
|
days : number;
|
||||||
|
download_times : number;
|
||||||
|
build_result?: string;
|
||||||
|
state ?: boolean;
|
||||||
|
}
|
||||||
|
export interface ProjectProductLogInterface {
|
||||||
|
id? : number;
|
||||||
|
userName : string;
|
||||||
|
addTime : any;
|
||||||
|
productName : string;
|
||||||
|
days : number;
|
||||||
|
content : string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductIpsInterface {
|
||||||
|
id? : number;
|
||||||
|
project_item_id ?: number;
|
||||||
|
server_ip :string;
|
||||||
|
created_at ?: string;
|
||||||
|
old_ip ?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserInterface {
|
||||||
|
id? : number;
|
||||||
|
username : string;
|
||||||
|
name : string;
|
||||||
|
openid : string;
|
||||||
|
deleted_at : string;
|
||||||
|
old_name ?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ElTreeDataInterface {
|
||||||
|
id : number;
|
||||||
|
label : string;
|
||||||
|
children : ElTreeDataInterface[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EVENT_TYPE {
|
||||||
|
UPDATE_BREAD_ITEM = "UPDATE_BREAD_ITEM",
|
||||||
|
UPDATE_MY_PROJECT = "UPDATE_MY_PROJECT"
|
||||||
|
}
|
45
src/views/home/Common/UiTypes.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
export interface DeviceInterface {
|
||||||
|
id ?: number;
|
||||||
|
name : string;
|
||||||
|
model : number;
|
||||||
|
version : number;
|
||||||
|
serial_number : number;
|
||||||
|
connect_url : string;
|
||||||
|
pic_url : string;
|
||||||
|
is_running ?: number;
|
||||||
|
platform : string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScriptInterface {
|
||||||
|
id ?: number;
|
||||||
|
name : string;
|
||||||
|
project_id : number;
|
||||||
|
project ?: string;
|
||||||
|
user_id ?: number;
|
||||||
|
user ?: string;
|
||||||
|
description : string;
|
||||||
|
path : string;
|
||||||
|
checkFile?:[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CollectionInterface {
|
||||||
|
id ?: number;
|
||||||
|
name : string;
|
||||||
|
project_id : number;
|
||||||
|
user_id ?: number;
|
||||||
|
description : string;
|
||||||
|
script : []
|
||||||
|
list?:object
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TaskInterface {
|
||||||
|
id ?: number;
|
||||||
|
name : string;
|
||||||
|
project_id : number;
|
||||||
|
project ?: string;
|
||||||
|
user_id ?: number;
|
||||||
|
description : string;
|
||||||
|
execute_count ?: number;
|
||||||
|
script_number ?: number;
|
||||||
|
list ?: []
|
||||||
|
}
|
6
src/views/home/cebg.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
interface Window {
|
||||||
|
ethereum: any
|
||||||
|
web3: any
|
||||||
|
celo: any
|
||||||
|
}
|
||||||
|
declare let window: Window
|
178
src/views/home/components/DownLoading.vue
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div class='box'>
|
||||||
|
<div class='dots childDots1'></div>
|
||||||
|
<div class='dots childDots2'></div>
|
||||||
|
<div class='dots childDots3'></div>
|
||||||
|
<div class='dots childDots4'></div>
|
||||||
|
<div class='dots childDots5'></div>
|
||||||
|
<div class='dots childDots6'></div>
|
||||||
|
<div class='dots childDots7'></div>
|
||||||
|
<div class='dots childDots8'></div>
|
||||||
|
<div class='dots childDots9'></div>
|
||||||
|
<div class='dots childDots10'></div>
|
||||||
|
<div class='dots childDots11'></div>
|
||||||
|
<div class='dots childDots12'></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "DownLoading"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #EEE;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
width: 3.7em;
|
||||||
|
height: 2em;
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
/*background-color: red;*/
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .dots {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .dots:before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 15%;
|
||||||
|
height: 15%;
|
||||||
|
background-color: #00BFFF;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: animate 1.2s infinite ease-in-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots2 {
|
||||||
|
transform: rotate(30deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots3 {
|
||||||
|
transform: rotate(60deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots4 {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots5 {
|
||||||
|
transform: rotate(120deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots6 {
|
||||||
|
transform: rotate(150deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots7 {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots8 {
|
||||||
|
transform: rotate(210deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots9 {
|
||||||
|
transform: rotate(240deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots10 {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots11 {
|
||||||
|
transform: rotate(300deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots12 {
|
||||||
|
transform: rotate(330deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots2:before {
|
||||||
|
animation-delay: -1.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots3:before {
|
||||||
|
animation-delay: -1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots4:before {
|
||||||
|
animation-delay: -0.9s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots5:before {
|
||||||
|
animation-delay: -0.8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots6:before {
|
||||||
|
animation-delay: -0.7s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots7:before {
|
||||||
|
animation-delay: -0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots8:before {
|
||||||
|
animation-delay: -0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots9:before {
|
||||||
|
animation-delay: -0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots10:before {
|
||||||
|
animation-delay: -0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots11:before {
|
||||||
|
animation-delay: -0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .childDots12:before {
|
||||||
|
animation-delay: -0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes animate {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animate {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
162
src/views/home/components/PaoMaDeng.vue
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="wrap" class="wrap">
|
||||||
|
<div ref="content" class="content" :class="animationClass" :style="contentStyle" @animationend="onAnimationEnd"
|
||||||
|
@webkitAnimationEnd="onAnimationEnd">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
content: {
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0.5
|
||||||
|
},
|
||||||
|
speed: {
|
||||||
|
type: Number,
|
||||||
|
default: 70
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: String,
|
||||||
|
default: "left"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
wrapWidth: 0,
|
||||||
|
firstRound: true,
|
||||||
|
duration: 0,
|
||||||
|
offsetWidth: 0,
|
||||||
|
animationClass: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
contentStyle() {
|
||||||
|
let styles_row = {
|
||||||
|
paddingLeft: (this.firstRound ? 0 : this.wrapWidth) + 'px',
|
||||||
|
animationDelay: (this.firstRound ? this.delay : 0) + 's',
|
||||||
|
animationDuration: this.duration + 's',
|
||||||
|
};
|
||||||
|
let styles_up = {
|
||||||
|
paddingTop: (this.firstRound ? 0 : this.wrapWidth) + 'px',
|
||||||
|
animationDelay: (this.firstRound ? this.delay : 0) + 's',
|
||||||
|
animationDuration: this.duration + 's',
|
||||||
|
flexFlow:'column nowrap'
|
||||||
|
}
|
||||||
|
return this.direction == 'up' ? styles_up : styles_row;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
content: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.direction == 'left') {
|
||||||
|
this.onLeft();
|
||||||
|
} else if (this.direction == 'up') {
|
||||||
|
this.onUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onLeft() {
|
||||||
|
const {
|
||||||
|
wrap,
|
||||||
|
content
|
||||||
|
} = this.$refs;
|
||||||
|
const wrapWidth = wrap.getBoundingClientRect().width;
|
||||||
|
const offsetWidth = content.getBoundingClientRect().width;
|
||||||
|
this.wrapWidth = wrapWidth;
|
||||||
|
this.offsetWidth = offsetWidth;
|
||||||
|
this.duration = offsetWidth / this.speed;
|
||||||
|
this.animationClass = 'animate';
|
||||||
|
},
|
||||||
|
onUp() {
|
||||||
|
const {
|
||||||
|
wrap,
|
||||||
|
content
|
||||||
|
} = this.$refs;
|
||||||
|
const wrapWidth = wrap.getBoundingClientRect().height;
|
||||||
|
const offsetWidth = content.getBoundingClientRect().height;
|
||||||
|
this.wrapWidth = wrapWidth;
|
||||||
|
this.offsetWidth = offsetWidth;
|
||||||
|
this.duration = offsetWidth / this.speed;
|
||||||
|
this.animationClass = 'animate-up';
|
||||||
|
},
|
||||||
|
onAnimationEnd() {
|
||||||
|
this.firstRound = false
|
||||||
|
this.duration = (this.offsetWidth + this.wrapWidth) / this.speed;
|
||||||
|
this.animationClass = this.direction == 'left' ? "animate-infinite" : "animate-infinite-up";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
.wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap .content {
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate {
|
||||||
|
animation: paomadeng linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-infinite {
|
||||||
|
animation: paomadeng-infinite linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-up {
|
||||||
|
animation: paomadeng-up linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-infinite-up {
|
||||||
|
animation: paomadeng-infinite-up linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes paomadeng {
|
||||||
|
to {
|
||||||
|
transform: translate3d(-100%, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes paomadeng-infinite {
|
||||||
|
to {
|
||||||
|
transform: translate3d(-100%, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes paomadeng-up {
|
||||||
|
to {
|
||||||
|
transform: translate3d(0, -100%, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes paomadeng-infinite-up {
|
||||||
|
to {
|
||||||
|
transform: translate3d(0, -100%, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
86
src/views/home/components/phoneCard.less
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
.device-item {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 220px;
|
||||||
|
padding: 5px 0;
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.top {
|
||||||
|
overflow: hidden;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding: 5px 10px;
|
||||||
|
display: inline-block;
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
.icon{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
float: left;
|
||||||
|
//margin-top: 3px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.button {
|
||||||
|
text-align: right;
|
||||||
|
//margin-left: 40px;
|
||||||
|
float: right;
|
||||||
|
// margin-top: -40px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.link{
|
||||||
|
font-size: 16px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.status-color1{
|
||||||
|
color: #eb4e3d;
|
||||||
|
}
|
||||||
|
.status-color2{
|
||||||
|
color: #2d8cf0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.div-inline{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.left {
|
||||||
|
float: left;
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 20%;
|
||||||
|
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-family: "PingFang SC", "Helvetica Neue", Helvetica, "Hiragino Sans GB", STHeitiSC-Light, "Microsoft YaHei", "微软雅黑", Arial, sans-serif; width: 100%;
|
||||||
|
// height: 66px;
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
// padding-left: 30px;
|
||||||
|
// margin-bottom: 30px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
// line-height: 33px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device-info {
|
||||||
|
float: left;
|
||||||
|
width: 65%;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
white-space:nowrap;
|
||||||
|
overflow:hidden;
|
||||||
|
text-overflow:ellipsis;
|
||||||
|
word-wrap:break-word;
|
||||||
|
word-break:break-all;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
40
src/views/home/components/phoneCard.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import HomeParent from "@/views/home/Common/HomeParent";
|
||||||
|
import {Component, Prop, Vue} from "vue-property-decorator";
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components : {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class phoneCard extends Vue {
|
||||||
|
name:string = 'phoneCard'
|
||||||
|
|
||||||
|
@Prop({type : Array, default : () => []})
|
||||||
|
dataList : Array<any>;
|
||||||
|
|
||||||
|
public edit(e) {
|
||||||
|
if (e.is_running == 1) {
|
||||||
|
this.$Message.error({
|
||||||
|
content:'设备正在运行中,无法编辑'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$emit('edit-device',e)
|
||||||
|
}
|
||||||
|
public del(e) {
|
||||||
|
this.$emit('del-device',e)
|
||||||
|
}
|
||||||
|
public exec(e) {
|
||||||
|
this.$emit('exec',e)
|
||||||
|
}
|
||||||
|
|
||||||
|
public copyLink(e){
|
||||||
|
this.$Notice.info({
|
||||||
|
title:'链接地址',
|
||||||
|
desc:e.connect_url,
|
||||||
|
duration:3
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
40
src/views/home/components/phoneCard.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div style="display: flex;flex-wrap:wrap;">
|
||||||
|
<div class="device-item" v-for="item in dataList" :key="item.id" >
|
||||||
|
<div class="top">
|
||||||
|
<!-- <Icon type="ios-link" class="link" />-->
|
||||||
|
<div class="icon"><svg-icon :icon-class=" item.is_running ?'device_busy': 'device_free' " :class="! item.is_running ?'status-color2': 'status-color1'"/></div>
|
||||||
|
<span v-text="! item.is_running ? '空闲中': '占用中'" :class="! item.is_running ?'': 'status-color1'"></span>
|
||||||
|
<Icon type="ios-link" class="link" @click="copyLink(item)"/>
|
||||||
|
<Button size="small" type="primary" class="button" v-if="! item.is_running" @click="exec(item)">立即使用</Button>
|
||||||
|
<Button size="small" disabled class="button" style="background-color: #f90;color: white;border-color: #f90" v-else>运行中...</Button>
|
||||||
|
<!-- <Icon type="md-link" class="link"/>-->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="title">{{item.name}}</div>
|
||||||
|
<div class="div-inline">
|
||||||
|
<div class="left">
|
||||||
|
<img src="https://inside.testin.cn/cfgfiles/images/model/1632454023561/f6aec1729de246f99e672b301dadca88.jpg"/>
|
||||||
|
<!-- <img :src="item.pic_url" />-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="device-info">
|
||||||
|
<div style="width:200px; white-space:nowrap;overflow:hidden;text-overflow:ellipsis; ">型号:{{item.model}}</div>
|
||||||
|
<div >版本号:{{item.version}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./phoneCard.ts"></script>
|
||||||
|
|
||||||
|
<style scoped lang="less" src="./phoneCard.less"></style>
|
17
src/views/home/main-app.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import {Component, Mixins, Vue, Watch} from 'vue-property-decorator'
|
||||||
|
import Url, {AdminUrl} from "@/utils/Url";
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import HomeParent from "@/views/home/Common/HomeParent";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class MainApp extends HomeParent {
|
||||||
|
|
||||||
|
public created() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
src/views/home/main.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import App from "./App.vue"
|
||||||
|
import router from './router/index'
|
||||||
|
import store from './store'
|
||||||
|
import Http, { get, post } from "@/utils/Http";
|
||||||
|
import "../../plugins/iview"
|
||||||
|
import "../../plugins/element";
|
||||||
|
import "@/assets/style/tailwind.css"
|
||||||
|
import * as _ from 'lodash'
|
||||||
|
const sprintf = require('sprintf-js');
|
||||||
|
|
||||||
|
import '@/icons'
|
||||||
|
|
||||||
|
Http.store = store;
|
||||||
|
Http.router = router;
|
||||||
|
Http.baseUri = '/rest/'
|
||||||
|
Vue.prototype.$http = Http;
|
||||||
|
Vue.config.devtools = process.env.NODE_ENV !== 'production';
|
||||||
|
// Vue.config.devtools = true;
|
||||||
|
Vue.config.silent = process.env.NODE_ENV === 'production';
|
||||||
|
// Vue.config.silent = false;
|
||||||
|
Vue.config.productionTip = process.env.NODE_ENV !== 'production';
|
||||||
|
Vue.prototype.$isDev = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
|
Vue.prototype.$sprintf = sprintf.sprintf;
|
||||||
|
Vue.prototype.$_ = _;
|
||||||
|
Vue.prototype.$bus = new Vue({});
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render : h => h(App),
|
||||||
|
created() {
|
||||||
|
this.$http.vue = this;
|
||||||
|
}
|
||||||
|
}).$mount('#app')
|
87
src/views/home/pages/home/home.less
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
.boxx{
|
||||||
|
margin: 0 0 18px 20px;
|
||||||
|
font-size: 40px
|
||||||
|
}
|
||||||
|
.demo-split1{
|
||||||
|
height: 450px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.demo-split-pane1{
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.demo-split{
|
||||||
|
height: 680px;
|
||||||
|
margin-top: 50px;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
.demo-split-pane{
|
||||||
|
padding: 10px;
|
||||||
|
//border: 1px solid red;
|
||||||
|
}
|
||||||
|
.demo-split-pane.no-padding{
|
||||||
|
height: 680px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.tag{
|
||||||
|
background-color: #374151;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 100px 8px 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow1 {
|
||||||
|
padding: 15px 0;
|
||||||
|
margin-left: 20px;
|
||||||
|
&-wrap {
|
||||||
|
//margin: 0 auto;
|
||||||
|
width: 120px;
|
||||||
|
height: 34px;
|
||||||
|
background-image: linear-gradient(to right, #227190 , #63c7ed);
|
||||||
|
color: #FFFFFF;
|
||||||
|
line-height: 34px;
|
||||||
|
text-align: start;
|
||||||
|
position: relative;
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: -34px;
|
||||||
|
border: 17px solid transparent;
|
||||||
|
border-left: 17px solid #63c7ed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.arrow2 {
|
||||||
|
padding: 15px 0;
|
||||||
|
margin-left: 20px;
|
||||||
|
&-wrap {
|
||||||
|
//margin: 0 auto;
|
||||||
|
width: 180px;
|
||||||
|
height: 34px;
|
||||||
|
background-image: linear-gradient(to right, #008B8B , #7FFFD4);
|
||||||
|
color: #FFFFFF;
|
||||||
|
line-height: 34px;
|
||||||
|
text-align: start;
|
||||||
|
position: relative;
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: -34px;
|
||||||
|
border: 17px solid transparent;
|
||||||
|
border-left: 17px solid #7FFFD4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress:hover:before{
|
||||||
|
content:attr(content);
|
||||||
|
background:#585e6b;
|
||||||
|
color:#fff;
|
||||||
|
padding:.8em 1em;
|
||||||
|
position:absolute;
|
||||||
|
bottom: -35px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-left:30%;
|
||||||
|
|
||||||
|
}
|
192
src/views/home/pages/home/home.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import { Component, Mixins, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
import Url from "@/utils/Url";
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation
|
||||||
|
} from "vuex-class";
|
||||||
|
import HomeParent from "@/views/home/Common/HomeParent";
|
||||||
|
import CustomPage from "@/components/page.vue";
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components : {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class Home extends HomeParent {
|
||||||
|
name : string = 'home'
|
||||||
|
public scriptList :any = [{ script_name: undefined, date: undefined,content:undefined}];
|
||||||
|
public projectList :any = [{ product_name: undefined, date: undefined}]
|
||||||
|
public myChart;
|
||||||
|
public cardProductData:object = {
|
||||||
|
product_count_trashed:undefined,
|
||||||
|
product_today:undefined,
|
||||||
|
day_rate:undefined,
|
||||||
|
day_icon:undefined,
|
||||||
|
week_rate:undefined,
|
||||||
|
week_icon:undefined,
|
||||||
|
}
|
||||||
|
public cardScriptData:object = {
|
||||||
|
script_week:undefined,
|
||||||
|
use_rate:undefined
|
||||||
|
}
|
||||||
|
public cardTaskData:object = {
|
||||||
|
day_rate:undefined,
|
||||||
|
task_count:undefined,
|
||||||
|
task_month_sum:undefined
|
||||||
|
}
|
||||||
|
public userNumber:number=0;
|
||||||
|
|
||||||
|
public created() {
|
||||||
|
// this._getData()
|
||||||
|
// this._getScriptLog()
|
||||||
|
// this._getProductLog()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private createChart(data) {
|
||||||
|
this.myChart = echarts.init(this.$refs['myChart'] as HTMLCanvasElement);
|
||||||
|
this.myChart.setOption(this.option(data));
|
||||||
|
this.myChart.on('updateAxisPointer', (event)=> {
|
||||||
|
const xAxisInfo = event.axesInfo[0];
|
||||||
|
if (xAxisInfo) {
|
||||||
|
const dimension = xAxisInfo.value + 1;
|
||||||
|
this.myChart.setOption({
|
||||||
|
series: {
|
||||||
|
id: 'pie',
|
||||||
|
label: {
|
||||||
|
formatter: '{b}: {@[' + dimension + ']} ({d}%)'
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
value: dimension,
|
||||||
|
tooltip: dimension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public shortcut(str){
|
||||||
|
this._push({name:str})
|
||||||
|
}
|
||||||
|
|
||||||
|
private option(data) {
|
||||||
|
return {
|
||||||
|
legend: {},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
showContent: false
|
||||||
|
},
|
||||||
|
dataset: {
|
||||||
|
source: data
|
||||||
|
},
|
||||||
|
xAxis: { type: 'category' },
|
||||||
|
yAxis: { gridIndex: 0 },
|
||||||
|
grid: { top: '55%' },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
seriesLayoutBy: 'row',
|
||||||
|
emphasis: { focus: 'series' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
seriesLayoutBy: 'row',
|
||||||
|
emphasis: { focus: 'series' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
seriesLayoutBy: 'row',
|
||||||
|
emphasis: { focus: 'series' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
seriesLayoutBy: 'row',
|
||||||
|
emphasis: { focus: 'series' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
id: 'pie',
|
||||||
|
radius: '30%',
|
||||||
|
center: ['50%', '25%'],
|
||||||
|
emphasis: {
|
||||||
|
focus: 'self'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
formatter: '{b}: {@2012} ({d}%)'
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
itemName: 'product',
|
||||||
|
value: '2012',
|
||||||
|
tooltip: '2012'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getData():void{
|
||||||
|
this.$http.get(Url.OVERVIEW).then((res)=>{
|
||||||
|
this.createChart(res.data.recent_task_logs)
|
||||||
|
|
||||||
|
this.cardProductData = this.alterProduct(res.data.card_data.product)
|
||||||
|
this.cardTaskData = this.alterTask(res.data.card_data.task)
|
||||||
|
this.cardScriptData = this.alterScript(res.data.card_data.script)
|
||||||
|
this.userNumber = res.data.card_data.user
|
||||||
|
|
||||||
|
}).catch((msg:string)=>{
|
||||||
|
this.error(msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getScriptLog():void{
|
||||||
|
this.$http.get(Url.OVERVIEW_SCRIPT).then((res)=>{
|
||||||
|
this.scriptList = res.data
|
||||||
|
}).catch((msg:string)=>{
|
||||||
|
this.error(msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getProductLog():void{
|
||||||
|
this.$http.get(Url.OVERVIEW_PRODUCT).then((res)=>{
|
||||||
|
this.projectList = res.data
|
||||||
|
}).catch((msg:string)=>{
|
||||||
|
this.error(msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private alterProduct(data):object{
|
||||||
|
return {
|
||||||
|
product_count_trashed:data.product_count_trashed,
|
||||||
|
product_today:data.product_today,
|
||||||
|
day_rate:data.product_yesterday==0?'(昨日无构建)':Math.abs(Math.floor(((parseInt(data.product_today)-parseInt(data.product_yesterday)) / parseInt(data.product_yesterday ))*100))+'%',
|
||||||
|
day_icon:parseInt(data.product_today) > parseInt(data.product_yesterday)?1:2,
|
||||||
|
week_rate:Math.abs(Math.floor(((parseInt(data.product_current_week)-parseInt(data.product_last_week)) / parseInt(data.product_last_week ))*100))+'%',
|
||||||
|
week_icon:parseInt(data.product_current_week) > parseInt(data.product_last_week)?1:2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private alterTask(data):object{
|
||||||
|
return {
|
||||||
|
task_count:data.task_count,
|
||||||
|
task_month_sum:data.task_month_sum,
|
||||||
|
day_rate:Math.abs(Math.floor((parseInt(data.task_end_sum)/ parseInt(data.task_logs_sum ))*100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private alterScript(data):object{
|
||||||
|
return {
|
||||||
|
script_week:data.script_week,
|
||||||
|
use_rate:Math.abs(Math.floor((parseInt(data.script_used)/ parseInt(data.script_count ))*100))+'%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
184
src/views/home/pages/home/home.vue
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- <project-list is-my-project></project-list>-->
|
||||||
|
|
||||||
|
|
||||||
|
<div class="demo-split1">
|
||||||
|
<Split v-model="0.5" mode="vertical">
|
||||||
|
<div slot="top" class="demo-split-pane1">
|
||||||
|
<Row>
|
||||||
|
<Col span="5" style="margin-left: 20px">
|
||||||
|
<Card >
|
||||||
|
<p slot="title" style="font-weight: bold;">构建量</p>
|
||||||
|
<p slot="extra"><Icon type="ios-keypad" style="font-size: 24px;color: #36cfc9"/></p>
|
||||||
|
<p > <span style="font-size: 28px">{{cardProductData.product_today}}</span>
|
||||||
|
<Tag type="border" color="success" style="width: 20px;float: right"> <span style="margin-left: -5px">日</span></Tag></p>
|
||||||
|
<p>
|
||||||
|
<span>日同比 {{cardProductData.day_rate}}
|
||||||
|
<Icon type="md-arrow-dropup" color="#19be6b" v-if="cardProductData.day_icon==1"/>
|
||||||
|
<Icon type="md-arrow-dropdown" color="#ed4014" v-else/>
|
||||||
|
</span> 
|
||||||
|
<span>周同比 {{cardProductData.week_rate}}
|
||||||
|
<Icon type="md-arrow-dropup" color="#19be6b" v-if="cardProductData.week_icon==1"/>
|
||||||
|
<Icon type="md-arrow-dropdown" color="#ed4014" v-else/>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<div style="border-top: 1px solid #e8eaec;margin: 10px -16px 0 -16px;">
|
||||||
|
<div style="height:24px;padding-top:10px;display: flex;justify-content: space-between;">
|
||||||
|
<span style="margin-left: 10px">总构建量</span>
|
||||||
|
<span style="margin-right: 10px">{{cardProductData.product_count_trashed}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span="5" offset="1">
|
||||||
|
<Card >
|
||||||
|
<p slot="title" style="font-weight: bold;">任务量</p>
|
||||||
|
<p slot="extra"><Icon type="ios-clipboard" style="font-size: 24px;color: #ff7a45" /></p>
|
||||||
|
<p>
|
||||||
|
<span style="font-size: 28px">{{cardTaskData.task_month_sum}}</span>
|
||||||
|
<Tag type="border" color="primary" style="width: 20px;float: right"> <span style="margin-left: -5px">月</span></Tag>
|
||||||
|
</p>
|
||||||
|
<Progress :percent="cardTaskData.day_rate" hide-info class="progress" :content="'已完成'+cardTaskData.day_rate+'%'"/>
|
||||||
|
<div style="border-top: 1px solid #e8eaec;margin: 10px -16px 0 -16px;">
|
||||||
|
<div style="height:24px;padding-top:10px;display: flex;justify-content: space-between;">
|
||||||
|
<span style="margin-left: 10px">总任务数</span>
|
||||||
|
<span style="margin-right: 10px">{{cardTaskData.task_count}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span="5" offset="1">
|
||||||
|
<Card >
|
||||||
|
<p slot="title" style="font-weight: bold;">脚本数</p>
|
||||||
|
<p slot="extra"><Icon type="logo-python" style="font-size: 24px;color: #47cb89"></Icon></p>
|
||||||
|
<p>
|
||||||
|
<span style="font-size: 28px">{{cardScriptData.script_week}}</span>
|
||||||
|
<Tag type="border" color="error" style="width: 20px;float: right"> <span style="margin-left: -5px">周</span></Tag>
|
||||||
|
</p>
|
||||||
|
<p> </p>
|
||||||
|
<div style="border-top: 1px solid #e8eaec;margin: 10px -16px 0 -16px;">
|
||||||
|
<div style="height:24px;padding-top:10px;display: flex;justify-content: space-between;">
|
||||||
|
<span style="margin-left: 10px">使用率</span>
|
||||||
|
<span style="margin-right: 10px">{{cardScriptData.use_rate}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span="5" offset="1">
|
||||||
|
<Card >
|
||||||
|
<p slot="title" style="font-weight: bold;">用户量</p>
|
||||||
|
<p slot="extra"><Icon type="ios-people" style="font-size: 24px;color: #57a3f3"/></p>
|
||||||
|
<p style="font-size: 28px">{{userNumber}}位</p>
|
||||||
|
<p> </p>
|
||||||
|
<div style="border-top: 1px solid #e8eaec;margin: 10px -16px 0 -16px;">
|
||||||
|
<div style="height:24px;padding-top:10px;display: flex;justify-content: space-between;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
<div slot="bottom" class="demo-split-pane1">
|
||||||
|
<div style="margin-top: 50px;display: flex;justify-content: space-around">
|
||||||
|
<Card style="width:120px;border-radius: 5px">
|
||||||
|
<div style="text-align:center" @click="shortcut('my_project')">
|
||||||
|
<div class="boxx"><svg-icon icon-class="project" /></div>
|
||||||
|
<h3>我的项目</h3>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card style="width:120px;" >
|
||||||
|
<div style="text-align:center;" @click="shortcut('task')">
|
||||||
|
<div class="boxx"><svg-icon icon-class="task" /></div>
|
||||||
|
<h3>任务中心</h3>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card style="width:120px;" >
|
||||||
|
<div style="text-align:center" @click="shortcut('script')">
|
||||||
|
<div class="boxx"><svg-icon icon-class="script" /></div>
|
||||||
|
<h3>脚本市场</h3>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card style="width:120px;" >
|
||||||
|
<div style="text-align:center" @click="shortcut('device')">
|
||||||
|
<div class="boxx"><svg-icon icon-class="device" /></div>
|
||||||
|
<h3>设备大全</h3>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card style="width:120px;" v-for="item in 4">
|
||||||
|
<div style="text-align:center">
|
||||||
|
<img src="@/assets/image/edit.png" width="40" style="margin-left: 20px"/><br >
|
||||||
|
<h3>尽情期待...</h3>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Split>
|
||||||
|
</div>
|
||||||
|
<div class="demo-split">
|
||||||
|
<Split v-model="0.5">
|
||||||
|
<div slot="left" class="demo-split-pane no-padding">
|
||||||
|
<Split v-model="0.5" mode="vertical" >
|
||||||
|
<div slot="top" class="demo-split-pane">
|
||||||
|
<section class="arrow1">
|
||||||
|
<div class="arrow1-wrap"><span style="padding-left:22px ">构建动态</span></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<List item-layout="horizontal" size="small">
|
||||||
|
<ListItem v-for="item in projectList">
|
||||||
|
<ListItemMeta :title="item.product_name" />
|
||||||
|
<template slot="action">
|
||||||
|
<li>
|
||||||
|
<span>{{item.date}}</span>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem v-show="projectList.length>=5">
|
||||||
|
<ListItemMeta />
|
||||||
|
<template slot="action">
|
||||||
|
<li>
|
||||||
|
<a href="my_project">更多</a>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
<div slot="bottom" class="demo-split-pane">
|
||||||
|
<section class="arrow2">
|
||||||
|
<div class="arrow2-wrap"><span style="padding-left:22px ">脚本动态</span></div>
|
||||||
|
</section>
|
||||||
|
<List item-layout="horizontal" size="small">
|
||||||
|
<ListItem v-for="item in scriptList">
|
||||||
|
<ListItemMeta :title="item.content" />
|
||||||
|
<template slot="action">
|
||||||
|
<li>
|
||||||
|
<span>{{item.date}}</span>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem v-show="scriptList.length>=5">
|
||||||
|
<ListItemMeta />
|
||||||
|
<template slot="action">
|
||||||
|
<li>
|
||||||
|
<a href="auto-test/script">更多</a>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
</Split>
|
||||||
|
</div>
|
||||||
|
<div slot="right" class="demo-split-pane">
|
||||||
|
<p style="text-align: center;font-size: 20px;font-weight: bolder;margin-top: 15px">任务执行情况</p>
|
||||||
|
<div ref="myChart" style="width: 800px; height:550px;margin-top:40px" ></div>
|
||||||
|
</div>
|
||||||
|
</Split>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./home.ts"></script>
|
||||||
|
<style lang="less" src="./home.less" scoped></style>
|
15
src/views/home/pages/layout/layout.less
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
.item-menu {
|
||||||
|
color: hsla(0,0%,100%,.7);
|
||||||
|
}
|
||||||
|
.layout{
|
||||||
|
border: 1px solid #d7dde4;
|
||||||
|
background: #f5f7f9;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
154
src/views/home/pages/layout/layout.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import { Component, Mixins, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
import Url, { AdminUrl } from "@/utils/Url";
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import Types from "@/views/admin/store/types";
|
||||||
|
import HomeParent, { BreadItem } from "@/views/home/Common/HomeParent";
|
||||||
|
import { EVENT_TYPE, MenuInterface, ProjectInterface } from "@/views/home/Common/Types";
|
||||||
|
import { Route, RouteRecord } from "vue-router";
|
||||||
|
import { Menu } from "view-design";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class Layout extends HomeParent {
|
||||||
|
|
||||||
|
public siteLogo: object = {}
|
||||||
|
public siteMarquee: object[] = [];
|
||||||
|
public visible: boolean = false;
|
||||||
|
public myMenus: MenuInterface[] = [];
|
||||||
|
public routes: BreadItem[] = [];
|
||||||
|
public myProject: ProjectInterface[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
public created() {
|
||||||
|
this._getMyMenu()
|
||||||
|
// this._getMyProject()
|
||||||
|
// this.$bus.$on(EVENT_TYPE.UPDATE_BREAD_ITEM, this._updateRoutes.bind(this));
|
||||||
|
// this.$bus.$on(EVENT_TYPE.UPDATE_MY_PROJECT, this._getMyProject.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Watch("$route", {immediate: true, deep: true})
|
||||||
|
private _watchRoute(route: Route): void {
|
||||||
|
this.routes.length = 0;
|
||||||
|
route.matched.forEach((item: RouteRecord) => {
|
||||||
|
let ret: BreadItem = this.$router.resolve({name: item.name, params: route.params});
|
||||||
|
ret.name = item.meta.title;
|
||||||
|
this.routes.push(ret);
|
||||||
|
// console.log(ret);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public get isLogin() {
|
||||||
|
return this.$store.state.user.token.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onDropdownEvent(name: string): void {
|
||||||
|
switch (name) {
|
||||||
|
case "logout" : this.logout();break;
|
||||||
|
case "updateName" : this.updateName();break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public logout() {
|
||||||
|
this.$http.get(Url.LOGOUT).then(res => {
|
||||||
|
this._push('/login')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateName(){
|
||||||
|
let self = this;
|
||||||
|
this.$Modal.confirm({
|
||||||
|
title:"修改昵称",
|
||||||
|
render: function(h) {
|
||||||
|
return h('Input', {
|
||||||
|
props: {
|
||||||
|
value: self.$store.getters.user.name,
|
||||||
|
autofocus: true,
|
||||||
|
placeholder: 'Please enter your name...'
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
input: (val) => {
|
||||||
|
this.value = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onOk :function() {
|
||||||
|
self.onVisibleChange(true)
|
||||||
|
if (!this.value || this.value == self.$store.getters.user.name || this.value == '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let data = {name:this.value};
|
||||||
|
self.$http.put(Url.UPDATE_MY_NAME,data).then(res=>{
|
||||||
|
self.success('修改成功',()=>{
|
||||||
|
self.$store.getters.user.name = res.data.name
|
||||||
|
let obj = JSON.parse(window.localStorage.getItem('home'));
|
||||||
|
obj.user.user.name = res.data.name
|
||||||
|
window.localStorage.setItem('home',JSON.stringify(obj));
|
||||||
|
})
|
||||||
|
}).catch((err)=>{
|
||||||
|
self.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转页面时关闭dropdown
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public onMenuChange(name): void {
|
||||||
|
this.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换dropdown显示状态
|
||||||
|
* @param st
|
||||||
|
*/
|
||||||
|
public onVisibleChange(st: boolean) : void {
|
||||||
|
this.visible = !this.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _getMyMenu() {
|
||||||
|
this.myMenus = [
|
||||||
|
{id:1,name:'用户管理',url:'/user',children:[
|
||||||
|
{id:2,name:'用户列表',url:'/user/list',children:[]},
|
||||||
|
{id:3,name:'用户权限',url:'/user/node',children:[]},
|
||||||
|
{id:4,name:'用户菜单',url:'/user/menu',children:[]},
|
||||||
|
]},
|
||||||
|
{id:5,name:'表格',url:'/table',children:[
|
||||||
|
{id:6,name:'普通表格',url:'/table/base',children:[]},
|
||||||
|
{id:7,name:'复杂表格',url:'/table/complex',children:[]},
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getMyProject() {
|
||||||
|
this.$http.get(Url.MY_PROJECT).then(res => {
|
||||||
|
this.myProject = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _parseTreeData(list: any[]) {
|
||||||
|
return list.map((item: any) => {
|
||||||
|
if (item.children.length > 0) {
|
||||||
|
item._showChildren = true;
|
||||||
|
item.children = this._parseTreeData(item.children);
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateRoutes(name: string, idx: number): void {
|
||||||
|
if (this.routes.length >= idx - 1) {
|
||||||
|
this.routes[idx].name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/views/home/pages/layout/layout.vue
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout w-screen h-screen bg-white" >
|
||||||
|
<Sider :style="{position: 'fixed', height: '100vh', left: 0, overflow: 'auto'}" width="300" class="bg-white" style="margin-top: -2px">
|
||||||
|
<h2 class="text-3xl italic pl-8 text-center " style="height: 80px;line-height: 80px;">系统</h2>
|
||||||
|
<Menu width="300">
|
||||||
|
<Submenu :name="item.id" v-for="item in myMenus" :key="item.id" accordion >
|
||||||
|
<template slot="title">
|
||||||
|
<span v-if="item.children.length>0">{{item.name}}</span>
|
||||||
|
<router-link v-else :to="item.url">{{item.name}}</router-link>
|
||||||
|
</template>
|
||||||
|
<MenuItem :name="sonChildren.id" v-for="sonChildren in item.children" :key="sonChildren.id"
|
||||||
|
:to="sonChildren.url">
|
||||||
|
{{sonChildren.name}}
|
||||||
|
</MenuItem>
|
||||||
|
</Submenu>
|
||||||
|
</Menu>
|
||||||
|
</Sider>
|
||||||
|
|
||||||
|
<div style="margin-left:300px ">
|
||||||
|
<div style="height: 66px;box-shadow: 0 2px 3px 2px rgba(0,0,0,.1);line-height: 66px">
|
||||||
|
<div style="float: left;margin-left: 25px">
|
||||||
|
<Breadcrumb params="params" >
|
||||||
|
<BreadcrumbItem :to="route.route.fullPath" :key="route.href"
|
||||||
|
v-for="route in routes" class="text-base "><span class="text-current ">{{route.name}}</span></BreadcrumbItem>
|
||||||
|
</Breadcrumb>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pr-8 text-current" style="float: right">
|
||||||
|
<Dropdown ref="dropdown" trigger="custom" @on-click="onDropdownEvent" :visible="visible">
|
||||||
|
<a href="javascript:void(0)" @click="onVisibleChange">
|
||||||
|
<Icon class="text-4xl " type="ios-contacts"/>
|
||||||
|
<!-- <span>{{this.$store.getters.user.name}}</span>-->
|
||||||
|
<Icon type="ios-arrow-down"></Icon>
|
||||||
|
</a>
|
||||||
|
<DropdownMenu slot="list" >
|
||||||
|
|
||||||
|
<DropdownItem name="updateName" class="text-black hover:text-white hover:bg-gray-700" >修改昵称</DropdownItem>
|
||||||
|
<DropdownItem name="logout" class="text-black hover:text-white hover:bg-gray-700" >退出</DropdownItem>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="p-4 overflow-y-auto lg:h-(screen-14)" >
|
||||||
|
<router-view ></router-view>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./layout.ts"></script>
|
||||||
|
<style lang="less" src="./layout.less" scoped></style>
|
3
src/views/home/pages/layout/router.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<router-view></router-view>
|
||||||
|
</template>
|
102
src/views/home/pages/login/login.less
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
.login {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: url(../../../../assets/image/loginBg.jpg) no-repeat center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.loginBox {
|
||||||
|
height: 455px;
|
||||||
|
width: 550px;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -287px;
|
||||||
|
}
|
||||||
|
.loginH2 {
|
||||||
|
font-size: 38px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.loginCon {
|
||||||
|
margin-top: 30px;
|
||||||
|
background: #eee;
|
||||||
|
border-radius: 4px;
|
||||||
|
.titleDiv {
|
||||||
|
padding: 0 28px;
|
||||||
|
background: #fff;
|
||||||
|
position: relative;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
h3 {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #555;
|
||||||
|
font-weight: initial;
|
||||||
|
padding-top: 23px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #888;
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
font-size: 65px;
|
||||||
|
color: #ddd;
|
||||||
|
position: absolute;
|
||||||
|
right: 27px;
|
||||||
|
top: 29px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-form {
|
||||||
|
padding: 25px 25px 30px 25px;
|
||||||
|
background: #eee;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loginBtn {
|
||||||
|
width: 100%;
|
||||||
|
background: #19b9e7;
|
||||||
|
}
|
||||||
|
.slideShadow {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 999;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
.slideSty {
|
||||||
|
position: absolute;
|
||||||
|
width: 380px;
|
||||||
|
height: 311px;
|
||||||
|
background: #e8e8e8;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
margin-left: -188px;
|
||||||
|
margin-top: -176px;
|
||||||
|
z-index: 99;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.iconBtn {
|
||||||
|
padding: 9px 0 0 19px;
|
||||||
|
color: #5f5f5f;
|
||||||
|
border-top: 1px solid #d8d8d8;
|
||||||
|
margin-top: 17px;
|
||||||
|
i {
|
||||||
|
font-size: 22px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
i:last-child {
|
||||||
|
margin-left: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.slideSty .slide-verify {
|
||||||
|
margin: 13px auto 0 auto;
|
||||||
|
width: 350px !important;
|
||||||
|
}
|
||||||
|
.slideSty .slide-verify-slider {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.slideSty .slide-verify-refresh-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
227
src/views/home/pages/login/login.ts
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
import { Component, Mixins, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
import Url, { AdminUrl } from "@/utils/Url";
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
Getter,
|
||||||
|
Action,
|
||||||
|
Mutation,
|
||||||
|
} from "vuex-class";
|
||||||
|
import { Form } from "view-design";
|
||||||
|
import "@/assets/js/wwlogin";
|
||||||
|
import HomeParent from "@/views/home/Common/HomeParent";
|
||||||
|
import Types from "@/views/admin/store/types";
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
import { Message } from 'element-ui';
|
||||||
|
import ChainManager from '@/metamask/ChainManager'
|
||||||
|
import Web3 from 'web3'
|
||||||
|
import {Http_getNonce, Http_login} from "@/utils/login-request";
|
||||||
|
import store from "@/views/home/store";
|
||||||
|
import {ActionContext} from "vuex";
|
||||||
|
import {UserState} from "@/views/home/store/user";
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
ethereum: any
|
||||||
|
web3: any
|
||||||
|
celo: any
|
||||||
|
}
|
||||||
|
declare let window: Window
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components : {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class Login extends HomeParent {
|
||||||
|
@Action('Login') Login;
|
||||||
|
public context : ActionContext<UserState, any>
|
||||||
|
public provider:any
|
||||||
|
public web3:Web3
|
||||||
|
public chainId:number
|
||||||
|
public account:string
|
||||||
|
public nonce:string
|
||||||
|
|
||||||
|
public async btn(){
|
||||||
|
if (!this.$store.getters.step){
|
||||||
|
try {
|
||||||
|
await this.connect()
|
||||||
|
await this.checkNance()
|
||||||
|
} catch (err) {
|
||||||
|
Message({
|
||||||
|
message: err.message,
|
||||||
|
type: 'error',
|
||||||
|
duration: 5 * 1000
|
||||||
|
})
|
||||||
|
Promise.reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public get accessToken(): string {
|
||||||
|
let token: string = this.$route.query.access_token as string;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public rules: object = {
|
||||||
|
username: [{required: true, trigger: 'blur', message: "请输入登录名"}],
|
||||||
|
password: [{required: true, trigger: 'blur', message: "请输入登录密码"}],
|
||||||
|
}
|
||||||
|
|
||||||
|
public created() {
|
||||||
|
// if(!this.accessToken) {
|
||||||
|
// this._getData();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getData(): void {
|
||||||
|
this.$http.get(Url.WORK_LOGIN).then(res => {
|
||||||
|
window["WwLogin"]({
|
||||||
|
id: "loginPage",
|
||||||
|
goto: res.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// public doLogin(): void {
|
||||||
|
// let form: Form = this.$refs["login"] as Form;
|
||||||
|
// form.validate((valid: boolean) => {
|
||||||
|
// if (!valid) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // this.Login(this.form).then((user) => {
|
||||||
|
// // this.goPage("home");
|
||||||
|
// // }).catch((msg: string) => {
|
||||||
|
// // this.error(msg);
|
||||||
|
// // })
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
private async login( account, chainId, nonce) {
|
||||||
|
nonce += ''
|
||||||
|
const tips = 'This signature is only used for verify your account'
|
||||||
|
const signMsg = {
|
||||||
|
tips,
|
||||||
|
nonce
|
||||||
|
}
|
||||||
|
const EIP721_DOMAIN_DATA = [
|
||||||
|
{ name: 'name', type: 'string' },
|
||||||
|
{ name: 'version', type: 'string' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const signObj = {
|
||||||
|
types: {
|
||||||
|
EIP712Domain: EIP721_DOMAIN_DATA,
|
||||||
|
set: [
|
||||||
|
{ name: 'tips', type: 'string' },
|
||||||
|
{ name: 'nonce', type: 'string' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
primaryType: 'set',
|
||||||
|
domain: {
|
||||||
|
name: 'Auth',
|
||||||
|
version: '1'
|
||||||
|
},
|
||||||
|
message: signMsg
|
||||||
|
}
|
||||||
|
const signature = await this.signData(signObj, account)
|
||||||
|
const authData = {
|
||||||
|
account,
|
||||||
|
nonce,
|
||||||
|
signature,
|
||||||
|
tips,
|
||||||
|
net_id: chainId
|
||||||
|
}
|
||||||
|
const res:any = await Http_login(authData)
|
||||||
|
if (!res.errcode && res.token) {
|
||||||
|
store.commit('set_token',res.token)
|
||||||
|
console.log(store.getters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async checkNance() {
|
||||||
|
try {
|
||||||
|
let nonce = store.getters.nonce
|
||||||
|
if (!nonce) {
|
||||||
|
let params = {account:this.account, net_id:this.chainId}
|
||||||
|
const res:any = await Http_getNonce(params);
|
||||||
|
store.commit('set_nonce',res.nonce)
|
||||||
|
this.nonce = res.nonce
|
||||||
|
}
|
||||||
|
this.login(this.account,this.chainId,this.nonce)
|
||||||
|
} catch (err) {
|
||||||
|
Promise.reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async connect(){
|
||||||
|
if (!this.hasMetamask()) {
|
||||||
|
Message({
|
||||||
|
message: '请先安装MetaMask插件',
|
||||||
|
type: 'error',
|
||||||
|
duration: 5 * 1000
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.provider = await this.connectMetaMask()
|
||||||
|
if (!this.provider) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.web3 = new Web3(this.provider)
|
||||||
|
this.chainId = await this.web3.eth.getChainId()
|
||||||
|
const accounts = await this.web3.eth.getAccounts()
|
||||||
|
if (accounts && accounts.length > 0) {
|
||||||
|
this.account =accounts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async connectMetaMask() {
|
||||||
|
let provider = window.ethereum
|
||||||
|
try {
|
||||||
|
await provider.request({ method: 'eth_requestAccounts' })
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === -32002) {
|
||||||
|
throw new Error('MeatMask not login, Open MeatMask and login first')
|
||||||
|
} else {
|
||||||
|
throw new Error('User Rejected')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasMetamask():boolean {
|
||||||
|
if (typeof window.ethereum !== 'undefined') {
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async signData(signObj: any, signer: string) {
|
||||||
|
const msgParams = JSON.stringify(signObj)
|
||||||
|
const from = signer
|
||||||
|
const params = [from, msgParams]
|
||||||
|
const result: any = await this.sendCmd({
|
||||||
|
method: 'eth_signTypedData_v4',
|
||||||
|
params,
|
||||||
|
from
|
||||||
|
})
|
||||||
|
return result.result
|
||||||
|
}
|
||||||
|
private async sendCmd({ method, params, from }:any) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
this.web3.currentProvider.sendAsync({
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
from
|
||||||
|
}, async function(err: any, result: any) {
|
||||||
|
if (err) {
|
||||||
|
reject && reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve && resolve(result)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
src/views/home/pages/login/login.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div class="login">
|
||||||
|
<div class="w-full h-3/5 flex items-center justify-center align-middle">系统</div>
|
||||||
|
<div class="w-full flex justify-center align-middle">
|
||||||
|
<div class=" rounded-xl" @click="btn">
|
||||||
|
<svg-icon icon-class="login" style="width: 100px;height: 100px;cursor:pointer"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./login.ts"></script>
|
||||||
|
<style lang="less" scoped src="./login.less"></style>
|
41
src/views/home/router/index.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter, { RouteConfig } from 'vue-router'
|
||||||
|
import Routers from './router'
|
||||||
|
import Store from '../store'
|
||||||
|
import { LoadingBar } from 'view-design'
|
||||||
|
import Types from "@/views/home/store/types";
|
||||||
|
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
const routes : Array<RouteConfig> = [
|
||||||
|
...Routers
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
base : "/dashboard/",
|
||||||
|
mode : "history",
|
||||||
|
routes,
|
||||||
|
})
|
||||||
|
|
||||||
|
function setTitle(title : string) : void {
|
||||||
|
window.document.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
LoadingBar.start();
|
||||||
|
let title : string = process.env.VUE_APP_TITLE;
|
||||||
|
setTitle(to.meta.title + '-' + title);
|
||||||
|
let token : string = to.query.access_token as string;
|
||||||
|
if (token) {
|
||||||
|
Store.commit(Types.SET_USER_TOKEN, token);
|
||||||
|
next({name : to.name === 'login'? 'home' : to.name})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
LoadingBar.finish();
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
23
src/views/home/router/router.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { RouteConfig } from "vue-router";
|
||||||
|
import Layout from '../pages/layout/layout.vue'
|
||||||
|
|
||||||
|
const routers: RouteConfig[] = [{
|
||||||
|
path: "/",
|
||||||
|
name: 'layout',
|
||||||
|
component: Layout,
|
||||||
|
redirect: "/home",
|
||||||
|
meta: {title: "首页", isMenu: false},
|
||||||
|
children: [{
|
||||||
|
path: "home",
|
||||||
|
name: 'home',
|
||||||
|
meta: {title: "dashboard", isMenu: false},
|
||||||
|
component: () => import(/* webpackChunkName: "home-home" */ '@/views/home/pages/home/home.vue'),
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
path: "/login",
|
||||||
|
name: 'login',
|
||||||
|
meta: {title: "", isMenu: false},
|
||||||
|
component: () => import(/* webpackChunkName: "home-login" */ '@/views/home/pages/login/login.vue'),
|
||||||
|
}];
|
||||||
|
|
||||||
|
export default routers;
|
54
src/views/home/store/index.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import user, { UserState } from "@/views/home/store/user";
|
||||||
|
import createPersistedState from 'vuex-persistedstate'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
interface StateInterface {
|
||||||
|
user : UserState,
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStorage : any = window.localStorage;
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
getters : {
|
||||||
|
token : (state : StateInterface) => state.user.token,
|
||||||
|
user : (state : StateInterface) => state.user.user,
|
||||||
|
step:state => state.step,
|
||||||
|
nonce:state => state.nonce
|
||||||
|
},
|
||||||
|
modules : {
|
||||||
|
user
|
||||||
|
},
|
||||||
|
plugins : [
|
||||||
|
createPersistedState({
|
||||||
|
key : 'home',
|
||||||
|
storage : {
|
||||||
|
getItem : (key : string) => {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
},
|
||||||
|
setItem : (key : string, value : any) => {
|
||||||
|
return localStorage.setItem(key, value);
|
||||||
|
},
|
||||||
|
removeItem : (key : string) => {
|
||||||
|
return localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
mutations: {
|
||||||
|
set_nonce(state, nonce) {
|
||||||
|
state.nonce = nonce
|
||||||
|
// sessionStorage.nonce = nonce
|
||||||
|
},
|
||||||
|
set_token(state, token) {
|
||||||
|
state.token = token
|
||||||
|
sessionStorage.token = token
|
||||||
|
},
|
||||||
|
del_token(state) {
|
||||||
|
state.token = ''
|
||||||
|
sessionStorage.removeItem('token')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
9
src/views/home/store/types.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default class Types {
|
||||||
|
static readonly SET_USER_INFO : string = 'SET_USER_INFO';
|
||||||
|
static readonly SET_USER_TOKEN : string = 'SET_USER_TOKEN';
|
||||||
|
static readonly SET_LANG : string = 'SET_LANG';
|
||||||
|
static readonly SET_SITE_INFO : string = "SET_SITE_INFO";
|
||||||
|
|
||||||
|
static readonly SET_USER_CURRENCY : string = 'SET_USER_CURRENCY';
|
||||||
|
static readonly UPDATE_USER_CREDIT : string = 'UPDATE_USER_CREDIT'
|
||||||
|
}
|
46
src/views/home/store/user.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import {ActionContext} from "vuex";
|
||||||
|
import Http, { ResponseErrorInterface, ResponseInterface } from "@/utils/Http";
|
||||||
|
import Url from "@/utils/Url";
|
||||||
|
import Types from "@/views/home/store/types";
|
||||||
|
import { UserInterface } from "@/views/home/Common/Types";
|
||||||
|
|
||||||
|
const sprintf = require('sprintf-js');
|
||||||
|
|
||||||
|
export interface UserState {
|
||||||
|
user : UserInterface,
|
||||||
|
token : string | undefined,
|
||||||
|
isLogin : boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name : "user",
|
||||||
|
namespace : true,
|
||||||
|
state : {
|
||||||
|
user : {},
|
||||||
|
token : undefined,
|
||||||
|
isLogin : false
|
||||||
|
},
|
||||||
|
actions : {
|
||||||
|
Login(context : ActionContext<UserState, any>, form : any) {
|
||||||
|
return Http.post(Url.LOGIN, form).then((res : ResponseInterface) => {
|
||||||
|
context.commit(Types.SET_USER_INFO, res.data);
|
||||||
|
context.commit(Types.SET_USER_TOKEN, res.data.access_token);
|
||||||
|
return Promise.resolve(res.data);
|
||||||
|
}).catch((err : string) => {
|
||||||
|
return Promise.reject(err);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getMenus() {
|
||||||
|
// return Http.get()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations : {
|
||||||
|
[Types.SET_USER_INFO](state : UserState, user : UserInterface) {
|
||||||
|
state.user = user;
|
||||||
|
},
|
||||||
|
[Types.SET_USER_TOKEN](state : UserState, token : string) {
|
||||||
|
state.token = token;
|
||||||
|
state.isLogin = token.length > 0;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
12
src/views/wap/App.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
background: #f2f2f2;
|
||||||
|
}
|
||||||
|
</style>
|
20
src/views/wap/Common/WapParent.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import Parent from "@/utils/Parnet";
|
||||||
|
|
||||||
|
export default class WapParent extends Parent {
|
||||||
|
public success(content? : string, callback? : Function) {
|
||||||
|
this.$toast.success( {
|
||||||
|
message: content ? content : "操作成功",
|
||||||
|
onClose : () => {
|
||||||
|
callback && callback();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
public error(content? : string, callback? : Function){
|
||||||
|
this.$toast.fail( {
|
||||||
|
message: content ? content : "操作成功",
|
||||||
|
onClose : () => {
|
||||||
|
callback && callback();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|