33235b33 by zhen

init project

0 parents
Showing 107 changed files with 3852 additions and 0 deletions
# just a flag
ENV = 'development'
# base api
# VUE_APP_BASE_API = 'http://192.168.11.94:8081'
# VUE_APP_BASE_API = 'http://192.168.252.25:8081'
VUE_APP_BASE_API = 'https://pre-web-chery.situdata.com'
VUE_APP_WEBRTC_URL = 'pre-jitsi-chery.situdata.com'
# VUE_APP_WEBRTC_URL = 'srtc.situdata.com'
\ No newline at end of file
# just a flag
VUE_APP_BASE_API = 'https://ft.cheryfs.cn:8100'
VUE_APP_WEBRTC_URL = 'vc.cheryfs.cn:8443'
\ No newline at end of file
node_modules
dist
.DS_Store
.idea
\ No newline at end of file
# 云霄后台管理
module.exports = {
presets: [
'@vue/app'
]
}
This diff could not be displayed because it is too large.
{
"name": "yunxiao-admin-fe",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit",
"commit": "cz"
},
"dependencies": {
"animate.css": "^4.1.0",
"axios": "^0.18.1",
"captcha-mini": "^1.1.0",
"core-js": "^2.6.11",
"echarts": "^4.8.0",
"element-ui": "^2.13.2",
"js-cookie": "^2.2.1",
"nprogress": "^0.2.0",
"pug": "^2.0.4",
"pug-plain-loader": "^1.0.0",
"uuid": "^8.3.0",
"v-charts": "^1.19.0",
"video.js": "^7.8.4",
"vue": "^2.6.10",
"vue-router": "^3.1.3",
"vue-simple-uploader": "^0.7.4",
"vuex": "^3.1.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.12.1",
"@vue/cli-plugin-eslint": "^3.12.1",
"@vue/cli-plugin-unit-mocha": "^3.12.1",
"@vue/cli-service": "^3.12.1",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "1.0.0-beta.29",
"babel-eslint": "^10.0.3",
"chai": "^4.1.2",
"commitizen": "^4.2.0",
"cz-conventional-changelog": "^3.2.1",
"cz-emoji": "^1.2.2",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"filemanager-webpack-plugin": "^2.0.5",
"node-sass": "^4.13.0",
"qr-image": "^3.2.0",
"sass-loader": "^7.3.1",
"svg-sprite-loader": "^4.3.0",
"vue-particles": "^1.0.9",
"vue-template-compiler": "^2.5.21"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"@vue/standard"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {
"no-tabs": "off",
"space-before-function-paren": "off"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"config": {
"cz-emoji": {
"types": [
{
"emoji": "🌟",
"code": "🌟feat:",
"description": "A new feature",
"name": "feature"
},
{
"emoji": "🐞",
"code": "🐞fix:",
"description": "A bug fix",
"name": "fix"
},
{
"emoji": "📝",
"code": "📝docs:",
"description": "update docs",
"name": "docs"
},
{
"emoji": "💰",
"code": "💰perf:",
"description": "Improves performance with this change",
"name": "perf"
},
{
"emoji": "🎨",
"code": "🎨style:",
"description": "Doesn't affect the meaning of the code (white-space, semi-colons, etc)",
"name": "style"
},
{
"emoji": "🚓",
"code": "🚓test:",
"description": "Testing improved with new or fixed tests",
"name": "test"
},
{
"emoji": "🔨",
"code": "🔨build-conf:",
"description": "更新一些配置文件",
"name": "build-conf"
},
{
"emoji": "💊",
"code": "💊revert:",
"description": "Reverts a previous commit",
"name": "revert"
}
]
},
"commitizen": {
"path": "./node_modules/cz-emoji"
}
}
}
module.exports = {
// tab缩进大小,默认为2
tabWidth: 2,
// 使用tab缩进,默认false
useTabs: false,
// 使用分号, 默认true
semi: false,
// 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
singleQuote: true,
// 行尾逗号,默认none,可选 none|es5|all
// es5 包括es5中的数组、对象
// all 包括函数对象等所有可选
TrailingCooma: 'none',
// 对象中的空格 默认true
// true: { foo: bar }
// false: {foo: bar}
bracketSpacing: true,
// JSX标签闭合位置 默认false
// false: <div
// className=""
// style={{}}
// >
// true: <div
// className=""
// style={{}} >
jsxBracketSameLine: false,
// 箭头函数参数括号 默认avoid 可选 avoid| always
// avoid 能省略括号的时候就省略 例如x => x
// always 总是有括号
arrowParens: 'avoid'
}
No preview for this file type
<!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" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>云销</title>
<!-- strophe删除待定 -->
<!-- <script src="./libs/strophe/strophe.js"></script>
<script src="./libs/strophe/strophe.disco.min.js?v=1"></script>
<script src="./libs/jquery-2.1.1.min.js"></script>
<script src="./libs/lib-jitsi-meet.min.js"></script> -->
</head>
<body>
<noscript>
<strong
>We're sorry but smartimageplatform 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>
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
Strophe.addConnectionPlugin("disco",{_connection:null,_identities:[],_features:[],_items:[],init:function(conn){this._connection=conn;this._identities=[];this._features=[];this._items=[];conn.addHandler(this._onDiscoInfo.bind(this),Strophe.NS.DISCO_INFO,"iq","get",null,null);conn.addHandler(this._onDiscoItems.bind(this),Strophe.NS.DISCO_ITEMS,"iq","get",null,null)},addIdentity:function(category,type,name,lang){for(var i=0;i<this._identities.length;i++){if(this._identities[i].category==category&&this._identities[i].type==type&&this._identities[i].name==name&&this._identities[i].lang==lang){return false}}this._identities.push({category:category,type:type,name:name,lang:lang});return true},addFeature:function(var_name){for(var i=0;i<this._features.length;i++){if(this._features[i]==var_name){return false}}this._features.push(var_name);return true},removeFeature:function(var_name){for(var i=0;i<this._features.length;i++){if(this._features[i]===var_name){this._features.splice(i,1);return true}}return false},addItem:function(jid,name,node,call_back){if(node&&!call_back){return false}this._items.push({jid:jid,name:name,node:node,call_back:call_back});return true},info:function(jid,node,success,error,timeout){var attrs={xmlns:Strophe.NS.DISCO_INFO};if(node){attrs.node=node}var info=$iq({from:this._connection.jid,to:jid,type:"get"}).c("query",attrs);this._connection.sendIQ(info,success,error,timeout)},items:function(jid,node,success,error,timeout){var attrs={xmlns:Strophe.NS.DISCO_ITEMS};if(node){attrs.node=node}var items=$iq({from:this._connection.jid,to:jid,type:"get"}).c("query",attrs);this._connection.sendIQ(items,success,error,timeout)},_buildIQResult:function(stanza,query_attrs){var id=stanza.getAttribute("id");var from=stanza.getAttribute("from");var iqresult=$iq({type:"result",id:id});if(from!==null){iqresult.attrs({to:from})}return iqresult.c("query",query_attrs)},_onDiscoInfo:function(stanza){var node=stanza.getElementsByTagName("query")[0].getAttribute("node");var attrs={xmlns:Strophe.NS.DISCO_INFO};if(node){attrs.node=node}var iqresult=this._buildIQResult(stanza,attrs);for(var i=0;i<this._identities.length;i++){var attrs={category:this._identities[i].category,type:this._identities[i].type};if(this._identities[i].name){attrs.name=this._identities[i].name}if(this._identities[i].lang){attrs["xml:lang"]=this._identities[i].lang}iqresult.c("identity",attrs).up()}for(var i=0;i<this._features.length;i++){iqresult.c("feature",{"var":this._features[i]}).up()}this._connection.send(iqresult.tree());return true},_onDiscoItems:function(stanza){var query_attrs={xmlns:Strophe.NS.DISCO_ITEMS};var node=stanza.getElementsByTagName("query")[0].getAttribute("node");if(node){query_attrs.node=node;var items=[];for(var i=0;i<this._items.length;i++){if(this._items[i].node==node){items=this._items[i].call_back(stanza);break}}}else{var items=this._items}var iqresult=this._buildIQResult(stanza,query_attrs);for(var i=0;i<items.length;i++){var attrs={jid:items[i].jid};if(items[i].name){attrs.name=items[i].name}if(items[i].node){attrs.node=items[i].node}iqresult.c("item",attrs).up()}this._connection.send(iqresult.tree());return true}});
\ No newline at end of file
This diff could not be displayed because it is too large.
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
methods: {
onlineMethod() {
this.$notify({ title: '网络恢复正常', type: 'success' })
},
offlineMethod() {
this.$notify.error({ title: '网络连接异常' })
}
},
beforeMount() {
window.addEventListener('online', this.onlineMethod)
window.addEventListener('offline', this.offlineMethod)
},
beforeDestroy() {
window.removeEventListener('online', this.onlineMethod)
window.removeEventListener('offline', this.offlineMethod)
}
}
</script>
<style lang="scss">
@mixin cover {
width: 100%;
height: 100%;
}
html,
body {
@include cover;
padding: 0;
margin: 0;
}
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
@include cover;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
.el-main {
text-align: left;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
</style>
import request from '@/utils/request'
/**
* 7天业务量
* @param {*} data
*/
export function volumeCalls(data) {
return request({
url: '/chery/homepage/volumeCalls',
method: 'post',
data
})
}
/**
* 通话时长
* @param {*} data
*/
export function durationsCalls(data) {
return request({
url: '/chery/homepage/durationsCalls',
method: 'post',
data
})
}
import request from '@/utils/request'
/**
* 删除订单
*/
export function deleteOrder(data) {
return request({
url: '/chery/order/delete',
method: 'post',
data
})
}
/**
* 全部订单列表查询
*/
export function queryOrderList(data) {
return request({
url: '/chery/order/query/list',
method: 'post',
data
})
}
/**
* 全部订单列表查询
*/
export function queryMyOrderList(data) {
return request({
url: '/chery/order/query/mylist',
method: 'post',
data
})
}
/**
* 订单详情
*/
export function getOrderDetail(data) {
return request({
url: '/chery/order/detail/get',
method: 'post',
data
})
}
import request from '@/utils/request'
/**
* 创建合作商
* @param {*} data
*/
export function createPattern(data) {
return request({
url: '/chery/partner/create',
method: 'post',
data
})
}
/**
* 删除合作商
* @param {*} data
*/
export function deletePattern(data) {
return request({
url: '/chery/partner/delete',
method: 'post',
data
})
}
/**
* 查询合作商
* @param {*} data
*/
export function queryPattern(data) {
return request({
url: '/chery/partner/query',
method: 'post',
data
})
}
/**
* 合作商code是否存在
* @param {*} data
*/
export function validateCode(data) {
return request({
url: '/chery/partner/valid-code',
method: 'post',
data
})
}
/**
* 报表列表查询
* @param {*} data
*/
export function reportList(data) {
return request({
url: '/chery/order/report/list',
method: 'post',
data
})
}
/**
* 报表下载接口
* @param {*} data
*/
export function reportDownload(data) {
return request({
url: '/chery/order/report/download',
method: 'post',
responseType: 'blob',
data
})
}
import request from '@/utils/request'
/**
* tts开关
* @param {*} data
*/
export function ttsSwitch(data) {
return request({
url: '/chery/tts/option/switch',
method: 'post',
data
})
}
/**
* web查询话术结果
* @param {*} data
*/
export function getTtsResult(data) {
return request({
url: '/chery/tts/result',
method: 'post',
data
})
}
/**
* 保存tts
* @param {*} data
*/
export function saveTts(data) {
return request({
url: '/chery/tts/save',
method: 'post',
data
})
}
/**
* web查询话术配置
* @param {*} data
*/
export function getTtsTemplate(data) {
return request({
url: '/chery/tts/getTemplate',
method: 'post',
data
})
}
/**
* 查询tts是否开放
* @param {*} data
*/
export function getTtsStatus(data) {
return request({
url: '/chery/call/workTimeStatus',
method: 'post',
data
})
}
import request from '@/utils/request'
/**
* 登录
* @param {*} data
*/
export function login(data) {
return request({
url: '/chery/account/login',
method: 'post',
data
})
}
/**
* 登出
*/
export function logout() {
return request({
url: '/chery/account/logout',
method: 'post'
})
}
/**
* 注册
* @param {*} data
*/
export function registry(data) {
return request({
url: '/chery/account/registry',
method: 'post',
data
})
}
/**
* 重置密码
* @param {*} data
*/
export function resetPassword(data) {
return request({
url: '/chery/account/reset-password',
method: 'post',
data
})
}
/**
* 删除
* @param {*} data
*/
export function deleteUser(data) {
return request({
url: '/chery/account/delete',
method: 'post',
data
})
}
/**
* 禁用账号
* @param {*} data
*/
export function accountAvailable(data) {
return request({
url: '/chery/account/available',
method: 'post',
data
})
}
/**
* 账号列表查询
* @param {*} data
*/
export function accountList(data) {
return request({
url: '/chery/account/list',
method: 'post',
data
})
}
/**
* 验证工号是否已存在
* @param {*} data
*/
export function validUsername(data) {
return request({
url: '/chery/account/valid-username',
method: 'post',
data
})
}
/**
* 监控开启关闭
* @param {*} data
*/
export function switchMonitor(data) {
return request({
url: '/chery/account/switch-monitor',
method: 'post',
data
})
}
import request from '@/utils/request'
/**
* 确认接通
* @param {*} data
*/
export function callWebConfirm(data) {
return request({
url: '/chery/call/web/confirm',
method: 'post',
data
})
}
/**
* 挂断电话
* @param {*} data
*/
export function callWebDisconnect(data) {
return request({
url: '/chery/call/web/disconnect',
method: 'post',
data
})
}
/**
* 拨打电话
* @param {*} data
*/
export function callWebIn(data) {
return request({
url: '/chery/call/web/in',
method: 'post',
data
})
}
/**
* 创建订单
* @param {*} data
*/
export function createOrder(data) {
return request({
url: 'chery/order/create',
method: 'post',
data
})
}
/**
* 删除订单
* @param {*} data
*/
export function deleteOrder(data) {
return request({
url: '/chery/order-system/delete',
method: 'post',
data
})
}
/**
* web-推送消息到app
* @param {*} data
*/
export function notifyApp(data) {
return request({
url: '/chery/notify/app',
method: 'post',
data
})
}
/**
* 工作台未沟通/已沟通列表
* @param {*} data
*/
export function getCommunicationList(data) {
return request({
url: '/chery/order/web/list',
method: 'post',
data
})
}
/**
* WEB-获取排队列表
* @param {*} data
*/
export function getQueueQuery(data) {
return request({
url: '/chery/call/web/queue/query',
method: 'post',
data
})
}
/**
*WEB-查询订单信息
* @param {*} data
*/
export function getOrderInfo(data) {
return request({
url: '/chery/order/fetch/order-info',
method: 'post',
data
})
}
/**
* 二要素比图身份认证接口
* @param {*} data
*/
export function twoElementFace(data) {
return request({
url: '/chery/external/two-element-face/verify',
method: 'post',
data
})
}
/**
*情绪程度识别
* @param {*} data
*/
export function emotionRecognize(data) {
return request({
url: '/chery/external/emotion/recognize',
method: 'post',
data
})
}
/**
* WEB-等待接通
* @param {*} data
*/
export function callWebWait(data) {
return request({
url: '/chery/call/web/wait',
method: 'post',
data
})
}
/**
* WEB-等待接通
* @param {*} data
*/
export function callWebPoll(data) {
return request({
url: '/chery/call/web/poll',
method: 'post',
data
})
}
No preview for this file type
No preview for this file type
h1,
h2,
h3,
h4,
h5,
h6 {
padding: 0;
margin: 0;
}
.upload-cropper {
display: inline-block;
width: 300px;
background: #f2f2f2;
}
// 外边距
.mb5 {
margin-bottom: 5px;
}
.mb10 {
margin-bottom: 10px;
}
.mb20 {
margin-bottom: 20px;
}
.mr5 {
margin-right: 5px;
}
.text-align-center {
text-align: center;
}
.forbid {
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor: not-allowed;
}
// 全局修改card样式
.el-card .el-card__body {
padding: 5px;
}
// color
.white {
color: white;
}
// 图片资源
.username-icon {
background: center no-repeat url('./assets/image/username.png');
}
.password-icon {
background: center no-repeat url('./assets/image/password.png');
}
.validate-icon {
background: center no-repeat url('./assets/image/validate.png');
}
.login-form-bg {
background: center / cover no-repeat url('./assets/image/login-form-bg.png');
}
<template>
<div class="bread">
<div>
<slot name="title"></slot>
<span class="btn">
<slot name="btn"></slot>
</span>
</div>
<el-button
v-if="isShowBack"
type="text"
style="margin-right:50px;"
@click="handleClick"
>返回</el-button
>
</div>
</template>
<script>
export default {
name: 'Bread',
props: {
isShowBack: {
type: Boolean,
default: false
}
},
methods: {
handleClick() {
this.$router.go(-1)
}
}
}
</script>
<style lang="scss" scoped>
.bread {
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
border-left: 5px solid #3f51b5;
padding-left: 15px;
font-size: 16px;
font-weight: 700;
.btn {
display: inline-block;
color: #3f51b5;
margin-left: 15px;
font-size: 20px;
cursor: pointer;
}
}
</style>
import Bread from './Bread.vue'
export default Bread
<template>
<div class="card-com">
<div><slot name="title"></slot></div>
<slot></slot>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
.card-com {
padding: 28px 24px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-sizing: border-box;
background-color: #fff;
}
</style>
<template lang="pug">
span(ref="countUp")
</template>
<script>
import { CountUp } from 'countup.js'
export default {
name: 'CountUp',
props: {
// 目标数字
end: {
type: Number,
default: 0
},
// 默认配置
options: {
type: Object,
default: () => {
return {
startVal: 0,
decimalPlaces: 0,
duration: 1,
separator: ',',
decimal: '.'
}
}
}
},
data() {
return {
numAnim: null
}
},
watch: {
end: {
handler(newVal, oldVal) {
this.numAnim.update(newVal)
}
}
},
mounted() {
this.initCountUp()
},
beforeDestroy() {
this.numAnim = null
},
methods: {
initCountUp() {
this.numAnim = new CountUp(this.$refs.countUp, this.end, this.options)
if (!this.numAnim.error) {
this.numAnim.start()
} else {
console.error(this.numAnim.error)
}
}
}
}
</script>
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: 'icon-svg',
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>
.svg-icon {
width: 1em;
height: 1em;
fill: currentColor;
overflow: hidden;
}
</style>
<template lang="pug">
div(class="login-main login-form-bg")
div(class="title")
.main-content
el-form(:model="loginForm" ref="form" :rules="rules" @keydown.enter.native="login")
el-form-item(prop="username")
el-input(
ref="username"
size="medium"
class="login-input"
placeholder="请输入工号"
v-model.trim="loginForm.username"
)
i(slot="prefix" class="icon username-icon")
el-form-item(prop="password")
el-input(
ref="password"
type="password"
size="medium"
placeholder="请输入密码"
class="login-input"
v-model.trim="loginForm.password"
)
i(slot="prefix" class="icon password-icon")
el-form-item(prop="verificationCode")
.captcha
el-input(
size="medium"
placeholder="请输入验证码"
class="captcha-input"
v-model.trim="loginForm.verificationCode"
)
i(slot="prefix" class="icon validate-icon")
<canvas width="93" height="36" id="captcha1"></canvas>
el-form-item
.buton-warp
el-button(class="login-btn" type="primary" @click="login" :loading="loading")
span(class="login-btn-text") 登&nbsp;&nbsp;&nbsp;&nbsp;录
</template>
<script>
import Captcha from 'captcha-mini'
import { maxSizeValidate } from '@/views/validate'
export default {
name: 'LoginForm',
props: {
usernameRules: {
type: Array,
default: () => {
return [
{ required: true, message: '账号不能为空', trigger: 'blur' },
maxSizeValidate
]
}
},
passwordRules: {
type: Array,
default: () => {
return [
{ required: true, message: '密码不能为空', trigger: 'blur' },
maxSizeValidate
]
}
},
loading: {
type: Boolean,
default: false
}
},
data() {
return {
verCode: '',
captcha1: null,
loginForm: {
username: '',
password: '',
verificationCode: ''
}
}
},
computed: {
rules() {
return {
username: this.usernameRules,
password: this.passwordRules,
verificationCode: [
{
validator: (rule, value, callback) => {
if (value === '') {
return callback(new Error('验证码不能为空'))
}
if (value.toLowerCase() !== this.verCode.toLowerCase()) {
return callback(new Error('请输入正确的验证码'))
} else {
callback()
}
},
trigger: 'blur'
},
maxSizeValidate
]
}
}
},
mounted() {
if (this.loginForm.username === '') {
this.$refs.username.focus()
}
this.captcha1 = new Captcha()
this.updateCaptcha()
},
methods: {
login() {
this.$refs.form.validate(valid => {
if (valid) {
this.$emit('on-success-valid', {
username: this.loginForm.username,
password: this.loginForm.password
})
} else {
this.updateCaptcha()
}
})
},
updateCaptcha() {
this.captcha1.draw(document.querySelector('#captcha1'), r => {
this.verCode = r
})
}
}
}
</script>
<style lang="scss">
.login-main {
height: 420px;
width: 420px;
display: flex;
flex-flow: column nowrap;
align-items: center;
padding: 0 48px;
box-sizing: border-box;
.title {
width: 292px;
height: 36px;
margin: 32px 0 36px 0;
}
.main-content {
.captcha {
display: flex;
}
.login-btn {
width: 100%;
height: 48px;
.login-btn-text {
font-size: 18px;
}
}
}
}
// 重置输入框 图标
.login-input {
.el-input__prefix {
display: inline-flex;
align-items: center;
}
.el-input__inner {
height: 44px;
width: 324px;
}
}
.captcha-input {
margin-right: 7px;
.el-input__prefix {
display: inline-flex;
align-items: center;
}
.el-input__inner {
height: 44px;
}
}
.login-input,
.captcha-input {
.el-input__inner {
background: #0f1f3b;
padding-left: 46px;
color: rgba(255, 255, 255, 1);
background: rgba(193, 225, 253, 0.03);
border-radius: 4px;
border: 1px solid rgba(24, 144, 255, 0.2);
}
.el-input__inner:active,
.el-input__inner:focus {
background: rgba(193, 225, 253, 0.03);
border-radius: 4px;
border: 1px solid rgba(94, 178, 255, 0.8);
}
.el-input__prefix {
left: 14px;
}
}
.icon {
width: 20px;
height: 20px;
display: inline-block;
}
</style>
import LoginForm from './LoginForm.vue'
export default LoginForm
<template>
<div
class="wrapper"
ref="wrapper"
@mousemove="mousemove"
@mouseenter="mouseenter"
@mouseleave="mouseleave"
@wheel="zoom"
>
<transition name="fade">
<div class="zoomed-container" v-show="isShow">
<div
class="transform-view"
:style="{
transform: `scale(${tempScale}, ${tempScale}) translate(${translateX}%, ${translateY}%)`
}"
>
<img :src="url" alt="" />
</div>
</div>
</transition>
<div class="view">
<img :src="url" alt="" />
</div>
</div>
</template>
<script>
import url from '@/assets/test.jpg'
export default {
props: {
scale: {
type: Number,
default: 2,
validator: val => {
if (val >= 1 && val <= 10) {
return val
} else {
return 1
}
}
}
},
data() {
return {
url,
translateX: 0,
translateY: 0,
tempScale: this.scale,
isShow: false
}
},
methods: {
zoom(e) {
e.preventDefault()
this.tempScale += e.deltaY * -0.01
this.tempScale = Math.min(Math.max(1, this.tempScale), 10)
},
mousemove(e) {
const {
left,
top,
width,
height
} = this.$refs.wrapper.getBoundingClientRect()
const x = e.clientX
const y = e.clientY
const percentW = (x - left) / width
const percentH = (y - top) / height
this.translateX = (0.4 - percentW) * 100
this.translateY = (0.4 - percentH) * 100
},
mouseenter() {
this.isShow = true
},
mouseleave() {
this.isShow = false
}
}
}
</script>
<style lang="scss" scoped>
// 过度效果
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.wrapper {
width: 400px;
height: 357px;
position: relative;
overflow: hidden;
box-sizing: border-box;
.zoomed-container {
background: #000;
position: absolute;
left: 5px;
top: 5px;
right: 5px;
bottom: 5px;
z-index: 9999;
overflow: hidden;
.transform-view {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
text-align: center;
img {
height: 100%;
}
}
}
.view {
position: absolute;
left: 5px;
top: 5px;
right: 5px;
bottom: 5px;
text-align: center;
img {
height: 100%;
}
}
}
</style>
<template lang="pug">
.play-audio
audio(ref="audio" :src="mp3")
</template>
<script>
import mp3 from '@/assets/ding.mp3'
export default {
name: 'PlayAudio',
props: {
mp3: {
type: [String, Blob, null],
default: mp3
}
},
data() {
return {
audioStatus: 'pause',
audioDuration: 0
}
},
methods: {
/**
* 播放提示音
* */
playMusic() {
if (this.audioStatus === 'pause') {
this.$refs.audio.play()
this.audioStatus = 'play'
} else {
this.$refs.audio.pause()
this.$refs.audio.currentTime = 0
this.audioStatus = 'pause'
}
}
},
mounted() {
this.$refs.audio.addEventListener('ended', () => {
this.$refs.audio.pause()
this.audioStatus = 'pause'
})
}
}
</script>
<template lang="pug">
.start-step
el-button(type="primary" icon="el-icon-caret-right" class="btn" v-on="buttonListeners") 开始
</template>
<script>
export default {
computed: {
buttonListeners() {
return Object.assign({}, this.$listeners)
}
}
}
</script>
<style lang="scss" scoped>
.start-step {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background-color: #eee;
.btn {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100px;
height: 70px;
font-size: 23px;
font-weight: 900;
padding: 0 10px;
border-radius: 13px;
box-shadow: 4px 5px 3px;
.el-icon-caret-right {
font-size: 50px;
}
}
}
</style>
<style lang="scss">
.start-step {
.btn {
.el-icon-caret-right {
font-size: 50px;
margin-left: -20px;
}
}
}
</style>
<template lang="pug">
.title-line
.header-wrapper
.left
slot(name="title")
.info
slot(name="info")
.right
slot(name="right")
.main
slot
</template>
<script>
export default {
name: 'TitleLine'
}
</script>
<style lang="scss" scoped>
.title-line{
width: 100%;
font-size: 18px;
.header-wrapper{
color: #fff;
display: flex;
justify-content: flex-start;
align-items: center;
background: #a3add8;
height: 30px;
padding: 5px 10px;
.left{
padding-right: 5px;
}
.right{
flex: auto;
display: flex;
justify-content: flex-end;
}
}
.main{
padding: 10px 5px;
}
}
</style>
<template lang="pug">
.top-tesk-detail
.status-text {{statusText}}
el-switch(
:value="copyValue"
@change="change"
)
template(v-if="isOpen")
.task-info
.over-task.mr5 剩余任务
.mr5 已完成
.already.mr5 {{completed}}
.mr5 待质检
.wait.mr5 {{wait}}
.countDown(v-if="copyCountDownTime !== 0") {{countDownText}}
</template>
<script>
export default {
name: 'TopTeskDetails',
props: {
isOpen: {
type: Boolean,
required: true
},
completed: {
type: [Number, String],
default: 0
},
wait: {
type: [Number, String],
default: 0
},
countDownTime: {
type: Number,
default: 0
}
},
data() {
return {
timer: null, // 计时器
second: this.timeout, // 倒计时时间
copyValue: this.isOpen,
copyCountDownTime: this.countDownTime
}
},
computed: {
statusText() {
return this.isOpen ? '进行中' : '开始'
},
countDownText() {
return this.copyCountDownTime === 0 ? '-' : this.copyCountDownTime
}
},
watch: {
isOpen: {
handler(val) {
if (val && this.copyCountDownTime) {
this.startTimeout()
}
},
immediate: true
}
},
methods: {
startTimeout() {
setTimeout(this.nextSecond, 1000)
},
nextSecond() {
this.copyCountDownTime--
if (this.copyCountDownTime === 0) {
this.$emit('update:isOpen', false)
return
}
setTimeout(this.nextSecond, 1000)
},
change(val) {
this.$nextTick(() => {
this.$emit('update:isOpen', val)
})
}
}
}
</script>
<style lang="scss" scoped>
.top-tesk-detail {
height: 35px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
.status-text {
width: 70px;
text-align: center;
font-size: 16px;
color: #333;
font-weight: 600;
}
.task-info {
margin: 0 5px;
font-size: 14px;
display: flex;
align-items: center;
.over-task {
font-weight: 500;
}
.already {
padding: 0 5px;
border-radius: 3px;
background-color: #52c3f1;
}
.wait {
padding: 0 5px;
border-radius: 3px;
background-color: #f19b12;
}
}
/* 倒计时*/
.countDown {
width: 35px;
height: 35px;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
border-radius: 50%;
border: 3px solid #3f51b5;
box-sizing: border-box;
}
}
</style>
<template>
<div class="upload-wrapper">
<label>{{ placeholderCopy }}</label>
<div class="uw-right">
<el-button class="uw-btn">
<slot></slot>
</el-button>
<input
class="uw-input"
type="file"
id="image_uploads"
name="image_uploads"
:accept="accept"
:multiple="multiple"
@change="handleChange"
/>
</div>
</div>
</template>
<script>
export default {
props: {
placeholder: {
type: String,
default: '上传图片,可多选'
},
accept: {
type: String,
default: '.jpg, .jpeg, .png, .JPG, .JPEG, .PNG, .bmp, .BMP'
},
multiple: {
type: Boolean,
default: false
},
onExceed: {
type: Function,
default: () => {}
},
limit: {
type: Number
},
onChange: {
type: Function,
default: () => {}
}
},
data() {
return {
placeholderCopy: this.placeholder
}
},
methods: {
handleChange(e) {
const files = e.currentTarget.files
const length = files.length
if (!this.isValidator(files)) {
this.$emit('onFail', files)
return
}
if (this.limit && length > this.limit) {
this.onExceed()
return
}
if (files.length > 0) {
this.placeholderCopy = files[0].name
this.onChange(Array.from(files))
}
},
getAcceptType() {
const arr = this.accept
.toLowerCase()
.split(',')
.map(item => `image/${item.slice(item.indexOf('.') + 1)}`)
return Array.from(new Set(arr))
},
isValidator(files) {
return Array.from(files).every(file =>
this.getAcceptType().includes(file.type)
)
}
},
mounted() {
this.getAcceptType()
}
}
</script>
<style lang="scss" scoped>
.upload-wrapper {
width: 300px;
height: 42px;
background: #f2f2f2;
display: inline-block;
position: relative;
label {
font-size: 12px;
line-height: 42px;
width: 100%;
display: inline-block;
height: 100%;
overflow: hidden;
}
.uw-right {
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 70px;
}
input {
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
}
</style>
/* eslint-disable */
const Exif = {}
Exif.getData = img =>
new Promise((reslove, reject) => {
let obj = {}
getImageData(img)
.then(data => {
obj.arrayBuffer = data
obj.orientation = getOrientation(data)
reslove(obj)
})
.catch(error => {
reject(error)
})
})
// 这里的获取exif要将图片转ArrayBuffer对象,这里假设获取了图片的baes64
// 步骤一
// base64转ArrayBuffer对象
function getImageData(img) {
let data = null
return new Promise((reslove, reject) => {
if (img.src) {
if (/^data\:/i.test(img.src)) {
// Data URI
data = base64ToArrayBuffer(img.src)
reslove(data)
} else if (/^blob\:/i.test(img.src)) {
// Object URL
var fileReader = new FileReader()
fileReader.onload = function(e) {
data = e.target.result
reslove(data)
}
objectURLToBlob(img.src, function(blob) {
fileReader.readAsArrayBuffer(blob)
})
} else {
var http = new XMLHttpRequest()
http.onload = function() {
if (this.status == 200 || this.status === 0) {
data = http.response
reslove(data)
} else {
throw 'Could not load image'
}
http = null
}
http.open('GET', img.src, true)
http.responseType = 'arraybuffer'
http.send(null)
}
} else {
reject('img error')
}
})
}
function objectURLToBlob(url, callback) {
var http = new XMLHttpRequest()
http.open('GET', url, true)
http.responseType = 'blob'
http.onload = function(e) {
if (this.status == 200 || this.status === 0) {
callback(this.response)
}
}
http.send()
}
function base64ToArrayBuffer(base64) {
base64 = base64.replace(/^data\:([^\;]+)\;base64,/gim, '')
var binary = atob(base64)
var len = binary.length
var buffer = new ArrayBuffer(len)
var view = new Uint8Array(buffer)
for (var i = 0; i < len; i++) {
view[i] = binary.charCodeAt(i)
}
return buffer
}
// 步骤二,Unicode码转字符串
// ArrayBuffer对象 Unicode码转字符串
function getStringFromCharCode(dataView, start, length) {
var str = ''
var i
for (i = start, length += start; i < length; i++) {
str += String.fromCharCode(dataView.getUint8(i))
}
return str
}
// 步骤三,获取jpg图片的exif的角度(在ios体现最明显)
function getOrientation(arrayBuffer) {
var dataView = new DataView(arrayBuffer)
var length = dataView.byteLength
var orientation
var exifIDCode
var tiffOffset
var firstIFDOffset
var littleEndian
var endianness
var app1Start
var ifdStart
var offset
var i
// Only handle JPEG image (start by 0xFFD8)
if (dataView.getUint8(0) === 0xff && dataView.getUint8(1) === 0xd8) {
offset = 2
while (offset < length) {
if (
dataView.getUint8(offset) === 0xff &&
dataView.getUint8(offset + 1) === 0xe1
) {
app1Start = offset
break
}
offset++
}
}
if (app1Start) {
exifIDCode = app1Start + 4
tiffOffset = app1Start + 10
if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
endianness = dataView.getUint16(tiffOffset)
littleEndian = endianness === 0x4949
if (littleEndian || endianness === 0x4d4d /* bigEndian */) {
if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002a) {
firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian)
if (firstIFDOffset >= 0x00000008) {
ifdStart = tiffOffset + firstIFDOffset
}
}
}
}
}
if (ifdStart) {
length = dataView.getUint16(ifdStart, littleEndian)
for (i = 0; i < length; i++) {
offset = ifdStart + i * 12 + 2
if (
dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */
) {
// 8 is the offset of the current tag's value
offset += 8
// Get the original orientation value
orientation = dataView.getUint16(offset, littleEndian)
// Override the orientation with its default value for Safari (#120)
// if (IS_SAFARI_OR_UIWEBVIEW) {
// dataView.setUint16(offset, 1, littleEndian);
// }
break
}
}
}
return orientation
}
export default Exif
import VueCropper from './vueCropper.vue'
export default VueCropper
import permission from './permission'
const install = function(Vue) {
Vue.directive('permission', permission)
}
if (window.Vue) {
window['permission'] = permission
Vue.use(install) // eslint-disable-line
}
permission.install = install
export default permission
import store from '@/store'
export default {
inserted(el, binding, vnode) {
const { value } = binding
const roles = store.state.roles
if (value && value instanceof Array && value.length > 0) {
const permissionRoles = value
const hasPermission = roles.some(role => {
return permissionRoles.includes(role)
})
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`need roles! Like v-permission="['factory','normal']"`)
}
}
}
/* 改变主题色变量 */
$--color-primary: #409eff;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import '~element-ui/packages/theme-chalk/src/index';
import Vue from 'vue'
import SvgIcon from '@/components/iconComponent'
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>账号管理-白</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-23.000000, -131.000000)">
<g id="编组-4" transform="translate(23.000000, 131.000000)">
<g id="账号管理" fill="#FFFFFF" fill-rule="nonzero">
<path d="M10.2230216,8.05755396 C9.4851496,8.02906906 8.80393552,8.45160855 8.50160716,9.12530285 C8.19927879,9.79899715 8.33644267,10.5887935 8.84821755,11.1211026 C9.35999242,11.6534116 10.1437849,11.8215235 10.8288455,11.545918 C11.5139061,11.2703125 11.9629036,10.6062391 11.9634532,9.86781775 C11.9494922,9.39289432 11.7753247,8.93665107 11.4692566,8.57323741 C11.129455,8.25694548 10.6869616,8.07384474 10.2230216,8.05755396 L10.2230216,8.05755396 Z M10.2230216,10.6467146 C9.81930162,10.6131005 9.50875278,10.2756205 9.50875278,9.8705036 C9.50875278,9.46538668 9.81930162,9.12790668 10.2230216,9.09429257 C10.4178006,9.11007026 10.6040891,9.18085988 10.7601918,9.29841727 C10.9065942,9.44997563 10.9792327,9.65807506 10.9589448,9.86781775 C10.9431396,10.2702783 10.6250454,10.595338 10.2230216,10.6198561 L10.2230216,10.6467146 Z" id="形状"></path>
<path d="M13.7790887,8.96 C13.3974741,8.86313379 13.0711026,8.61635671 12.873916,8.27557784 C12.6767294,7.93479897 12.625418,7.52886251 12.7316067,7.14973621 C12.7397811,7.07569471 12.7206831,7.00121265 12.6778897,6.94023981 C12.331848,6.62256644 11.9266321,6.37615136 11.4853717,6.21505995 C11.4130369,6.20722007 11.340353,6.22634744 11.281247,6.26877698 C11.0209363,6.57522731 10.6357013,6.7471014 10.233765,6.73611511 C9.83422948,6.73546094 9.45365256,6.56566509 9.18628297,6.26877698 C9.12953599,6.225711 9.05824525,6.20644323 8.98752998,6.21505995 C8.54460609,6.37602801 8.13760745,6.62241732 7.78964029,6.94023981 C7.72248855,6.98754531 7.70166323,7.07778837 7.74129496,7.14973621 C7.84086816,7.53447 7.78693155,7.94284719 7.59088729,8.28853717 C7.40923551,8.63687962 7.07923085,8.88388909 6.69381295,8.96 C6.64546763,8.96 6.5971223,9.01371703 6.54340528,9.11577938 C6.44660599,9.59438721 6.44660599,10.0875313 6.54340528,10.5661391 C6.54340528,10.6198561 6.5971223,10.6682014 6.69381295,10.7219185 C7.07608824,10.8050007 7.40343248,11.0500189 7.59088729,11.3933813 C7.78725971,11.7409174 7.84117696,12.1510736 7.74129496,12.537554 C7.73460668,12.6090549 7.75159257,12.6807731 7.78964029,12.7416787 C8.13760745,13.0595011 8.54460609,13.3058905 8.98752998,13.4668585 L9.041247,13.4668585 C9.0944142,13.4734903 9.14772828,13.4557189 9.18628297,13.4185132 C9.44559503,13.1168804 9.82528379,12.9457254 10.2230216,12.9511751 C10.634041,12.9446659 11.0270554,13.1195573 11.2973621,13.4292566 C11.3510791,13.4776019 11.3994245,13.4776019 11.5014868,13.4776019 C11.9427472,13.3165105 12.3479631,13.0700954 12.6940048,12.7524221 C12.7477218,12.698705 12.7960671,12.6503597 12.7477218,12.5482974 C12.6182907,12.1794361 12.6506553,11.7730677 12.8368394,11.4293432 C13.0230235,11.0856187 13.3457101,10.8365079 13.7253717,10.7434053 C13.7790887,10.7434053 13.8274341,10.6896882 13.8757794,10.5876259 C13.9779384,10.1095695 13.9779384,9.61532259 13.8757794,9.13726619 C13.8757794,9.06743405 13.8274341,9.01371703 13.7790887,8.96 Z M12.9088729,10.2545803 C12.5570203,10.3738745 12.2571941,10.6110788 12.0601439,10.9260432 C11.8674513,11.2354631 11.812917,11.6113602 11.9097362,11.9627818 C11.6995825,12.1612408 11.4427762,12.3035004 11.1630695,12.3764029 C10.9001251,12.1084012 10.539367,11.9590551 10.1639329,11.9627818 C9.79228538,11.9773991 9.4380279,12.124054 9.16479616,12.3764029 C8.90552032,12.2581748 8.65587259,12.1198807 8.4181295,11.9627818 C8.52125061,11.6117806 8.46633703,11.2332691 8.26772182,10.9260432 C8.07378679,10.6083049 7.77282806,10.3702047 7.41899281,10.2545803 C7.37050545,9.96292879 7.37050545,9.66527265 7.41899281,9.3736211 C7.78078559,9.26252636 8.0899869,9.0239451 8.28920863,8.70215827 C8.48447126,8.39368341 8.53916815,8.01666554 8.43961631,7.66541966 C8.65057904,7.46806986 8.90708761,7.32597519 9.18628297,7.25179856 C9.44922742,7.51980025 9.80998552,7.66914635 10.1854197,7.66541966 C10.5570671,7.65080237 10.9113246,7.50414739 11.1845564,7.25179856 C11.4444148,7.36886747 11.6941537,7.50721202 11.931223,7.66541966 C11.8309713,8.01661891 11.8857103,8.393927 12.0816307,8.70215827 C12.2702379,9.01594747 12.5630021,9.25358071 12.9088729,9.3736211 C12.9573603,9.66527265 12.9573603,9.96292879 12.9088729,10.2545803 L12.9088729,10.2545803 Z M1.51545602,10.8776978 L2.50925659,10.8776978 C2.485191,9.19597558 3.81990192,7.80854717 5.50129496,7.76748201 C5.95305398,7.76791383 6.39837238,7.87464303 6.801247,8.07904077 C6.98750594,7.78214723 7.20348599,7.50497283 7.44585132,7.25179856 C7.35677722,7.2113638 7.27364289,7.15895303 7.198753,7.09601918 C7.74475372,6.60874162 8.06220635,5.9154095 8.07434053,5.18369305 C8.07434053,4.29321926 7.59927844,3.47038755 6.82810553,3.02515066 C6.05693261,2.57991376 5.1068084,2.57991376 4.33563548,3.02515066 C3.56446257,3.47038755 3.08940047,4.29321926 3.08940048,5.18369305 C3.0690725,5.91658356 3.38100313,6.61941459 3.9381295,7.09601918 C2.45694705,7.77021525 1.50876239,9.25030837 1.51545602,10.8776978 L1.51545602,10.8776978 Z M5.50129496,3.63125663 C5.90873661,3.62948611 6.2992156,3.79426079 6.58220695,4.08739519 C6.86519829,4.3805296 7.01612586,4.77656673 7,5.18369305 C7.03332384,5.73956249 6.75569599,6.26807752 6.27908764,6.55608065 C5.80247929,6.84408378 5.20548234,6.84408378 4.72887399,6.55608065 C4.25226564,6.26807752 3.97463779,5.73956249 4.00796163,5.18369305 C3.99340666,4.7779193 4.14411589,4.38360482 4.42560278,4.09097996 C4.70708967,3.7983551 5.09526202,3.63246535 5.50129496,3.63125663 L5.50129496,3.63125663 Z" id="形状"></path>
<path d="M12.978705,0 L1.01592326,0 C0.74521743,0.00563905362 0.487846369,0.118615445 0.30045916,0.314062318 C0.113071952,0.509509191 0.0110275373,0.771407006 0.0167865707,1.04211031 L0.0167865707,11.3933813 C0.0077943878,11.9550253 0.454330229,12.4183663 1.01592326,12.4301199 L6.24796163,12.4301199 C6.15347803,12.0905554 6.08700419,11.7438135 6.04920863,11.3933813 L1.51549161,11.3933813 C1.23359784,11.3736011 1.01523013,11.1387971 1.01592326,10.856211 L1.01592326,1.55779376 C1.01523013,1.27520772 1.23359784,1.04040373 1.51549161,1.0206235 L12.4791367,1.0206235 C12.7610305,1.04040373 12.9793982,1.27520772 12.978705,1.55779376 L12.978705,6.1129976 C13.3416127,6.27160518 13.6798936,6.48144788 13.9832134,6.73611511 L13.9832134,1.04211031 C13.9889659,0.770492956 13.8861881,0.507791018 13.6976439,0.312188988 C13.5090997,0.116586957 13.2503504,0.00422874936 12.978705,0 Z" id="路径"></path>
<path d="M9.48709832,3.63127098 L11.9795683,3.63127098 C12.1204387,3.63685572 12.2567289,3.58067135 12.3527387,3.47743498 C12.4487485,3.37419862 12.4949119,3.23419632 12.4791367,3.09410072 C12.4968375,2.95359324 12.4513335,2.81246879 12.3548898,2.70876591 C12.2584461,2.60506303 12.120989,2.54945504 11.9795683,2.55693046 L9.48709832,2.55693046 C9.34659209,2.55109685 9.21064377,2.60742026 9.11543115,2.71091224 C9.02021852,2.81440422 8.97539973,2.9545668 8.99290168,3.09410072 C8.97728866,3.23323418 9.02275873,3.37230344 9.1175512,3.47533874 C9.21234368,3.57837404 9.3471483,3.63525552 9.48709832,3.63127098 L9.48709832,3.63127098 Z M9.48709832,5.6993765 L10.9858034,5.6993765 C11.1266737,5.70496124 11.2629639,5.64877687 11.3589737,5.5455405 C11.4549835,5.44230413 11.5011469,5.30230183 11.4853717,5.16220624 C11.5011469,5.02211064 11.4549835,4.88210834 11.3589737,4.77887197 C11.2629639,4.6756356 11.1266737,4.61945123 10.9858034,4.62503597 L9.48709832,4.62503597 C9.3471483,4.62105144 9.21234368,4.67793291 9.1175512,4.78096821 C9.02275873,4.88400351 8.97728866,5.02307277 8.99290168,5.16220624 C8.97539973,5.30174015 9.02021852,5.44190273 9.11543115,5.54539471 C9.21064377,5.64888669 9.34659209,5.70521011 9.48709832,5.6993765 L9.48709832,5.6993765 Z" id="形状"></path>
</g>
<rect id="账号管理-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>账号管理-灰</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-57.000000, -131.000000)">
<g id="编组-4" transform="translate(57.000000, 131.000000)">
<g id="账号管理" fill="#A6ADB4" fill-rule="nonzero">
<path d="M10.2230216,8.05755396 C9.4851496,8.02906906 8.80393552,8.45160855 8.50160716,9.12530285 C8.19927879,9.79899715 8.33644267,10.5887935 8.84821755,11.1211026 C9.35999242,11.6534116 10.1437849,11.8215235 10.8288455,11.545918 C11.5139061,11.2703125 11.9629036,10.6062391 11.9634532,9.86781775 C11.9494922,9.39289432 11.7753247,8.93665107 11.4692566,8.57323741 C11.129455,8.25694548 10.6869616,8.07384474 10.2230216,8.05755396 L10.2230216,8.05755396 Z M10.2230216,10.6467146 C9.81930162,10.6131005 9.50875278,10.2756205 9.50875278,9.8705036 C9.50875278,9.46538668 9.81930162,9.12790668 10.2230216,9.09429257 C10.4178006,9.11007026 10.6040891,9.18085988 10.7601918,9.29841727 C10.9065942,9.44997563 10.9792327,9.65807506 10.9589448,9.86781775 C10.9431396,10.2702783 10.6250454,10.595338 10.2230216,10.6198561 L10.2230216,10.6467146 Z" id="形状"></path>
<path d="M13.7790887,8.96 C13.3974741,8.86313379 13.0711026,8.61635671 12.873916,8.27557784 C12.6767294,7.93479897 12.625418,7.52886251 12.7316067,7.14973621 C12.7397811,7.07569471 12.7206831,7.00121265 12.6778897,6.94023981 C12.331848,6.62256644 11.9266321,6.37615136 11.4853717,6.21505995 C11.4130369,6.20722007 11.340353,6.22634744 11.281247,6.26877698 C11.0209363,6.57522731 10.6357013,6.7471014 10.233765,6.73611511 C9.83422948,6.73546094 9.45365256,6.56566509 9.18628297,6.26877698 C9.12953599,6.225711 9.05824525,6.20644323 8.98752998,6.21505995 C8.54460609,6.37602801 8.13760745,6.62241732 7.78964029,6.94023981 C7.72248855,6.98754531 7.70166323,7.07778837 7.74129496,7.14973621 C7.84086816,7.53447 7.78693155,7.94284719 7.59088729,8.28853717 C7.40923551,8.63687962 7.07923085,8.88388909 6.69381295,8.96 C6.64546763,8.96 6.5971223,9.01371703 6.54340528,9.11577938 C6.44660599,9.59438721 6.44660599,10.0875313 6.54340528,10.5661391 C6.54340528,10.6198561 6.5971223,10.6682014 6.69381295,10.7219185 C7.07608824,10.8050007 7.40343248,11.0500189 7.59088729,11.3933813 C7.78725971,11.7409174 7.84117696,12.1510736 7.74129496,12.537554 C7.73460668,12.6090549 7.75159257,12.6807731 7.78964029,12.7416787 C8.13760745,13.0595011 8.54460609,13.3058905 8.98752998,13.4668585 L9.041247,13.4668585 C9.0944142,13.4734903 9.14772828,13.4557189 9.18628297,13.4185132 C9.44559503,13.1168804 9.82528379,12.9457254 10.2230216,12.9511751 C10.634041,12.9446659 11.0270554,13.1195573 11.2973621,13.4292566 C11.3510791,13.4776019 11.3994245,13.4776019 11.5014868,13.4776019 C11.9427472,13.3165105 12.3479631,13.0700954 12.6940048,12.7524221 C12.7477218,12.698705 12.7960671,12.6503597 12.7477218,12.5482974 C12.6182907,12.1794361 12.6506553,11.7730677 12.8368394,11.4293432 C13.0230235,11.0856187 13.3457101,10.8365079 13.7253717,10.7434053 C13.7790887,10.7434053 13.8274341,10.6896882 13.8757794,10.5876259 C13.9779384,10.1095695 13.9779384,9.61532259 13.8757794,9.13726619 C13.8757794,9.06743405 13.8274341,9.01371703 13.7790887,8.96 Z M12.9088729,10.2545803 C12.5570203,10.3738745 12.2571941,10.6110788 12.0601439,10.9260432 C11.8674513,11.2354631 11.812917,11.6113602 11.9097362,11.9627818 C11.6995825,12.1612408 11.4427762,12.3035004 11.1630695,12.3764029 C10.9001251,12.1084012 10.539367,11.9590551 10.1639329,11.9627818 C9.79228538,11.9773991 9.4380279,12.124054 9.16479616,12.3764029 C8.90552032,12.2581748 8.65587259,12.1198807 8.4181295,11.9627818 C8.52125061,11.6117806 8.46633703,11.2332691 8.26772182,10.9260432 C8.07378679,10.6083049 7.77282806,10.3702047 7.41899281,10.2545803 C7.37050545,9.96292879 7.37050545,9.66527265 7.41899281,9.3736211 C7.78078559,9.26252636 8.0899869,9.0239451 8.28920863,8.70215827 C8.48447126,8.39368341 8.53916815,8.01666554 8.43961631,7.66541966 C8.65057904,7.46806986 8.90708761,7.32597519 9.18628297,7.25179856 C9.44922742,7.51980025 9.80998552,7.66914635 10.1854197,7.66541966 C10.5570671,7.65080237 10.9113246,7.50414739 11.1845564,7.25179856 C11.4444148,7.36886747 11.6941537,7.50721202 11.931223,7.66541966 C11.8309713,8.01661891 11.8857103,8.393927 12.0816307,8.70215827 C12.2702379,9.01594747 12.5630021,9.25358071 12.9088729,9.3736211 C12.9573603,9.66527265 12.9573603,9.96292879 12.9088729,10.2545803 L12.9088729,10.2545803 Z M1.51545602,10.8776978 L2.50925659,10.8776978 C2.485191,9.19597558 3.81990192,7.80854717 5.50129496,7.76748201 C5.95305398,7.76791383 6.39837238,7.87464303 6.801247,8.07904077 C6.98750594,7.78214723 7.20348599,7.50497283 7.44585132,7.25179856 C7.35677722,7.2113638 7.27364289,7.15895303 7.198753,7.09601918 C7.74475372,6.60874162 8.06220635,5.9154095 8.07434053,5.18369305 C8.07434053,4.29321926 7.59927844,3.47038755 6.82810553,3.02515066 C6.05693261,2.57991376 5.1068084,2.57991376 4.33563548,3.02515066 C3.56446257,3.47038755 3.08940047,4.29321926 3.08940048,5.18369305 C3.0690725,5.91658356 3.38100313,6.61941459 3.9381295,7.09601918 C2.45694705,7.77021525 1.50876239,9.25030837 1.51545602,10.8776978 L1.51545602,10.8776978 Z M5.50129496,3.63125663 C5.90873661,3.62948611 6.2992156,3.79426079 6.58220695,4.08739519 C6.86519829,4.3805296 7.01612586,4.77656673 7,5.18369305 C7.03332384,5.73956249 6.75569599,6.26807752 6.27908764,6.55608065 C5.80247929,6.84408378 5.20548234,6.84408378 4.72887399,6.55608065 C4.25226564,6.26807752 3.97463779,5.73956249 4.00796163,5.18369305 C3.99340666,4.7779193 4.14411589,4.38360482 4.42560278,4.09097996 C4.70708967,3.7983551 5.09526202,3.63246535 5.50129496,3.63125663 L5.50129496,3.63125663 Z" id="形状"></path>
<path d="M12.978705,0 L1.01592326,0 C0.74521743,0.00563905362 0.487846369,0.118615445 0.30045916,0.314062318 C0.113071952,0.509509191 0.0110275373,0.771407006 0.0167865707,1.04211031 L0.0167865707,11.3933813 C0.0077943878,11.9550253 0.454330229,12.4183663 1.01592326,12.4301199 L6.24796163,12.4301199 C6.15347803,12.0905554 6.08700419,11.7438135 6.04920863,11.3933813 L1.51549161,11.3933813 C1.23359784,11.3736011 1.01523013,11.1387971 1.01592326,10.856211 L1.01592326,1.55779376 C1.01523013,1.27520772 1.23359784,1.04040373 1.51549161,1.0206235 L12.4791367,1.0206235 C12.7610305,1.04040373 12.9793982,1.27520772 12.978705,1.55779376 L12.978705,6.1129976 C13.3416127,6.27160518 13.6798936,6.48144788 13.9832134,6.73611511 L13.9832134,1.04211031 C13.9889659,0.770492956 13.8861881,0.507791018 13.6976439,0.312188988 C13.5090997,0.116586957 13.2503504,0.00422874936 12.978705,0 Z" id="路径"></path>
<path d="M9.48709832,3.63127098 L11.9795683,3.63127098 C12.1204387,3.63685572 12.2567289,3.58067135 12.3527387,3.47743498 C12.4487485,3.37419862 12.4949119,3.23419632 12.4791367,3.09410072 C12.4968375,2.95359324 12.4513335,2.81246879 12.3548898,2.70876591 C12.2584461,2.60506303 12.120989,2.54945504 11.9795683,2.55693046 L9.48709832,2.55693046 C9.34659209,2.55109685 9.21064377,2.60742026 9.11543115,2.71091224 C9.02021852,2.81440422 8.97539973,2.9545668 8.99290168,3.09410072 C8.97728866,3.23323418 9.02275873,3.37230344 9.1175512,3.47533874 C9.21234368,3.57837404 9.3471483,3.63525552 9.48709832,3.63127098 L9.48709832,3.63127098 Z M9.48709832,5.6993765 L10.9858034,5.6993765 C11.1266737,5.70496124 11.2629639,5.64877687 11.3589737,5.5455405 C11.4549835,5.44230413 11.5011469,5.30230183 11.4853717,5.16220624 C11.5011469,5.02211064 11.4549835,4.88210834 11.3589737,4.77887197 C11.2629639,4.6756356 11.1266737,4.61945123 10.9858034,4.62503597 L9.48709832,4.62503597 C9.3471483,4.62105144 9.21234368,4.67793291 9.1175512,4.78096821 C9.02275873,4.88400351 8.97728866,5.02307277 8.99290168,5.16220624 C8.97539973,5.30174015 9.02021852,5.44190273 9.11543115,5.54539471 C9.21064377,5.64888669 9.34659209,5.70521011 9.48709832,5.6993765 L9.48709832,5.6993765 Z" id="形状"></path>
</g>
<rect id="账号管理-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>首页-白</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-23.000000, -263.000000)">
<g id="编组" transform="translate(23.000000, 263.000000)">
<path d="M13.8237634,5.9772172 L7.90871505,1.30222645 C7.39952808,0.899009055 6.60060637,0.899506723 6.09185284,1.30222645 L0.177318171,5.9772172 C-0.0247159515,6.1373194 -0.0592632085,6.43084278 0.100325266,6.6328769 C0.259913757,6.83497523 0.54696755,6.86952251 0.749081932,6.70995006 L0.933376855,6.55869338 L0.933376855,12.2114426 C0.933376855,13.0127402 1.77769805,13.6115061 2.52014332,13.6115061 L11.8542158,13.6115061 C12.5879118,13.6115061 13.0676887,13.0487002 13.0676887,12.2114426 L13.0676887,6.58062254 L13.238017,6.70995006 C13.3239196,6.77759978 13.4293755,6.81028485 13.5306414,6.81028485 C13.6683007,6.81028485 13.8064577,6.74961843 13.8983804,6.6328769 C14.0584826,6.43084278 14.0262952,6.1373194 13.8237634,5.9772172 L13.8237634,5.9772172 Z M6.53379144,12.6781036 L6.53379144,10.0907185 C6.53379144,9.96193677 6.76716211,9.89754593 7.00053278,9.89754593 C7.23390345,9.89754593 7.46725807,9.96193677 7.46725807,10.0907185 L7.46725807,12.6781036 L6.53379144,12.6781036 L6.53379144,12.6781036 Z M12.1342863,12.2114265 C12.1342863,12.5208429 12.0488331,12.6781036 11.8542158,12.6781036 L8.40997157,12.6781036 C8.40997157,12.6711043 8.40064444,12.6655176 8.40064444,12.6585344 L8.40064444,10.0907185 C8.40064444,9.54794743 7.96289584,8.96361372 7.00053278,8.96361372 C6.03821788,8.96361372 5.60040506,9.54794743 5.60040506,10.0907185 L5.60040506,12.6585504 C5.60040506,12.6655337 5.61302317,12.6711203 5.61302317,12.6781036 L2.52014335,12.6781036 C2.22755107,12.6781036 1.86676326,12.4251637 1.86676326,12.2114426 L1.86676326,5.82083943 L6.66405007,2.03452587 C6.8362406,1.89821505 7.14706974,1.89821505 7.31977399,2.03452587 L12.1342863,5.84276861 L12.1342863,12.2114265 L12.1342863,12.2114265 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero"></path>
<rect id="首页-白" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>首页-灰</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-57.000000, -263.000000)">
<g id="编组" transform="translate(57.000000, 263.000000)">
<path d="M13.8237634,5.9772172 L7.90871505,1.30222645 C7.39952808,0.899009055 6.60060637,0.899506723 6.09185284,1.30222645 L0.177318171,5.9772172 C-0.0247159515,6.1373194 -0.0592632085,6.43084278 0.100325266,6.6328769 C0.259913757,6.83497523 0.54696755,6.86952251 0.749081932,6.70995006 L0.933376855,6.55869338 L0.933376855,12.2114426 C0.933376855,13.0127402 1.77769805,13.6115061 2.52014332,13.6115061 L11.8542158,13.6115061 C12.5879118,13.6115061 13.0676887,13.0487002 13.0676887,12.2114426 L13.0676887,6.58062254 L13.238017,6.70995006 C13.3239196,6.77759978 13.4293755,6.81028485 13.5306414,6.81028485 C13.6683007,6.81028485 13.8064577,6.74961843 13.8983804,6.6328769 C14.0584826,6.43084278 14.0262952,6.1373194 13.8237634,5.9772172 L13.8237634,5.9772172 Z M6.53379144,12.6781036 L6.53379144,10.0907185 C6.53379144,9.96193677 6.76716211,9.89754593 7.00053278,9.89754593 C7.23390345,9.89754593 7.46725807,9.96193677 7.46725807,10.0907185 L7.46725807,12.6781036 L6.53379144,12.6781036 L6.53379144,12.6781036 Z M12.1342863,12.2114265 C12.1342863,12.5208429 12.0488331,12.6781036 11.8542158,12.6781036 L8.40997157,12.6781036 C8.40997157,12.6711043 8.40064444,12.6655176 8.40064444,12.6585344 L8.40064444,10.0907185 C8.40064444,9.54794743 7.96289584,8.96361372 7.00053278,8.96361372 C6.03821788,8.96361372 5.60040506,9.54794743 5.60040506,10.0907185 L5.60040506,12.6585504 C5.60040506,12.6655337 5.61302317,12.6711203 5.61302317,12.6781036 L2.52014335,12.6781036 C2.22755107,12.6781036 1.86676326,12.4251637 1.86676326,12.2114426 L1.86676326,5.82083943 L6.66405007,2.03452587 C6.8362406,1.89821505 7.14706974,1.89821505 7.31977399,2.03452587 L12.1342863,5.84276861 L12.1342863,12.2114265 L12.1342863,12.2114265 Z" id="形状" fill="#A6ADB4" fill-rule="nonzero"></path>
<rect id="首页-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>角色权限-白</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-23.000000, -87.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="角色权限-白" transform="translate(23.000000, 87.000000)">
<path d="M11.6451085,6.69136043 C10.6179505,6.69136043 9.78247041,7.52752414 9.78247043,8.55563911 C9.78247043,9.02540014 9.95828902,9.45387252 10.2458057,9.78213104 L9.2224759,10.8062812 L8.6996685,10.2863449 C8.5089477,10.0974014 8.20188039,10.0983584 8.01252677,10.2885323 C7.82344659,10.4791164 7.82467704,10.787004 8.01471424,10.9763577 L8.53533417,11.4941065 L8.02633523,12.0035156 L6.91058441,10.8868078 C6.72082064,10.6969073 6.41347988,10.6969073 6.22371612,10.8868078 C6.03395235,11.0767082 6.03395235,11.3843224 6.22371612,11.5742229 L7.33946694,12.6909308 L6.86068255,13.1701253 C6.67091879,13.3600258 6.67091879,13.66764 6.86068255,13.8575405 C6.95556444,13.9525591 7.07984056,14 7.20411669,14 C7.32839282,14 7.45266895,13.9525591 7.54755084,13.8575405 L11.0729461,10.3290007 C11.2534131,10.387379 11.4453643,10.4197811 11.6449718,10.4197811 C12.6721297,10.4197811 13.5076098,9.58361734 13.5076098,8.55550239 C13.5076098,7.52738744 12.6722664,6.69136043 11.6451085,6.69136043 L11.6451085,6.69136043 Z M11.6451085,9.4474468 C11.1536094,9.4474468 10.7539844,9.04741165 10.7539844,8.55550239 C10.7539844,8.06359313 11.1537461,7.66355797 11.6451085,7.66355797 C12.1366076,7.66355797 12.5362326,8.06359313 12.5362326,8.55550239 C12.5362326,9.04741165 12.1364709,9.4474468 11.6451085,9.4474468 Z" id="形状"></path>
<path d="M5.08841471,13.0200096 L0.992497666,13.0200096 C1.23722184,10.1929669 3.59395664,7.96789094 6.45558885,7.96789094 C6.51752184,7.96789094 6.57631033,7.95517622 6.63086058,7.93398502 C8.7374025,7.84060703 10.4238118,6.09062412 10.4238118,3.94703177 C10.4238118,1.77049052 8.64361436,0 6.45558885,0 C4.26770006,0 2.48763931,1.77049052 2.48763931,3.94689505 C2.48763931,5.38393181 3.24737798,6.64241561 4.38117552,7.346647 C1.8374113,8.22081816 6.5953125e-05,10.648646 6.5953125e-05,13.50604 C6.5953125e-05,13.7744163 0.217583365,13.9922071 0.485822928,13.9922071 L5.08841471,13.9922071 C5.35665427,13.9922071 5.57417168,13.7744163 5.57417168,13.50604 C5.57417168,13.2376637 5.35665427,13.0200096 5.08841471,13.0200096 Z M3.45915326,3.94689505 C3.45915326,2.30669623 4.80322217,0.972334248 6.45558885,0.972334248 C8.10795553,0.972334248 9.45229787,2.30669622 9.45229787,3.94689505 C9.45229787,5.61430064 8.10795553,6.9705374 6.45558885,6.9705374 C4.80322217,6.9705374 3.45915326,5.61430064 3.45915326,3.94689505 Z" id="形状"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>角色权限-灰</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-57.000000, -87.000000)" fill="#A6ADB4" fill-rule="nonzero">
<g id="角色权限-灰" transform="translate(57.000000, 87.000000)">
<path d="M11.6451085,6.69136043 C10.6179505,6.69136043 9.78247041,7.52752414 9.78247043,8.55563911 C9.78247043,9.02540014 9.95828902,9.45387252 10.2458057,9.78213104 L9.2224759,10.8062812 L8.6996685,10.2863449 C8.5089477,10.0974014 8.20188039,10.0983584 8.01252677,10.2885323 C7.82344659,10.4791164 7.82467704,10.787004 8.01471424,10.9763577 L8.53533417,11.4941065 L8.02633523,12.0035156 L6.91058441,10.8868078 C6.72082064,10.6969073 6.41347988,10.6969073 6.22371612,10.8868078 C6.03395235,11.0767082 6.03395235,11.3843224 6.22371612,11.5742229 L7.33946694,12.6909308 L6.86068255,13.1701253 C6.67091879,13.3600258 6.67091879,13.66764 6.86068255,13.8575405 C6.95556444,13.9525591 7.07984056,14 7.20411669,14 C7.32839282,14 7.45266895,13.9525591 7.54755084,13.8575405 L11.0729461,10.3290007 C11.2534131,10.387379 11.4453643,10.4197811 11.6449718,10.4197811 C12.6721297,10.4197811 13.5076098,9.58361734 13.5076098,8.55550239 C13.5076098,7.52738744 12.6722664,6.69136043 11.6451085,6.69136043 L11.6451085,6.69136043 Z M11.6451085,9.4474468 C11.1536094,9.4474468 10.7539844,9.04741165 10.7539844,8.55550239 C10.7539844,8.06359313 11.1537461,7.66355797 11.6451085,7.66355797 C12.1366076,7.66355797 12.5362326,8.06359313 12.5362326,8.55550239 C12.5362326,9.04741165 12.1364709,9.4474468 11.6451085,9.4474468 Z" id="形状"></path>
<path d="M5.08841471,13.0200096 L0.992497666,13.0200096 C1.23722184,10.1929669 3.59395664,7.96789094 6.45558885,7.96789094 C6.51752184,7.96789094 6.57631033,7.95517622 6.63086058,7.93398502 C8.7374025,7.84060703 10.4238118,6.09062412 10.4238118,3.94703177 C10.4238118,1.77049052 8.64361436,0 6.45558885,0 C4.26770006,0 2.48763931,1.77049052 2.48763931,3.94689505 C2.48763931,5.38393181 3.24737798,6.64241561 4.38117552,7.346647 C1.8374113,8.22081816 6.5953125e-05,10.648646 6.5953125e-05,13.50604 C6.5953125e-05,13.7744163 0.217583365,13.9922071 0.485822928,13.9922071 L5.08841471,13.9922071 C5.35665427,13.9922071 5.57417168,13.7744163 5.57417168,13.50604 C5.57417168,13.2376637 5.35665427,13.0200096 5.08841471,13.0200096 Z M3.45915326,3.94689505 C3.45915326,2.30669623 4.80322217,0.972334248 6.45558885,0.972334248 C8.10795553,0.972334248 9.45229787,2.30669622 9.45229787,3.94689505 C9.45229787,5.61430064 8.10795553,6.9705374 6.45558885,6.9705374 C4.80322217,6.9705374 3.45915326,5.61430064 3.45915326,3.94689505 Z" id="形状"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>合作商管理-白</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-23.000000, -175.000000)">
<g id="编组-5" transform="translate(23.000000, 175.000000)">
<g id="二级-管理员首页" fill="#FFFFFF" fill-rule="nonzero">
<path d="M8.75273438,7 C9.80273438,6.3 10.5902344,5.1625 10.5902344,3.7625 C10.5027344,1.6625 8.84023437,0 6.74023438,0 C4.64023437,0 2.97773437,1.6625 2.97773437,3.7625 C2.97773437,5.1625 3.67773438,6.3 4.81523438,7 C2.01523438,7.875 0.002734375,10.5 0.002734375,13.5625 C0.002734375,13.825 0.177734375,14 0.440234375,14 C0.702734375,14 0.877734375,13.825 0.877734375,13.5625 C0.877734375,10.4125 3.32773438,7.875 6.30273438,7.6125 C6.04023438,8.225 5.42773438,9.8875 5.42773438,11.2 C5.42773438,13.0375 6.56523438,13.5625 6.65273437,13.5625 L7.00273438,13.5625 C7.09023437,13.5625 8.22773438,13.0375 8.22773438,11.2 C8.22773438,9.8875 7.61523438,8.225 7.35273438,7.6125 C10.4152344,7.875 12.7777344,10.4125 12.7777344,13.5625 C12.7777344,13.825 12.9527344,14 13.2152344,14 C13.4777344,14 13.6527344,13.825 13.6527344,13.5625 C13.5652344,10.5 11.5527344,7.875 8.75273438,7 Z M3.85273438,3.7625 C3.85273438,2.1875 5.16523438,0.875 6.74023438,0.875 C8.31523438,0.875 9.62773438,2.1875 9.62773438,3.7625 C9.62773438,5.3375 8.31523438,6.7375 6.74023438,6.7375 C5.16523438,6.7375 3.85273438,5.425 3.85273438,3.7625 Z M6.74023438,12.6875 C6.56523438,12.5125 6.21523438,12.075 6.21523438,11.2875 C6.21523438,10.5 6.47773438,9.5375 6.74023438,8.8375 C7.00273438,9.5375 7.26523438,10.5 7.26523438,11.2875 C7.26523438,12.075 6.91523437,12.5125 6.74023438,12.6875 L6.74023438,12.6875 Z" id="形状"></path>
</g>
<rect id="合作商管理-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>合作商管理-灰</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-57.000000, -175.000000)">
<g id="编组-5" transform="translate(57.000000, 175.000000)">
<g id="二级-管理员首页" fill="#A6ADB4" fill-rule="nonzero">
<path d="M8.75273438,7 C9.80273438,6.3 10.5902344,5.1625 10.5902344,3.7625 C10.5027344,1.6625 8.84023437,0 6.74023438,0 C4.64023437,0 2.97773437,1.6625 2.97773437,3.7625 C2.97773437,5.1625 3.67773438,6.3 4.81523438,7 C2.01523438,7.875 0.002734375,10.5 0.002734375,13.5625 C0.002734375,13.825 0.177734375,14 0.440234375,14 C0.702734375,14 0.877734375,13.825 0.877734375,13.5625 C0.877734375,10.4125 3.32773438,7.875 6.30273438,7.6125 C6.04023438,8.225 5.42773438,9.8875 5.42773438,11.2 C5.42773438,13.0375 6.56523438,13.5625 6.65273437,13.5625 L7.00273438,13.5625 C7.09023437,13.5625 8.22773438,13.0375 8.22773438,11.2 C8.22773438,9.8875 7.61523438,8.225 7.35273438,7.6125 C10.4152344,7.875 12.7777344,10.4125 12.7777344,13.5625 C12.7777344,13.825 12.9527344,14 13.2152344,14 C13.4777344,14 13.6527344,13.825 13.6527344,13.5625 C13.5652344,10.5 11.5527344,7.875 8.75273438,7 Z M3.85273438,3.7625 C3.85273438,2.1875 5.16523438,0.875 6.74023438,0.875 C8.31523438,0.875 9.62773438,2.1875 9.62773438,3.7625 C9.62773438,5.3375 8.31523438,6.7375 6.74023438,6.7375 C5.16523438,6.7375 3.85273438,5.425 3.85273438,3.7625 Z M6.74023438,12.6875 C6.56523438,12.5125 6.21523438,12.075 6.21523438,11.2875 C6.21523438,10.5 6.47773438,9.5375 6.74023438,8.8375 C7.00273438,9.5375 7.26523438,10.5 7.26523438,11.2875 C7.26523438,12.075 6.91523437,12.5125 6.74023438,12.6875 L6.74023438,12.6875 Z" id="形状"></path>
</g>
<rect id="合作商管理-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>报表管理-白</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-23.000000, -219.000000)">
<g id="编组-6" transform="translate(23.000000, 219.000000)">
<g id="Group-5-Copy" transform="translate(0.000000, 1.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="列表" transform="translate(0.000000, 1.000000)">
<path d="M13.015625,0 L0.984375,0 C0.440234375,0 0,0.461197917 0,1.03125 L0,4.23958333 L0,5.15625 L0,7.10416667 L0,8.02083333 L0,9.96875 C0,10.5388021 0.440234375,11 0.984375,11 L4.375,11 L5.25,11 L8.75,11 L9.625,11 L13.015625,11 C13.5597656,11 14,10.5388021 14,9.96875 L14,8.02083333 L14,7.10416667 L14,5.15625 L14,4.23958333 L14,1.03125 C14,0.461197917 13.5597656,0 13.015625,0 Z M5.25,4.23958333 L5.25,2.29166667 L8.75,2.29166667 L8.75,4.23958333 L5.25,4.23958333 Z M8.75,5.15625 L8.75,7.10416667 L5.25,7.10416667 L5.25,5.15625 L8.75,5.15625 Z M0.984375,2.29166667 L4.375,2.29166667 L4.375,4.23958333 L0.984375,4.23958333 L0.984375,2.29166667 Z M0.984375,5.15625 L4.375,5.15625 L4.375,7.10416667 L0.984375,7.10416667 L0.984375,5.15625 Z M0.984375,9.96875 L0.984375,8.02083333 L4.375,8.02083333 L4.375,9.96875 L0.984375,9.96875 Z M5.25,9.96875 L5.25,8.02083333 L8.75,8.02083333 L8.75,9.96875 L5.25,9.96875 Z M13.015625,9.96875 L9.625,9.96875 L9.625,8.02083333 L13.015625,8.02083333 L13.015625,9.96875 Z M13.015625,7.10416667 L9.625,7.10416667 L9.625,5.15625 L13.015625,5.15625 L13.015625,7.10416667 Z M9.625,4.23958333 L9.625,2.29166667 L13.015625,2.29166667 L13.015625,4.23958333 L9.625,4.23958333 Z" id="Shape"></path>
</g>
</g>
<rect id="报表管理-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>报表管理-灰</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-57.000000, -219.000000)">
<g id="编组-6" transform="translate(57.000000, 219.000000)">
<g id="Group-5-Copy" opacity="0.65" transform="translate(0.000000, 1.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="列表" transform="translate(0.000000, 1.000000)">
<path d="M13.015625,0 L0.984375,0 C0.440234375,0 0,0.461197917 0,1.03125 L0,4.23958333 L0,5.15625 L0,7.10416667 L0,8.02083333 L0,9.96875 C0,10.5388021 0.440234375,11 0.984375,11 L4.375,11 L5.25,11 L8.75,11 L9.625,11 L13.015625,11 C13.5597656,11 14,10.5388021 14,9.96875 L14,8.02083333 L14,7.10416667 L14,5.15625 L14,4.23958333 L14,1.03125 C14,0.461197917 13.5597656,0 13.015625,0 Z M5.25,4.23958333 L5.25,2.29166667 L8.75,2.29166667 L8.75,4.23958333 L5.25,4.23958333 Z M8.75,5.15625 L8.75,7.10416667 L5.25,7.10416667 L5.25,5.15625 L8.75,5.15625 Z M0.984375,2.29166667 L4.375,2.29166667 L4.375,4.23958333 L0.984375,4.23958333 L0.984375,2.29166667 Z M0.984375,5.15625 L4.375,5.15625 L4.375,7.10416667 L0.984375,7.10416667 L0.984375,5.15625 Z M0.984375,9.96875 L0.984375,8.02083333 L4.375,8.02083333 L4.375,9.96875 L0.984375,9.96875 Z M5.25,9.96875 L5.25,8.02083333 L8.75,8.02083333 L8.75,9.96875 L5.25,9.96875 Z M13.015625,9.96875 L9.625,9.96875 L9.625,8.02083333 L13.015625,8.02083333 L13.015625,9.96875 Z M13.015625,7.10416667 L9.625,7.10416667 L9.625,5.15625 L13.015625,5.15625 L13.015625,7.10416667 Z M9.625,4.23958333 L9.625,2.29166667 L13.015625,2.29166667 L13.015625,4.23958333 L9.625,4.23958333 Z" id="Shape"></path>
</g>
</g>
<rect id="报表管理-灰" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48px" height="20px" viewBox="0 0 48 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>近7天</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="标准列表" transform="translate(-1324.000000, -172.000000)" fill="#1890FF">
<g id="编组-7" transform="translate(280.000000, 142.000000)">
<g id="近7天" transform="translate(1044.000000, 30.000000)">
<rect id="矩形" stroke="#1890FF" stroke-width="0.5" fill-opacity="0.04" x="0.25" y="0.25" width="47.5" height="19.5" rx="2"></rect>
<text font-family="PingFangSC-Regular, PingFang SC" font-size="13" font-weight="normal" line-spacing="14" letter-spacing="1">
<tspan x="5.0085" y="16.624">近7天</tspan>
</text>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="16px" viewBox="0 0 18 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="标准列表" transform="translate(-281.000000, -24.000000)">
<g id="Group" transform="translate(290.000000, 32.000000) scale(-1, 1) translate(-290.000000, -32.000000) translate(280.000000, 22.000000)">
<rect id="Rectangle-9" x="0" y="0" width="20" height="20"></rect>
<rect id="Combined-Shape" fill-opacity="0.65" fill="#000000" x="1.25" y="2.5" width="17.5" height="1.875" rx="0.9375"></rect>
<rect id="Rectangle-Copy" fill-opacity="0.65" fill="#000000" x="1.25" y="9.0625" width="11.25" height="1.875" rx="0.9375"></rect>
<path d="M13.0947111,7.8250177 L17.3692475,7.53744049 C17.5414472,7.52585544 17.6904342,7.65605936 17.7020193,7.82825908 C17.7029688,7.8423724 17.7029589,7.85653391 17.7019898,7.87064589 L17.4088387,12.1393768 C17.4029264,12.2254685 17.3283424,12.2904668 17.2422507,12.2845545 C17.2045995,12.2819688 17.1691565,12.2658432 17.1424704,12.2391571 L12.994714,8.09140072 C12.9336946,8.0303813 12.9336946,7.93144927 12.994714,7.87042985 C13.021453,7.84369083 13.0569817,7.82755601 13.0947111,7.8250177 Z" id="Rectangle-6" fill-opacity="0.65" fill="#000000"></path>
<rect id="Rectangle-Copy-2" fill-opacity="0.65" fill="#000000" x="1.25" y="15.625" width="17.5" height="1.875" rx="0.9375"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>用户</title>
<desc>Created with Sketch.</desc>
<defs>
<rect id="path-1" x="0" y="0" width="20.5333333" height="20.5333333" rx="10.2666667"></rect>
<filter x="-73.1%" y="-73.1%" width="246.1%" height="246.1%" filterUnits="objectBoundingBox" id="filter-3">
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.839215686 0 0 0 0 0.839215686 0 0 0 0 0.839215686 0 0 0 0.56173514 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<path d="M9.12592593,0 C14.1660356,-9.25853135e-16 18.2518519,4.08581621 18.2518519,9.12592593 C18.2518519,14.1660356 14.1660356,18.2518519 9.12592593,18.2518519 C4.08581621,18.2518519 6.17235423e-16,14.1660356 0,9.12592593 C-6.17235423e-16,4.08581621 4.08581621,9.25853135e-16 9.12592593,0 Z" id="path-4"></path>
<linearGradient x1="37.9394531%" y1="0%" x2="50%" y2="137.329102%" id="linearGradient-6">
<stop stop-color="#E4E8F0" offset="0%"></stop>
<stop stop-color="#D4DDE6" offset="100%"></stop>
</linearGradient>
<linearGradient x1="36.9648438%" y1="30.46875%" x2="56.9830204%" y2="68.7200429%" id="linearGradient-7">
<stop stop-color="#DFE5EC" offset="0%"></stop>
<stop stop-color="#D6DDED" offset="100%"></stop>
</linearGradient>
</defs>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="标准列表" transform="translate(-1305.000000, -18.000000)">
<g id="编组-5" transform="translate(1305.000000, 18.000000)">
<g id="编组-3" transform="translate(3.733333, 3.733333)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Mask">
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-1"></use>
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"></use>
</g>
<g id="Group" mask="url(#mask-2)">
<g transform="translate(1.140741, 1.140741)">
<mask id="mask-5" fill="white">
<use xlink:href="#path-4"></use>
</mask>
<use id="Rectangle-16" stroke="none" fill="#F2F4F9" fill-rule="evenodd" xlink:href="#path-4"></use>
<g id="通用" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" mask="url(#mask-5)">
<g transform="translate(2.281481, 3.137037)" id="编组-2">
<g transform="translate(0.095062, 0.095062)">
<path d="M6.70185182,0 C8.07732435,0 9.34831338,0.73380583 10.0360497,1.92499998 C10.7237859,3.11619414 10.7237859,4.58380586 10.0360497,5.77500002 C9.34831338,6.96619417 8.07732435,7.7 6.70185182,7.7 C4.57555555,7.7 2.85185185,5.97629629 2.85185185,3.85 C2.85185185,1.72370371 4.57555555,0 6.70185182,0 Z" id="路径" fill="url(#linearGradient-6)" fill-rule="nonzero"></path>
<path d="M0.000589300402,15.2355823 C-0.0387694808,11.3476639 1.89836705,8.9336627 4.32663273,7.98518519 L6.81992595,12.0661566 L9.44669678,8.07919358 C11.7893999,9.08642633 13.6512414,11.4718892 13.6888889,15.2389398 C9.38166923,16.9143036 4.84171938,17.0351715 0.000589300402,15.2355823 L0.000589300402,15.2355823 Z" id="路径" fill="url(#linearGradient-7)" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</g>
<rect id="客户" x="0" y="0" width="28" height="28"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>任务管理-白</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-23.000000, -42.000000)">
<g id="编组-3" transform="translate(23.000000, 42.000000)">
<g id="任务" transform="translate(1.000000, 0.000000)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M8.17930744,8.04981368 C8.13130606,7.87535135 8.06135226,7.71009841 7.97349567,7.55611875 C8.07323534,7.4212771 8.41800092,6.91859168 8.16951953,6.67036046 L8.04226116,6.53597224 C7.83011697,6.32364042 7.28793596,6.65510009 7.15623707,6.74098659 C7.00053749,6.65253584 6.8329392,6.58248823 6.65624098,6.53481521 C6.6280343,6.36627878 6.50426268,5.77745669 6.15507221,5.77745669 L6.01525843,5.77745669 C5.71525765,5.77745669 5.54321884,6.38632365 5.50498973,6.53902119 C5.33038668,6.58761672 5.165337,6.65788323 5.01196713,6.74600562 C4.89077539,6.65591314 4.37142239,6.29695041 4.11804705,6.55032575 L3.98331485,6.66349642 C3.76257106,6.88449038 4.12947669,7.46710512 4.19683497,7.56908068 C4.11177716,7.72062118 4.04371527,7.88273137 3.99660513,8.05416039 C3.85025566,8.07723857 3.22503383,8.19797689 3.22503383,8.55789339 L3.22503383,8.69761336 C3.22503383,9.00938777 3.88097967,9.18258361 4.00076421,9.21149389 C4.04810889,9.38128116 4.11638967,9.54248448 4.20149439,9.69271159 C4.13108716,9.8031773 3.77815978,10.3832591 3.99705856,10.6023768 L4.1245671,10.7083081 C4.41266917,10.9961757 5.01454701,10.5231354 5.01454701,10.5231354 L4.98655924,10.4933026 C5.14792218,10.5889706 5.32111447,10.6631036 5.50172189,10.7138119 C5.5317892,10.8366454 5.70473487,11.4879005 6.01525843,11.4879005 L6.15507221,11.4879005 C6.56253666,11.4879005 6.66346464,10.7273367 6.66346464,10.7273367 L6.62617366,10.7266174 C6.81079915,10.6796324 6.98609017,10.6083183 7.14809091,10.5174128 C7.27559945,10.6019077 7.80869616,10.9358221 8.02126251,10.7229118 L8.16298384,10.5812843 C8.4471301,10.2972475 7.98489404,9.71600867 7.97207283,9.6998258 C8.05996069,9.54609631 8.13010212,9.38117171 8.17857256,9.20681883 C8.33758689,9.1663851 8.93544637,8.99492481 8.93544637,8.69761336 L8.93544637,8.55789339 C8.93544637,8.16323452 8.2238377,8.05645882 8.17930744,8.04981368 Z M6.0811626,9.78898015 C5.4427443,9.78898015 4.92547084,9.27186304 4.92547084,8.63349165 C4.92547084,7.99512026 5.4427443,7.4778937 6.08117824,7.4778937 C6.71917438,7.4778937 7.23641656,7.99515153 7.23641656,8.63350729 C7.23641656,9.27186304 6.71919001,9.78898015 6.08117824,9.78898015 L6.0811626,9.78898015 Z M10.6902641,1.99694963 L10.6902641,1.24392218 C10.6902641,0.502449457 10.2222116,0.0595703125 9.43852268,0.0595703125 C8.65533411,0.0595703125 8.18725033,0.502465093 8.18725033,1.24392218 L8.18725033,1.99693399 L7.33923645,1.99693399 L7.33923645,1.24392218 C7.33923645,0.502449457 6.87163738,0.0595703125 6.08794846,0.0595703125 C5.30429082,0.0595703125 4.83667612,0.502465093 4.83667612,1.24392218 L4.83667612,1.99693399 L3.98819316,1.99693399 L3.98819316,1.24392218 C3.98819316,0.502449457 3.52060973,0.0595703125 2.73692081,0.0595703125 C1.95373224,0.0595703125 1.4856641,0.502465093 1.4856641,1.24392218 L1.4856641,1.99693399 L0.048828125,1.99693399 L0.048828125,14.0595703 L12.1117146,14.0595703 L12.1117146,1.99694963 L10.6902485,1.99694963 L10.6902641,1.99694963 Z M8.85762786,1.24392218 C8.85762786,0.878079768 9.02546068,0.7297133 9.43852268,0.7297133 C9.85249155,0.7297133 10.0198709,0.878064133 10.0198709,1.24392218 L10.0198709,3.25826005 C10.0198709,3.62397737 9.85249155,3.77248456 9.43853832,3.77248456 C9.02547632,3.77248456 8.85762786,3.62400864 8.85762786,3.25826005 L8.85762786,1.24392218 L8.85762786,1.24392218 Z M5.50706927,1.24392218 C5.50706927,0.878079768 5.67443303,0.7297133 6.08793283,0.7297133 C6.50147954,0.7297133 6.66931236,0.878064133 6.66931236,1.24392218 L6.66931236,3.25826005 C6.66931236,3.62397737 6.50147954,3.77248456 6.08794846,3.77248456 C5.67443303,3.77248456 5.50706927,3.62400864 5.50706927,3.25826005 L5.50706927,1.24392218 L5.50706927,1.24392218 Z M2.15557255,1.24392218 C2.15557255,0.878079768 2.32340538,0.7297133 2.73690518,0.7297133 C3.15045188,0.7297133 3.31873814,0.878064133 3.31873814,1.24392218 L3.31873814,3.25826005 C3.31873814,3.62397737 3.15043625,3.77248456 2.73690518,3.77248456 C2.32340538,3.77248456 2.15557255,3.62400864 2.15557255,3.25826005 L2.15557255,1.24392218 Z M11.106594,13.054606 L1.05394879,13.054606 L1.05394879,4.67758412 L11.106594,4.67758412 L11.106594,13.054606 L11.106594,13.054606 Z" id="形状"></path>
</g>
<rect id="矩形" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>任务管理-灰</title>
<desc>Created with Sketch.</desc>
<g id="奇瑞后台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标" transform="translate(-57.000000, -42.000000)">
<g id="编组-3" transform="translate(57.000000, 42.000000)">
<g id="任务" transform="translate(1.000000, 0.000000)" fill="#A6ADB4" fill-rule="nonzero">
<path d="M8.17930744,8.04981368 C8.13130606,7.87535135 8.06135226,7.71009841 7.97349567,7.55611875 C8.07323534,7.4212771 8.41800092,6.91859168 8.16951953,6.67036046 L8.04226116,6.53597224 C7.83011697,6.32364042 7.28793596,6.65510009 7.15623707,6.74098659 C7.00053749,6.65253584 6.8329392,6.58248823 6.65624098,6.53481521 C6.6280343,6.36627878 6.50426268,5.77745669 6.15507221,5.77745669 L6.01525843,5.77745669 C5.71525765,5.77745669 5.54321884,6.38632365 5.50498973,6.53902119 C5.33038668,6.58761672 5.165337,6.65788323 5.01196713,6.74600562 C4.89077539,6.65591314 4.37142239,6.29695041 4.11804705,6.55032575 L3.98331485,6.66349642 C3.76257106,6.88449038 4.12947669,7.46710512 4.19683497,7.56908068 C4.11177716,7.72062118 4.04371527,7.88273137 3.99660513,8.05416039 C3.85025566,8.07723857 3.22503383,8.19797689 3.22503383,8.55789339 L3.22503383,8.69761336 C3.22503383,9.00938777 3.88097967,9.18258361 4.00076421,9.21149389 C4.04810889,9.38128116 4.11638967,9.54248448 4.20149439,9.69271159 C4.13108716,9.8031773 3.77815978,10.3832591 3.99705856,10.6023768 L4.1245671,10.7083081 C4.41266917,10.9961757 5.01454701,10.5231354 5.01454701,10.5231354 L4.98655924,10.4933026 C5.14792218,10.5889706 5.32111447,10.6631036 5.50172189,10.7138119 C5.5317892,10.8366454 5.70473487,11.4879005 6.01525843,11.4879005 L6.15507221,11.4879005 C6.56253666,11.4879005 6.66346464,10.7273367 6.66346464,10.7273367 L6.62617366,10.7266174 C6.81079915,10.6796324 6.98609017,10.6083183 7.14809091,10.5174128 C7.27559945,10.6019077 7.80869616,10.9358221 8.02126251,10.7229118 L8.16298384,10.5812843 C8.4471301,10.2972475 7.98489404,9.71600867 7.97207283,9.6998258 C8.05996069,9.54609631 8.13010212,9.38117171 8.17857256,9.20681883 C8.33758689,9.1663851 8.93544637,8.99492481 8.93544637,8.69761336 L8.93544637,8.55789339 C8.93544637,8.16323452 8.2238377,8.05645882 8.17930744,8.04981368 Z M6.0811626,9.78898015 C5.4427443,9.78898015 4.92547084,9.27186304 4.92547084,8.63349165 C4.92547084,7.99512026 5.4427443,7.4778937 6.08117824,7.4778937 C6.71917438,7.4778937 7.23641656,7.99515153 7.23641656,8.63350729 C7.23641656,9.27186304 6.71919001,9.78898015 6.08117824,9.78898015 L6.0811626,9.78898015 Z M10.6902641,1.99694963 L10.6902641,1.24392218 C10.6902641,0.502449457 10.2222116,0.0595703125 9.43852268,0.0595703125 C8.65533411,0.0595703125 8.18725033,0.502465093 8.18725033,1.24392218 L8.18725033,1.99693399 L7.33923645,1.99693399 L7.33923645,1.24392218 C7.33923645,0.502449457 6.87163738,0.0595703125 6.08794846,0.0595703125 C5.30429082,0.0595703125 4.83667612,0.502465093 4.83667612,1.24392218 L4.83667612,1.99693399 L3.98819316,1.99693399 L3.98819316,1.24392218 C3.98819316,0.502449457 3.52060973,0.0595703125 2.73692081,0.0595703125 C1.95373224,0.0595703125 1.4856641,0.502465093 1.4856641,1.24392218 L1.4856641,1.99693399 L0.048828125,1.99693399 L0.048828125,14.0595703 L12.1117146,14.0595703 L12.1117146,1.99694963 L10.6902485,1.99694963 L10.6902641,1.99694963 Z M8.85762786,1.24392218 C8.85762786,0.878079768 9.02546068,0.7297133 9.43852268,0.7297133 C9.85249155,0.7297133 10.0198709,0.878064133 10.0198709,1.24392218 L10.0198709,3.25826005 C10.0198709,3.62397737 9.85249155,3.77248456 9.43853832,3.77248456 C9.02547632,3.77248456 8.85762786,3.62400864 8.85762786,3.25826005 L8.85762786,1.24392218 L8.85762786,1.24392218 Z M5.50706927,1.24392218 C5.50706927,0.878079768 5.67443303,0.7297133 6.08793283,0.7297133 C6.50147954,0.7297133 6.66931236,0.878064133 6.66931236,1.24392218 L6.66931236,3.25826005 C6.66931236,3.62397737 6.50147954,3.77248456 6.08794846,3.77248456 C5.67443303,3.77248456 5.50706927,3.62400864 5.50706927,3.25826005 L5.50706927,1.24392218 L5.50706927,1.24392218 Z M2.15557255,1.24392218 C2.15557255,0.878079768 2.32340538,0.7297133 2.73690518,0.7297133 C3.15045188,0.7297133 3.31873814,0.878064133 3.31873814,1.24392218 L3.31873814,3.25826005 C3.31873814,3.62397737 3.15043625,3.77248456 2.73690518,3.77248456 C2.32340538,3.77248456 2.15557255,3.62400864 2.15557255,3.25826005 L2.15557255,1.24392218 Z M11.106594,13.054606 L1.05394879,13.054606 L1.05394879,4.67758412 L11.106594,4.67758412 L11.106594,13.054606 L11.106594,13.054606 Z" id="形状"></path>
</g>
<rect id="矩形" x="0" y="0" width="14" height="14"></rect>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view :key="key" />
</transition>
<ResetPassDialog></ResetPassDialog>
</section>
</template>
<script>
import ResetPassDialog from '@/views/components/ResetPassDialog'
export default {
name: 'AppMain',
components: {
ResetPassDialog
},
data() {
return {
visible: true
}
},
computed: {
key() {
return this.$route.fullPath
}
}
}
</script>
<style scoped>
.app-main {
/* height: calc(100% - 35px); */
padding: 24px 24px 0 24px;
background-color: #f0f2f5;
}
/* 定义过渡时间 */
.fade-transform-enter-active,
.fade-transform-live-active {
transition: all 0.5s;
}
.fade-transform-enter,
.fade-transform-live-to {
opacity: 0;
}
</style>
<template lang="pug">
div(class="header")
.logo
span(@click="expanMenu")
<svg-icon className="toggle-icon" icon-class='togglemenu' />
.right-menu
el-dropdown(trigger="click" @command="handleCommand")
span(class="el-dropdown-link")
<svg-icon className="icon" icon-class='user' />
span(class="userInfo-name userInfo-discription") {{name}}
i(class="el-icon-arrow-down el-icon-caret-bottom")
el-dropdown-menu(slot="dropdown")
el-dropdown-item(command="pass")
span(class="userInfo-operation userInfo-discription") 修改密码
el-dropdown-item(command="logout")
span(class="userInfo-operation userInfo-discription") 退出
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex'
export default {
name: 'CommHeader',
computed: {
...mapState('app', ['sidebar']),
...mapState(['name', 'userId']),
isCollapse() {
return this.sidebar.opened
}
},
data() {
return {
visible: true,
resetObj: null
}
},
mounted() {},
methods: {
...mapMutations(['TOGGLE_UPDATEPASS_DIALOG']),
...mapActions(['logout']),
...mapActions('app', ['toggleSideBar']),
handleLogout() {
try {
this.logout()
this.$router.push('/login')
} catch (error) {
console.log(error)
}
},
handleUpdatepass() {
this.TOGGLE_UPDATEPASS_DIALOG({
name: this.name,
username: this.userId
})
},
expanMenu() {
this.toggleSideBar()
},
handleCommand(data) {
if (data === 'pass') {
this.handleUpdatepass()
} else if (data === 'logout') {
this.handleLogout()
}
}
}
}
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
box-shadow: 0px 1px 4px 0px rgba(0, 21, 41, 0.12);
padding: 0 20px 0 24px;
}
.logo {
display: flex;
justify-content: flex-start;
align-items: center;
.toggle-icon {
width: 20px;
height: 20px;
}
span {
font-size: 14px;
cursor: pointer;
.rotate {
transform: rotate(90deg);
}
}
}
.right-menu {
.el-dropdown-link {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
height: 100%;
.icon {
height: 28px;
width: 28px;
margin-right: 6px;
}
}
.user-icon {
font-size: 20px;
margin-right: 10px;
}
.userInfo-name {
margin-right: 10px;
color: #666666;
}
}
</style>
<template>
<span>
<svg-icon v-if="icon" className="icon" :icon-class="ComIcon" />
<span v-if="title" slot="title">{{ title }}</span>
</span>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'MenuItem',
props: {
icon: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
item: {
type: Object
}
},
computed: {
...mapState('permission', ['routes']),
ComIcon() {
const { path } = this.$route
if (path.indexOf(this.item.path) > -1) {
return `${this.icon}-active`
} else {
return this.icon
}
}
}
}
</script>
<style lang="scss" scoped>
.icon {
width: 14px;
height: 14px;
}
</style>
<template>
<!-- eslint-disable vue/require-component-is -->
<component v-bind="linkProps(to)">
<slot/>
</component>
</template>
<script>
import { isExternal } from '@/utils/validate'
export default {
props: {
to: {
type: String,
required: true
}
},
methods: {
linkProps(url) {
if (isExternal(url)) {
return {
is: 'a',
href: url,
target: '_blank',
rel: 'noopener'
}
}
return {
is: 'router-link',
to: url
}
}
}
}
</script>
<template>
<div v-if="!item.hidden">
<template
v-if="hasOneShowingChild(item.children, item) && !item.alwaysShow"
>
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)">
<item
:icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"
:title="onlyOneChild.meta.title"
:item="onlyOneChild"
/>
</el-menu-item>
</app-link>
</template>
<el-submenu v-else :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<item
v-if="item.meta"
:icon="item.meta && item.meta.icon"
:title="item.meta.title"
:item="item"
/>
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
/>
</el-submenu>
</div>
</template>
<script>
import path from 'path'
import Item from './Item'
import { isExternal } from '@/utils/validate'
import AppLink from './Link'
export default {
name: 'SidebarItem',
components: {
Item,
AppLink
},
props: {
item: {
type: Object,
require: true
},
basePath: {
type: String,
default: ''
}
},
data() {
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
this.onlyOneChild = null
return {}
},
methods: {
hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
if (item.hidden) {
return false
} else {
// Temp set(will be used if only has one showing child)
this.onlyOneChild = item
return true
}
})
// When there is only one child router, the child router is displayed by default
if (showingChildren.length === 1) {
return true
}
// Show parent if there are no child router to display
if (showingChildren.length === 0) {
this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
return true
}
return false
},
resolvePath(routePath) {
if (isExternal(routePath)) {
return routePath
}
if (isExternal(this.basePath)) {
return this.basePath
}
return path.resolve(this.basePath, routePath)
}
}
}
</script>
<style lang="scss"></style>
<template>
<div class="sidebar-container">
<div class="home-title">
<div class="title title-icon" v-if="!isCollapse"></div>
</div>
<el-scrollbar>
<el-menu
mode="vertical"
:default-active="activeMenu"
:collapse="isCollapse"
:unique-opened="false"
:collapse-transition="false"
>
<sidebar-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import SidebarItem from './SidebarItem'
import { mapState, mapMutations } from 'vuex'
export default {
components: {
SidebarItem
},
data() {
return {
menuBg: '#304156',
menuText: '#bfcbd9',
menuActiveText: '#409EFF'
}
},
computed: {
...mapState('app', ['sidebar']),
...mapState('permission', ['routes']),
activeMenu() {
const route = this.$route
const { meta, path } = route
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
isCollapse() {
return this.sidebar.opened
}
},
methods: {
...mapMutations('app', ['SET_IS_COLLAPSE'])
}
}
</script>
<style lang="scss">
.sidebar-container {
width: 100%;
height: 100%;
.home-title {
background: #002140;
height: 64px;
display: flex;
justify-content: center;
align-items: center;
.title {
width: 166px;
height: 24px;
background-size: contain;
}
}
.el-scrollbar {
height: calc(100% - 64px);
background-color: #001529;
.el-scrollbar__wrap {
overflow-x: hidden !important;
// 导航栏间距
.el-scrollbar__view {
> .el-menu {
> div {
margin: 10px 0;
}
}
}
.el-menu {
width: 100%;
background: #001529;
border-right: 0;
.el-submenu.is-active {
.el-submenu__title {
span {
color: #fff;
}
}
}
.el-submenu,
.el-menu-item > span {
.icon {
margin-right: 14px;
}
}
.el-menu-item,
.el-submenu__title {
color: #999;
background: #001529;
text-align: left;
}
.el-menu-item.is-active {
color: #fff;
background: #1890ff;
}
span {
font-size: 14px;
font-weight: 500;
}
}
.el-menu--collapse {
.el-submenu > .el-submenu__title > span {
display: inline-flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
height: 20px;
width: 20px;
overflow: visible;
visibility: visible;
.icon {
margin: 0;
}
span {
display: none;
}
}
.el-menu-item > span {
span {
display: none;
}
}
}
}
}
}
.el-menu--collapse {
.el-submenu {
& > .el-submenu__title {
& > span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
.el-submenu__icon-arrow {
display: none;
}
}
}
}
</style>
<template lang="pug">
el-breadcrumb(separator="/" class="app-breadcrumb")
transition-group(name="breadcrumb")
el-breadcrumb-item(v-for="(item,index) in levelList" :key="item.path")
span(v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect") {{ item.meta.title }}
a(v-else @click.prevent="handleLink(item)") {{ item.meta.title }}
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route() {
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(
item => item.meta && item.meta.title
)
// const first = matched[0]
// if (this.isWhoRoute(first, 'dayBillingInquiry')) {
// matched = [{ path: '/billing', meta: { title: '账单查询' } }].concat(
// matched
// )
// }
// if (this.isWhoRoute(first, 'billingDetail')) {
// matched = [
// { path: '/billing', meta: { title: '账单查询' } },
// { path: '/billing/dayBillingInquiry', meta: { title: '日调用量' } }
// ].concat(matched)
// }
this.levelList = matched.filter(
item => item.meta && item.meta.title && item.meta.breadcrumb !== false
)
},
isWhoRoute(route, str) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === str.toLocaleLowerCase()
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route
const toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
}
}
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
height: 54px;
font-size: 14px;
padding-left: 32px;
display: flex;
align-items: center;
.no-redirect {
color: #666;
cursor: text;
}
}
/* breadcrumb transition */
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all 0.5s;
}
.breadcrumb-enter,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-move {
transition: all 0.5s;
}
.breadcrumb-leave-active {
position: absolute;
}
</style>
<style lang="scss" scoped>
.app-breadcrumb {
.el-breadcrumb__inner.is-link,
.el-breadcrumb__inner a {
color: rgba(0, 0, 0, 0.45);
}
.el-breadcrumb__inner .no-redirect {
color: rgba(0, 0, 0, 0.65);
font-weight: 400;
}
.el-breadcrumb__inner.is-link:hover,
.el-breadcrumb__inner a:hover {
cursor: auto;
color: rgba(0, 0, 0, 0.45);
}
}
</style>
export { default as Sidebar } from './Sidebar'
export { default as AppMain } from './AppMain'
export { default as Header } from './Header'
<template lang="pug">
.app
el-container
el-aside(:width="asideWidth")
sidebar
el-container
el-header(height='118px')
Header
Breadcrumb
el-main
AppMain
</template>
<script>
import { Sidebar, AppMain, Header } from './components'
import Breadcrumb from './components/breadcrumb'
import { mapState } from 'vuex'
export default {
name: 'Layout',
components: {
Sidebar,
Header,
AppMain,
Breadcrumb
},
computed: {
...mapState('app', ['sidebar']),
siderbar() {
return this.$store.state.app.siderbar
},
asideWidth() {
return this.sidebar.opened ? '64px' : '256px'
}
}
}
</script>
<style lang="scss" scope>
.app {
height: 100%;
> .el-container {
height: 100%;
}
.el-header {
padding: 0;
}
.el-main {
padding: 0;
}
.el-aside {
transition: width 0.2s ease-in;
box-shadow: 2px 0px 6px 0px rgba(0, 21, 41, 0.35);
}
}
</style>
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import VueParticles from 'vue-particles'
import ElementUI from 'element-ui'
import './element-variables.scss'
import './base.scss'
import './permission'
import '@/icons'
import 'animate.css'
import 'video.js/dist/video-js.css'
import VeLine from 'v-charts/lib/line.common'
import VeHistogram from 'v-charts/lib/histogram.common'
import Card from '_c/card'
Vue.config.productionTip = false
Vue.use(ElementUI)
Vue.use(VueParticles)
Vue.component('Card', Card)
Vue.component(VeLine.name, VeLine)
Vue.component(VeHistogram.name, VeHistogram)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
import router from './router'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import store from './store'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login']
router.beforeEach((to, from, next) => {
let routerTemp = store.state.resetRouterTemp
// start progress bar
NProgress.start()
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (routerTemp) {
next()
} else {
store.commit('SET_ROUTER_TEMP', 'TEMP')
let roles = store.state.roles
store.commit('permission/SET_ROUTES', { roles })
router.addRoutes(store.state.permission.routes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
}
} else {
// other pages that do not have permission to access are redirected to the login page.
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login?redirect=${to.path}`) // 重定向到登录页
NProgress.done()
}
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/layout'
import { PERMISSION_USER_MAP } from '@/utils/mappingData'
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
Vue.use(Router)
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar
noCache: true if set true, the page will no be cached(default is false)
affix: true if set true, the tag will affix in the tags-view
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
}
*/
/**
* constantRoutes
* a base page that does not have permission requirements
* all roles can be accessed
*/
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
}
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{
path: '/',
component: Layout,
redirect: '/monitor',
meta: {
roles: [
PERMISSION_USER_MAP.admin.code,
PERMISSION_USER_MAP.dataAnalyst.code
]
},
children: [
{
path: 'monitor',
name: 'monitor',
component: () => import('@/views/monitor'),
meta: {
title: '资源监控',
icon: 'home'
}
},
{
path: 'monitor-details',
name: 'monitor-details',
hidden: true,
component: () => import('@/views/monitor'),
meta: {
title: '远程订单详情',
icon: 'home'
}
}
]
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
}
// { path: '*', redirect: '/404', hidden: true }
]
const createRouter = () =>
new Router({
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
export default router
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import permission from './modules/permisssion'
import { login, logout } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { NAME, USER_TYPE, USER_ID, USER_PASS } from '@/utils/mappingData'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token: getToken(),
name: sessionStorage.getItem(NAME),
roles: JSON.parse(sessionStorage.getItem(USER_TYPE)) || '',
userId: sessionStorage.getItem(USER_ID),
resetRouterTemp: '',
userpass: JSON.parse(sessionStorage.getItem(USER_PASS)) || ''
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
setToken(token)
},
SET_NAME: (state, name) => {
sessionStorage.setItem(NAME, name)
state.name = name
},
SET_USER_ID: (state, userId) => {
sessionStorage.setItem(USER_ID, userId)
state.userId = userId
},
SET_ROLES: (state, userType) => {
state.roles = userType
sessionStorage.setItem(USER_TYPE, JSON.stringify(userType))
},
SET_ROUTER_TEMP(state, payload) {
state.resetRouterTemp = payload
},
SET_USERPASS(state, payload) {
state.userpass = payload
sessionStorage.setItem(USER_PASS, payload)
}
},
actions: {
async login({ dispatch, commit }, userinfo) {
try {
const { username, password } = userinfo
const res = await login({
username: username.trim(),
password: password
})
if (res.code === 0) {
commit('SET_ROLES', res.result.roleCode)
commit('SET_NAME', res.result.name)
commit('SET_USER_ID', res.result.username)
commit('SET_TOKEN', res.result.token)
}
return res
} catch (error) {
console.log(error)
}
},
// remove token
resetToken({ commit }) {
return new Promise(resolve => {
removeToken()
sessionStorage.clear()
resolve()
})
},
async logout({ dispatch, commit }) {
try {
const res = await logout()
dispatch('resetToken')
return res
} catch (error) {
console.log(error)
}
}
},
modules: {
app,
permission
}
})
// import Cookies from 'js-cookie'
const state = {
sidebar: {
// string => num => boolean
opened: !!+sessionStorage.getItem('sidebarStatus'),
withoutAnimation: false
}
}
const mutations = {
TOGGLE_SIDEBAR: state => {
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false
if (state.sidebar.opened) {
sessionStorage.setItem('sidebarStatus', 1)
} else {
sessionStorage.setItem('sidebarStatus', 0)
}
},
CLOSE_SIDEBAR: (state, withoutAnimation) => {
sessionStorage.setItem('sidebarStatus', 0)
state.sidebar.opened = false
state.sidebar.withoutAnimation = withoutAnimation
}
}
const actions = {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
import { constantRoutes, asyncRoutes } from '@/router'
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return route.meta.roles.includes(roles)
} else {
return true
}
}
function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const temp = { ...route }
if (hasPermission(roles, temp)) {
if (temp.children) {
temp.children = filterAsyncRoutes(temp.children, roles)
}
res.push(temp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, payload) => {
state.addRoutes = filterAsyncRoutes(asyncRoutes, payload.roles)
state.routes = constantRoutes.concat(state.addRoutes)
}
}
export default {
namespaced: true,
state,
mutations
}
import Cookies from 'js-cookie'
import { USER_ID } from '@/utils/mappingData'
export function getToken() {
if (sessionStorage.getItem(USER_ID) === null) {
return ''
} else {
return Cookies.get(sessionStorage.getItem(USER_ID))
}
}
export function setToken(token) {
let expires = new Date(new Date().getTime() + 60 * 60 * 24 * 1000)
return Cookies.set(sessionStorage.getItem(USER_ID), token, {
expires: expires
})
}
export function removeToken() {
return Cookies.remove(sessionStorage.getItem(USER_ID))
}
// session key
export const NAME = 'name'
export const USER_ID = 'userId'
export const USER_TYPE = 'userType'
export const USER_PASS = 'userpass'
// 权限字段
export const PERMISSION_USER_MAP = {
admin: {
code: 'admin',
name: '管理员'
},
auditor: {
code: 'auditor',
name: '初级审核员'
},
dataAnalyst: {
code: 'dataAnalyst',
name: '数据分析员'
}
}
// contactCard const
export const CONTACT_CARD = {
ANSWER_END: 'answerEnd', // 接听挂断
ANSWER: 'answer', // 接听
CALL: 'call', // 呼叫
CALL_END: 'callEnd' // 呼叫挂断
}
import store from '@/store'
export default function checkPermission(value) {
if (value && value instanceof Array && value.length > 0) {
const roles = store.state.roles
const permissionRoles = value
const hasPermission = roles.some(role => {
return permissionRoles.includes(role)
})
if (hasPermission) {
return true
} else {
return false
}
} else {
console.error(`need roles! Like v-permission="['admin','editor']"`)
return false
}
}
import axios from 'axios'
// MessageBox
import { Message } from 'element-ui'
import store from '@/store'
import { getToken, removeToken } from '@/utils/auth'
import router from '@/router'
// create an axios instance
const service = axios.create({
// baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
withCredentials: false // send cookies when cross-domain requests
// timeout: 10000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.state.token) {
// let each request carry token --['X-Token'] as a custom key.
// please modify it according to the actual situation.
config.headers['X-Source'] = 'web'
config.headers['x-auth-token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code.
*/
response => {
const res = response.data
if (response.config.url.includes('download')) {
return res
}
if (response.config.url.includes('recognize')) {
return res
}
if (response.config.url.includes('verify')) {
return res
}
// 3703图片未识别 3730报表无数据
if (
(res && res.code === 0) ||
res.code === 2926 ||
res.code === 4001 ||
res.code === 3703 ||
res.code === 3730
) {
return res
} else if (res && res.code === 2909) {
// 2909 登录超时
// cookie失效
Message({
message: res.msg || 'error',
type: 'error',
duration: 5 * 1000
})
removeToken()
router.push('/login')
} else if (res && res.code) {
Message({
message: res.msg || 'error',
type: 'error',
duration: 5 * 1000
})
}
return res
},
error => {
Message({
message: '网络连接异常',
type: 'error',
duration: 5 * 1000
})
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default service
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object' && time) {
date = time
} else {
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
time = parseInt(time)
}
if (typeof time === 'number' && time.toString().length === 10) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') {
return ['日', '一', '二', '三', '四', '五', '六'][value]
}
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return timeStr
}
/**
* @param {string} url
* @returns {Object}
*/
export function getQueryObject(url) {
url = url == null ? window.location.href : url
const search = url.substring(url.lastIndexOf('?') + 1)
const obj = {}
const reg = /([^?&=]+)=([^?&=]*)/g
search.replace(reg, (rs, $1, $2) => {
const name = decodeURIComponent($1)
let val = decodeURIComponent($2)
val = String(val)
obj[name] = val
return rs
})
return obj
}
/**
* @param {string} input value
* @returns {number} output value
*/
export function byteLength(str) {
// returns the byte length of an utf8 string
let s = str.length
for (var i = str.length - 1; i >= 0; i--) {
const code = str.charCodeAt(i)
if (code > 0x7f && code <= 0x7ff) s++
else if (code > 0x7ff && code <= 0xffff) s += 2
if (code >= 0xdc00 && code <= 0xdfff) i--
}
return s
}
/**
* @param {Array} actual
* @returns {Array}
*/
export function cleanArray(actual) {
const newArray = []
for (let i = 0; i < actual.length; i++) {
if (actual[i]) {
newArray.push(actual[i])
}
}
return newArray
}
/**
* @param {Object} json
* @returns {Array}
*/
export function param(json) {
if (!json) return ''
return cleanArray(
Object.keys(json).map(key => {
if (json[key] === undefined) return ''
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
})
).join('&')
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"')
.replace(/\+/g, ' ') +
'"}'
)
}
/**
* Merges two objects, giving the last one precedence
* @param {Object} target
* @param {(Object|Array)} source
* @returns {Object}
*/
export function objectMerge(target, source) {
if (typeof target !== 'object') {
target = {}
}
if (Array.isArray(source)) {
return source.slice()
}
Object.keys(source).forEach(property => {
const sourceProperty = source[property]
if (typeof sourceProperty === 'object') {
target[property] = objectMerge(target[property], sourceProperty)
} else {
target[property] = sourceProperty
}
})
return target
}
/**
* @param {string} type
* @returns {Date}
*/
export function getTime(type) {
if (type === 'start') {
return new Date().getTime() - 3600 * 1000 * 24 * 90
} else {
return new Date(new Date().toDateString())
}
}
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function() {
// 据上一次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function(...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}
/**
* 节流
* @param {*} func
* @param {*} wait
* @param {*} immediate
*/
export function throttle(fn, wait = 1000, immediate) {
let timer = null
let callNow = immediate
return function(...args) {
let context = this
if (callNow) {
fn.apply(context, args)
callNow = null
}
if (!timer) {
timer = setTimeout(() => {
fn.apply(context, args)
timer = null
}, wait)
}
}
}
/**
* @param {Array} arr
* @returns {Array}
*/
export function uniqueArr(arr) {
return Array.from(new Set(arr))
}
/**
* @returns {string}
*/
export function createUniqueString() {
const timestamp = +new Date() + ''
const randomNum = parseInt((1 + Math.random()) * 65536) + ''
return (+(randomNum + timestamp)).toString(32)
}
/**
* 延迟执行某个操作
* @param {} ms
*/
export function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done')
})
}
/**
* 二进制转文件
* @param {*} blobs blob对象
* @param {*} fileName 文件名
*/
export function blob2File(blobs, fileName) {
const blob = new Blob([blobs])
const href = window.URL.createObjectURL(blob) // 创建下载的链接
const aEle = document.createElement('a') // 创建a标签
aEle.href = href
aEle.download = fileName // 下载后文件名
document.body.appendChild(aEle)
aEle.click() // 点击下载
document.body.removeChild(aEle) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
}
/**
* url下载文件
* @param {*} url
* @param {*} name
*/
export function downFile(url, name) {
const a = document.createElement('a')
a.href = url
a.download = name
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
/**
* 对象转换成formdata形式
* @param {*} data
*/
export function obj2FormData(data) {
const form = new FormData()
Object.keys(data).forEach(key => {
if (data[key] !== undefined) {
form.append(key, data[key])
}
})
return form
}
function typeOf(obj) {
const toString = Object.prototype.toString
const map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Null]': 'null',
'[object Undefined]': 'undefined',
'[object Symbol]': 'symbol',
'[object Object]': 'object',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regexp'
}
return map[toString.call(obj)]
}
/**
* 深克隆
* @param {*} data
*/
export function deepClone(data) {
const type = typeOf(data)
let copy
if (type === 'array') {
copy = []
} else if (type === 'object') {
copy = {}
} else {
return data
}
if (type === 'array') {
for (let i = 0; i < data.length; i++) {
copy.push(deepClone(data[i]))
}
}
if (type === 'object') {
for (let key in data) {
copy[key] = deepClone(data[key])
}
}
return copy
}
/**
* filter undefined
* @param {*} temp
*/
export function parseUndefined(temp) {
// 判断是否为0
if (temp === 0 || temp === '0') {
return temp
}
if (temp) {
return temp
} else {
return undefined
}
}
/**
* 获取目标的元素的截图
* @param {*} target
* @param {*} format
*/
export function shotTargetToImage(target, format) {
const canvas = document.createElement('canvas') // 创建画布
canvas.width = target.videoWidth
canvas.height = target.videoHeight // 设定宽高比
canvas.getContext('2d').drawImage(target, 0, 0, canvas.width, canvas.height) // 将视频此刻帧数画入画布
return canvas.toDataURL(format)
}
// 去掉base头部
export function substringBasehead(base64) {
let length = 'data:image/png;base64,'.length
return base64.substring(length)
}
export function parseTimeSecond(time) {
let minutes = parseInt((time % (1000 * 60 * 60)) / (1000 * 60))
let second = parseInt((time % (1000 * 60)) / 1000)
if (minutes < 10) {
minutes = `0${minutes}`
}
if (second < 10) {
second = `0${second}`
}
return `${minutes}:${second}`
}
export function sleep(time) {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const validMap = ['admin', 'editor']
return validMap.indexOf(str.trim()) >= 0
}
/**
* 模型名称校验函数
* @param {*} rule
* @param {*} value
* @param {*} callback
*/
export function validateName(rule, value, callback) {
if (!value) {
return callback(new Error('模型名称不能为空'))
}
if (/(^\s+)|(\s+$)/.test(value)) {
return callback(new Error('首字符和尾字符不得为空格'))
}
if (value.length < 2 || value.length > 10) {
return callback(new Error('长度在 2 到 10 个字符'))
}
callback()
}
/**
* 模型描述校验函数
* @param {*} rule
* @param {*} value
* @param {*} callback
*/
export function validateDes(rule, value, callback) {
if (!value) {
return callback(new Error('模型描述不能为空'))
}
if (/(^\s+)|(\s+$)/.test(value)) {
return callback(new Error('首字符和尾字符不得为空格'))
}
if (value.length < 2 || value.length > 20) {
return callback(new Error('长度在 2 到 20 个字符'))
}
callback()
}
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!