Commit 9dae96ab by li

manager

parents
> 1%
last 2 versions
not ie <= 10
NODE_ENV=production
VUE_APP_PREVIEW=false
VUE_APP_BASE_URL=/
VUE_APP_API_BASE_URL=
\ No newline at end of file
NODE_ENV=development
VUE_APP_PREVIEW=true
VUE_APP_BASE_URL=/
VUE_APP_API_BASE_URL=http://38.47.232.137:9217
\ No newline at end of file
/**
默认eslint规则:
代码末尾不能加分号 ;(强迫症的我受不了 哭)
代码中不能存在多行空行;(这个我更也忍不了大哭)
tab键不能使用,必须换成两个空格;(超级不习惯)
代码中不能存在声明了但未使用的变量;(这个我觉得可以有)
* **/
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/strongly-recommended',
'@vue/standard'
],
rules: {
'no-console': 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'generator-star-spacing': 'off',
'no-mixed-operators': 0,
'vue/max-attributes-per-line': [
2,
{
'singleline': 5, //单行的情况下可以接受的属性数量
'multiline': {
'max': 1, //多行的情况下每行最多属性数量
'allowFirstLine': false //不允许在多行的情况下第一行有属性
}
}
],
'vue/attribute-hyphenation': 0,
'vue/html-self-closing': 0,
'vue/component-name-in-template-casing': 0,
'vue/html-closing-bracket-spacing': 0,
'vue/singleline-html-element-content-newline': 0,
'vue/no-unused-components': 0,
'vue/multiline-html-element-content-newline': 0,
'vue/no-use-v-if-with-v-for': 0,
'vue/html-closing-bracket-newline': 0,
'vue/no-parsing-error': 0,
'no-tabs': 0,
'quotes': [
2,
'single',
{
'avoidEscape': true,
'allowTemplateLiterals': true
}
],
/**
* 分号配置项:
* 第一个参数:
" off"或0 - 关闭规则
" warn"或1 - 将该规则作为警告打开(不影响退出代码)
" error"或2 - 将规则作为错误打开(退出代码将为1)
*
*第二个参数
always(默认):在语句末尾需要分号
never:不允许加分号
*
* 第三个参数:
"beforeStatementContinuationChars": "any"(默认)如果下一行语句以 [,(,/,+,或 - 开头,忽略语句末尾的分号(或缺失分号),
"beforeStatementContinuationChars": "always" 如果下一行语句以 [,(,/,+,或 - 开头,在语句末尾需要添加分号。
"beforeStatementContinuationChars": "never" 如果该语句不会因为ASI而带来风险,那么即使它的下一行语句以 [,(,/,+,或 - 开头,也不允许在语句末尾添加分号。
* **/
'semi': [
2,
'never',
{
'beforeStatementContinuationChars': 'never'
}
],
'no-delete-var': 2,
'prefer-const': [
2,
{
'ignoreReadBeforeAssign': false
}
],
'template-curly-spacing': 'off',
'indent': 'off'
},
parserOptions: {
parser: 'babel-eslint'
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
],
env: {
jest: true
}
}
]
}
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const plugins = []
if (IS_PROD) {
plugins.push('transform-remove-console')
}
// lazy load ant-design-vue
// if your use import on Demand, Use this code
plugins.push(['import', {
'libraryName': 'ant-design-vue',
'libraryDirectory': 'es',
'style': true // `style: true` 会加载 less 文件
}])
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
[
'@babel/preset-env',
{
'useBuiltIns': 'entry',
'corejs': 3
}
]
],
'plugins': [
[
'import',
{
'libraryName': 'ant-design-vue',
'libraryDirectory': 'es',
'style': 'css'
}
]
]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "jeepay-ui-manager",
"version": "1.10.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint",
"build:preview": "vue-cli-service build --mode preview",
"lint:nofix": "vue-cli-service lint --no-fix"
},
"dependencies": {
"@ant-design-vue/pro-layout": "^1.0.7",
"@antv/data-set": "^0.10.2",
"@antv/g2plot": "^2.3.21",
"@antv/util": "^2.0.13",
"ant-design-vue": "^1.7.2",
"axios": "^0.19.0",
"core-js": "^3.1.2",
"enquire.js": "^2.1.6",
"js-base64": "^2.5.2",
"lodash.clonedeep": "^4.5.0",
"lodash.get": "^4.4.2",
"lodash.pick": "^4.4.0",
"md5": "^2.2.1",
"mockjs2": "1.0.8",
"moment": "^2.24.0",
"nprogress": "^0.2.0",
"store": "^2.0.12",
"viser-vue": "^2.4.6",
"vue": "^2.6.10",
"vue-clipboard2": "^0.2.1",
"vue-cropper": "0.4.9",
"vue-i18n": "^8.17.4",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.1.2",
"vue-svg-component-runtime": "^1.0.1",
"vuex": "^3.1.1",
"wangeditor": "^3.1.1"
},
"devDependencies": {
"@ant-design/colors": "^3.2.1",
"@vue/cli-plugin-babel": "^4.0.4",
"@vue/cli-plugin-eslint": "^4.0.4",
"@vue/cli-plugin-router": "^4.0.4",
"@vue/cli-plugin-unit-jest": "^4.0.4",
"@vue/cli-plugin-vuex": "^4.0.4",
"@vue/cli-service": "^4.0.4",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "^1.0.0-beta.29",
"babel-eslint": "^10.0.1",
"babel-plugin-import": "^1.12.2",
"babel-plugin-transform-remove-console": "^6.9.4",
"eslint": "^5.16.0",
"eslint-plugin-html": "^5.0.0",
"eslint-plugin-vue": "^5.2.3",
"git-revision-webpack-plugin": "^3.0.6",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"opencollective": "^1.0.3",
"opencollective-postinstall": "^2.0.2",
"style-resources-loader": "^1.4.1",
"vue-cli-plugin-style-resources-loader": "^0.1.5",
"vue-svg-icon-loader": "^2.1.1",
"vue-template-compiler": "^2.6.10",
"webpack-theme-color-replacer": "^1.3.12"
}
}
module.exports = {
plugins: {
autoprefixer: {}
}
}
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="90.000000pt" height="32.000000pt" viewBox="0 0 90.000000 32.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,32.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
</g>
</svg>
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<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 %>imgs/favicon.ico">
<title>运营平台</title>
<style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
<!-- require cdn assets css -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
<% } %>
</head>
<body>
<noscript>
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<div class="first-loading-wrp">
<% { %>
<img type="text/javascript" src="<%= BASE_URL %>imgs/logo.svg">
<% } %>
<div class="loading-wrp">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
<div style="display: flex; justify-content: center; align-items: center;">聚合支付</div>
</div>
</div>
<!-- require cdn assets js -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<a-config-provider :locale="locale">
<div id="app">
<router-view/>
<loading v-show="globalLoading"></loading>
</div>
</a-config-provider>
</template>
<script>
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
import Loading from './components/GlobalLoad/GlobalLoad' // 全局Loading组件
import { mapState } from 'vuex' // 引入vuex状态管理,mapState管理中存在全局loading
export default {
data () {
return {
locale: zhCN
}
},
components: {
Loading // 注册全局loading 组件
},
computed: {
// 全局 loading
...mapState([
'globalLoading'
])
}
}
</script>
import request from '@/http/request'
import { Base64 } from 'js-base64'
// 登录认证接口
export function login ({ username, password, vercode, vercodeToken }) {
const data = {
ia: Base64.encode(username), // 账号
ip: Base64.encode(password), // 密码
vc: Base64.encode(vercode), // 验证码值
vt: Base64.encode(vercodeToken) // 验证码token
}
return request.request({
url: '/api/anon/auth/validate',
method: 'post',
data: data
}, true, false, false)
}
// 获取图形验证码信息接口
export function vercode () {
return request.request({ url: '/api/anon/auth/vercode', method: 'get' }, true, true, true)
}
// 获取当前用户信息
export function getInfo () {
return request.request({
url: '/api/current/user',
method: 'get'
})
}
// 退出接口
export function logout () {
return new Promise(resolve => { resolve() })
}
import request from '@/http/request'
/*
* 全系列 restful api格式, 定义通用req对象
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/8 07:18
*/
export const req = {
// 通用列表查询接口
list: (url, params) => {
return request.request({ url: url, method: 'GET', params: params }, true, true, false)
},
// 通用新增接口
add: (url, data) => {
return request.request({ url: url, method: 'POST', data: data }, true, true, false)
},
// 通用查询单条数据接口
getById: (url, bizId) => {
return request.request({ url: url + '/' + bizId, method: 'GET' }, true, true, false)
},
// 通用修改接口
updateById: (url, bizId, data) => {
return request.request({ url: url + '/' + bizId, method: 'PUT', data: data }, true, true, false)
},
// 通用删除接口
delById: (url, bizId) => {
return request.request({ url: url + '/' + bizId, method: 'DELETE' }, true, true, false)
}
}
// 全系列 restful api格式 (全局loading方式)
export const reqLoad = {
// 通用列表查询接口
list: (url, params) => {
return request.request({ url: url, method: 'GET', params: params }, true, true, true)
},
// 通用新增接口
add: (url, data) => {
return request.request({ url: url, method: 'POST', data: data }, true, true, true)
},
// 通用查询单条数据接口
getById: (url, bizId) => {
return request.request({ url: url + '/' + bizId, method: 'GET' }, true, true, true)
},
// 通用修改接口
updateById: (url, bizId, data) => {
return request.request({ url: url + '/' + bizId, method: 'PUT', data: data }, true, true, true)
},
// 通用删除接口
delById: (url, bizId) => {
return request.request({ url: url + '/' + bizId, method: 'DELETE' }, true, true, true)
}
}
/** 角色管理页面 **/
export const API_URL_ENT_LIST = '/api/sysEnts'
export const API_URL_ROLE_LIST = '/api/sysRoles'
export const API_URL_ROLE_ENT_RELA_LIST = '/api/sysRoleEntRelas'
export const API_URL_SYS_USER_LIST = '/api/sysUsers'
export const API_URL_USER_ROLE_RELA_LIST = '/api/sysUserRoleRelas'
/** 服务商、商户管理 **/
export const API_URL_ISV_LIST = '/api/isvInfo'
export const API_URL_MCH_LIST = '/api/mchInfo'
/** 商户App管理 **/
export const API_URL_MCH_APP = '/api/mchApps'
/** 支付订单管理 **/
export const API_URL_PAY_ORDER_LIST = '/api/payOrder'
/** 退款订单管理 **/
export const API_URL_REFUND_ORDER_LIST = '/api/refundOrder'
/** 商户通知管理 **/
export const API_URL_MCH_NOTIFY_LIST = '/api/mchNotify'
/** 系统日志 **/
export const API_URL_SYS_LOG = 'api/sysLog'
/** 系统配置 **/
export const API_URL_SYS_CONFIG = 'api/sysConfigs'
/** 首页统计 **/
export const API_URL_MAIN_STATISTIC = 'api/mainChart'
/** 支付接口定义页面 **/
export const API_URL_IFDEFINES_LIST = '/api/payIfDefines'
export const API_URL_PAYWAYS_LIST = '/api/payWays'
/** 服务商、商户支付参数配置 **/
export const API_URL_ISV_PAYCONFIGS_LIST = '/api/isv/payConfigs'
export const API_URL_MCH_PAYCONFIGS_LIST = '/api/mch/payConfigs'
/** 商户支付通道配置 **/
export const API_URL_MCH_PAYPASSAGE_LIST = '/api/mch/payPassages'
/** 转账订单管理 **/
export const API_URL_TRANSFER_ORDER_LIST = '/api/transferOrders'
/** 上传图片/文件地址 **/
export const upload = {
avatar: request.baseUrl + '/api/ossFiles/avatar',
ifBG: request.baseUrl + '/api/ossFiles/ifBG',
cert: request.baseUrl + '/api/ossFiles/cert'
}
const api = {
user: '/user',
role_list: '/role',
service: '/service',
permission: '/permission',
permissionNoPager: '/permission/no-pager',
orgTree: '/org/tree'
}
export default api
/** 获取权限树状结构图 **/
export function getEntTree (sysType) {
return request.request({ url: '/api/sysEnts/showTree?sysType=' + sysType, method: 'GET' })
}
/** 退款接口 */
export function payOrderRefund (payOrderId, refundAmount, refundReason) {
return request.request({
url: '/api/payOrder/refunds/' + payOrderId,
method: 'POST',
data: { refundAmount, refundReason }
})
}
/** 更新用户角色信息 */
export function uSysUserRoleRela (sysUserId, roleIdList) {
return request.request({
url: 'api/sysUserRoleRelas/relas/' + sysUserId,
method: 'POST',
data: { roleIdListStr: JSON.stringify(roleIdList) }
})
}
export function getRoleList (parameter) {
return request({
url: '/api/sysRoles',
method: 'get',
params: parameter
})
}
export function getServiceList (parameter) {
return request({
url: api.service,
method: 'get',
params: parameter
})
}
export function getPermissions (parameter) {
return request({
url: api.permissionNoPager,
method: 'get',
params: parameter
})
}
export function getOrgTree (parameter) {
return request({
url: api.orgTree,
method: 'get',
params: parameter
})
}
// id == 0 add post
// id != 0 update put
export function saveService (parameter) {
return request({
url: api.service,
method: parameter.id === 0 ? 'post' : 'put',
data: parameter
})
}
export function saveSub (sub) {
return request({
url: '/sub',
method: sub.id === 0 ? 'post' : 'put',
data: sub
})
}
export function getIsvPayConfigUnique (infoId, ifCode) {
return request.request({
url: '/api/isv/payConfigs/' + infoId + '/' + ifCode,
method: 'get'
})
}
export function getMchPayConfigUnique (infoId, ifCode) {
return request.request({
url: '/api/mch/payConfigs/' + infoId + '/' + ifCode,
method: 'get'
})
}
export function getAvailablePayInterfaceList (mchNo, wayCode) {
return request.request({
url: '/api/mch/payPassages/availablePayInterface/' + mchNo + '/' + wayCode,
method: 'GET'
})
}
export function getPayAmountWeek () {
return request.request({
url: API_URL_MAIN_STATISTIC + '/payAmountWeek',
method: 'GET'
})
}
export function getNumCount () {
return request.request({
url: API_URL_MAIN_STATISTIC + '/numCount',
method: 'GET'
})
}
export function getPayCount (parameter) {
return request.request({
url: API_URL_MAIN_STATISTIC + '/payCount',
method: 'GET',
params: parameter
})
}
export function getPayType (parameter) {
return request.request({
url: API_URL_MAIN_STATISTIC + '/payTypeCount',
method: 'GET',
params: parameter
})
}
export function getMainUserInfo (parameter) {
return request.request({
url: API_URL_MAIN_STATISTIC + '/' + parameter,
method: 'GET'
})
}
export function updateUserPass (parameter) {
return request.request({
url: '/api/current/modifyPwd',
method: 'put',
data: parameter
})
}
export function updateUserInfo (parameter) {
return request.request({
url: '/api/current/user',
method: 'put',
data: parameter
})
}
export function getUserInfo () {
return request.request({
url: '/api/current/user',
method: 'get'
})
}
export function getConfigs (parameter) {
return request.request({
url: API_URL_SYS_CONFIG + '/' + parameter,
method: 'GET'
})
}
export function getEntBySysType (entId, sysType) {
return request.request({
url: '/api/sysEnts/bySysType',
method: 'GET',
params: { entId: entId, sysType: sysType }
})
}
export function mchNotifyResend (notifyId) {
return request.request({
url: '/api/mchNotify/resend/' + notifyId,
method: 'POST'
})
}
/** 查询支付宝授权地址URL **/
export function queryAlipayIsvsubMchAuthUrl (mchAppId) {
return request.request({
url: '/api/mch/payConfigs/alipayIsvsubMchAuthUrls/' + mchAppId,
method: 'GET'
})
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<defs>
<clipPath id="clip-path">
<rect id="矩形_2548" data-name="矩形 2548" width="32" height="32" transform="translate(6848 11598)" fill="#fff" stroke="#707070" stroke-width="1"/>
</clipPath>
<clipPath id="clip-path-2">
<rect id="矩形_2547" data-name="矩形 2547" width="32" height="29.211" transform="translate(0 0)" fill="#1953ff"/>
</clipPath>
</defs>
<g id="logo-jeepay" transform="translate(-6848 -11598)" clip-path="url(#clip-path)">
<g id="组_1000" data-name="组 1000" transform="translate(3462.959 9987.395)">
<g id="组_999" data-name="组 999" transform="translate(3385.041 1612)" clip-path="url(#clip-path-2)">
<path id="路径_4157" data-name="路径 4157" d="M3398.508,1679.5h0l-4.173,3.659a2.08,2.08,0,0,0,1.371,3.644h7.49a.729.729,0,0,0,.553-1.2Z" transform="translate(-3390.837 -1657.592)" fill="#1953ff" opacity="0.5"/>
<path id="路径_4158" data-name="路径 4158" d="M3387.958,1615.772l-2.874,20.448a4.382,4.382,0,0,0,4.339,4.991h1.628a.73.73,0,0,0,.723-.628l.762-5.418a1.459,1.459,0,0,1,1.445-1.256h4.765a1.46,1.46,0,0,0,1.446-1.256l.673-4.789a1.461,1.461,0,0,1,1.446-1.257h4.353a1.461,1.461,0,0,1,1.446,1.664l-.792,5.639-.91,6.473a.729.729,0,0,0,.722.83h2.655a4.382,4.382,0,0,0,4.339-3.772l2.874-20.448a4.381,4.381,0,0,0-4.338-4.991H3392.3A4.382,4.382,0,0,0,3387.958,1615.772Zm19.628,7.182h-4.351a1.462,1.462,0,0,1-1.447-1.665l.615-4.379a1.462,1.462,0,0,1,1.448-1.258h4.351a1.462,1.462,0,0,1,1.448,1.665l-.615,4.379A1.462,1.462,0,0,1,3407.586,1622.954Z" transform="translate(-3385.041 -1612)" fill="#1953ff"/>
</g>
</g>
</g>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="90.000000pt" height="32.000000pt" viewBox="0 0 90.000000 32.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,32.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
</g>
</svg>
@jee-theme: #1A53FF; //主题色
@jee-back: #F0F2F5; //主要背景色
@jee-card-back: #FFF; //卡片底色
@jee-theme-mask: rgba(26,83,255,0.1); //主体遮罩色(10% 透明度)
@jee-strengthen: #596380; //强化色
@jee-theme-hover: #0033CC; //主题Hover
@jee-warning: #FF4B33; //危险,强化警告色
@jee-inside-link: #1A79FF; //内部链接
@jee-external-link: #AE1B6E; //外部链接
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="308" height="230" viewBox="0 0 308 230"><defs><style>.a{fill:none;}.b{clip-path:url(#a);}.c{opacity:0.05;}.d{opacity:0.1;}.e{fill:#999691;}.f{fill:#ffd200;}.g{fill:#aeb8c2;}.h{fill:#ff4633;}.i{fill:#fff;}</style><clipPath id="a"><rect class="a" width="308" height="230" transform="translate(179 574)"/></clipPath></defs><g transform="translate(-179 -574)"><g class="b"><ellipse class="c" cx="154" cy="35" rx="154" ry="35" transform="translate(179 734)"/><ellipse class="d" cx="34" cy="7.727" rx="34" ry="7.727" transform="translate(354 774.773)"/><path class="e" d="M235.514,736.729H179V716.794l40.835-86.53H244.19l-40.835,86.53h32.159V683.575h21.607v33.219h11.958v19.935H257.121V757.8H235.514Z"/><path class="e" d="M290.391,714.573V673.478c0-27.189,18.694-45.883,45.883-45.883s45.884,18.694,45.884,45.883v41.095c0,27.2-18.694,45.883-45.884,45.883S290.391,741.777,290.391,714.573Zm69.979,1.515v-44.2a24.092,24.092,0,1,0-48.184,0v44.2a24.092,24.092,0,0,0,48.184,0Z"/><path class="e" d="M487,717.948c0,24.175-19.574,42.249-43.489,42.249-19.134,0-36.313-11.871-41.809-30.378l20.642-5.582A21.347,21.347,0,0,0,443.424,740,21.571,21.571,0,0,0,465.3,717.948c0-12.578-9.03-22.242-21.875-22.242a23.294,23.294,0,0,0-11.07,3.015l-9.744-16.833,36.847-31.532H406.664V630.264H484.88v20.193L456.089,678.08C475.663,682.075,487,698.548,487,717.948Z"/><path class="f" d="M487,649.66,179,736.34v-19L487,630.66Z"/><path d="M194.8,732l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M218.8,725.241l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M242.8,718.487l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M266.8,711.733l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M290.8,704.978l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M314.8,698.224l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M338.8,691.47l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M362.8,684.715l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M386.8,677.961l-12,3.126,2.394-19.628,12-3.126Z"/><path d="M410.8,671.207l-12,3.126L401.2,654.7l12-3.126Z"/><path d="M434.8,664.452l-12,3.126L425.2,647.95l12-3.126Z"/><path d="M458.8,657.7l-12,3.126L449.2,641.2l12-3.126Z"/><path d="M482.8,650.944l-12,3.126,2.394-19.628,12-3.126Z"/><path class="g" d="M386,650V782c0,.552.895,1,2,1s2-.448,2-1V650Z"/><rect class="h" width="80" height="80" rx="9.891" transform="translate(348 574)"/><path class="i" d="M388,584a30,30,0,1,0,30,30A30,30,0,0,0,388,584Zm0,55a25,25,0,1,1,25-25A25,25,0,0,1,388,639Z"/><rect class="i" width="25" height="5" transform="translate(375.5 611.5)"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="308" height="230" viewBox="0 0 308 230"><defs><style>.a{fill:none;}.b{clip-path:url(#a);}.c{opacity:0.05;}.d{fill:#f5f5f7;}.e{fill:#dce0e6;}.f{fill:#24285b;}.g{fill:#596380;}.h{fill:#ffd200;}.i{fill:#fff;}.j{fill:#97a3ad;}</style><clipPath id="a"><rect class="a" width="308" height="230" transform="translate(1010 582)"/></clipPath></defs><g transform="translate(-1010 -582)"><g class="b"><ellipse class="c" cx="154" cy="35" rx="154" ry="35" transform="translate(1010 742)"/><ellipse class="c" cx="121" cy="2" rx="121" ry="2" transform="translate(1043 752)"/><rect class="d" width="228.672" height="158.82" transform="translate(1049.664 582)"/><rect class="e" width="228.672" height="125.754" transform="translate(1049.664 615.066)"/><ellipse class="f" cx="4.398" cy="4.429" rx="4.398" ry="4.429" transform="translate(1063.711 592.142)"/><ellipse class="g" cx="4.398" cy="4.429" rx="4.398" ry="4.429" transform="translate(1076.794 592.142)"/><ellipse class="h" cx="4.398" cy="4.429" rx="4.398" ry="4.429" transform="translate(1089.123 592.142)"/><path class="i" d="M1111.9,664.221a2.54,2.54,0,0,1,0-3.575l0,0,14.97-15.067a2.5,2.5,0,0,1,3.545.2,2.542,2.542,0,0,1,0,3.369l-14.971,15.077A2.5,2.5,0,0,1,1111.9,664.221Z"/><path class="i" d="M1127.106,664.464l-14.97-15.077a2.541,2.541,0,0,1-.057-3.575,2.5,2.5,0,0,1,3.55-.057c.021.02.041.041.061.062l14.961,15.067a2.542,2.542,0,0,1,.066,3.575,2.5,2.5,0,0,1-3.549.067l-.062-.062Z"/><path class="i" d="M1194.91,664.221a2.54,2.54,0,0,1-.005-3.575l.005,0,14.97-15.067a2.5,2.5,0,0,1,3.544-.2,2.539,2.539,0,0,1,.2,3.569,2.483,2.483,0,0,1-.2.2l-14.96,15.077A2.517,2.517,0,0,1,1194.91,664.221Z"/><path class="i" d="M1210.151,664.464l-14.97-15.077a2.541,2.541,0,0,1-.057-3.575,2.5,2.5,0,0,1,3.549-.057l.062.062,14.96,15.067a2.541,2.541,0,0,1,.067,3.575,2.5,2.5,0,0,1-3.549.067l-.062-.062Z"/><path class="i" d="M1142.82,707.39a2.508,2.508,0,0,1-2.49-2.326c-.7-8.605,2.54-25.543,19.8-28.01,5.392-.759,9.9.485,13.394,3.721,8.2,7.594,7.39,23.561,7.36,24.269a2.514,2.514,0,1,1-5.02-.283h0c0-.142.713-14.258-5.743-20.225-2.37-2.184-5.4-2.973-9.288-2.426-16.948,2.335-15.573,21.72-15.5,22.56a2.523,2.523,0,0,1-2.3,2.72Z"/><ellipse cx="52.8" cy="12" rx="52.8" ry="12" transform="translate(1111.2 765)"/><path class="j" d="M1065.337,756.844H1010V737.324l39.985-84.729h23.855l-39.985,84.729h31.482V704.8H1086.5v32.527H1098.2v19.519H1086.5v20.635h-21.158Z"/><path class="j" d="M1285.134,756.844H1229.8V737.324l39.985-84.729h23.855l-39.985,84.729h31.482V704.8h21.158v32.527H1318v19.519h-11.709v20.635h-21.158Z"/><path class="j" d="M1142.457,787.955a23.67,23.67,0,0,1,42.566.054,115.012,115.012,0,0,0,21.241-3.822c-5.762-17.839-21.556-29.205-42.531-29.205-20.925,0-36.693,11.3-42.5,29.049A111.5,111.5,0,0,0,1142.457,787.955Z"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="308" height="230" viewBox="0 0 308 230"><defs><style>.a{fill:none;}.b{clip-path:url(#a);}.c{fill:#e6e6e6;}.d{fill:#f5f5f7;}.e{fill:#9294ad;}.f{fill:#ffd200;}.g{fill:#aeb8c2;}.h{fill:#dce0e6;}.i{fill:#24285b;}.j{fill:#ff4d4d;}.k{fill:#fff;}</style><clipPath id="a"><rect class="a" width="308" height="230" transform="translate(638 574)"/></clipPath></defs><g transform="translate(-638 -574)"><g class="b"><path class="c" d="M788,799.455H748.216v-3.017h36.743V742.822H788Z"/><path class="d" d="M879.86,659.975c-.944,0-1.868.06-2.781.15v-1.3a39.4,39.4,0,0,0-39.585-39.217h-1.675c-.724-25.9-22.5-46.31-48.642-45.593a47.1,47.1,0,0,0-46.021,48.19,46.481,46.481,0,0,0,1.192,9.239,39.2,39.2,0,0,0,1.492,78.363H879.85a24.909,24.909,0,1,0,0-49.815h0Z"/><path class="e" d="M724.522,702.141c0,23.811-20.829,42.683-44.952,42.683A42.973,42.973,0,0,1,638,713.341l20.651-5.468c2.582,10.23,12.107,16.579,21.72,16.579a22.462,22.462,0,0,0,22.61-22.311c0-12.346-10.326-22.223-22.61-22.223-9.88,0-16.2,4.321-19.672,8.289l-18.338-5.82,3.917-67.2h69.61v19.93h-50.56l-1.959,31.219a39.764,39.764,0,0,1,19.94-5.644C707.342,660.693,724.522,678.33,724.522,702.141Z"/><path class="e" d="M744.521,699.142V658.224c0-27.074,18.782-45.682,46.11-45.682s46.109,18.608,46.109,45.682v40.918c0,27.074-18.782,45.682-46.109,45.682S744.521,726.216,744.521,699.142Zm70.322,1.5V656.636a24.212,24.212,0,0,0-48.424,0v44.006a24.213,24.213,0,0,0,48.424,0Z"/><path class="e" d="M853.89,699.142V658.224c0-27.074,18.782-45.682,46.11-45.682s46.11,18.608,46.11,45.682v40.918c0,27.074-18.782,45.682-46.11,45.682S853.89,726.216,853.89,699.142Zm70.322,1.5V656.636a24.212,24.212,0,0,0-48.424,0v44.006a24.213,24.213,0,0,0,48.424,0Z"/><rect class="f" width="94.385" height="58.936" transform="translate(743.832 700.859)"/><rect class="g" width="94.385" height="58.936" transform="translate(743.832 700.859)"/><rect class="h" width="111.021" height="28.91" transform="translate(735.691 676.123)"/><rect class="i" width="66.239" height="6.727" transform="translate(748.216 686.741)"/><ellipse class="j" cx="5.542" cy="5.49" rx="5.542" ry="5.49" transform="translate(823.063 685.615)"/><rect class="h" width="111.021" height="28.91" transform="translate(735.691 710.975)"/><rect class="i" width="66.239" height="6.727" transform="translate(748.216 721.584)"/><ellipse class="k" cx="5.542" cy="5.49" rx="5.542" ry="5.49" transform="translate(823.063 720.468)"/><rect class="h" width="111.021" height="28.91" transform="translate(735.691 745.828)"/><rect class="i" width="66.239" height="6.727" transform="translate(748.216 756.437)"/><ellipse class="k" cx="5.542" cy="5.49" rx="5.542" ry="5.49" transform="translate(823.063 755.321)"/><rect class="c" width="36.581" height="3.017" transform="translate(786.482 796.438)"/><ellipse class="i" cx="5.988" cy="5.933" rx="5.988" ry="5.933" transform="translate(743.842 792.134)"/><ellipse class="i" cx="5.988" cy="5.933" rx="5.988" ry="5.933" transform="translate(817.074 792.134)"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="76" height="76" viewBox="0 0 76 76"><defs><style>.a{fill:#1953ff;}</style></defs><path class="a" d="M-1198-1084a6.007,6.007,0,0,1-6-6v-64a6.007,6.007,0,0,1,6-6h64a6.007,6.007,0,0,1,6,6v64a6.006,6.006,0,0,1-6,6Zm-4-70v64a4,4,0,0,0,4,4h64a4,4,0,0,0,4-4v-64a4,4,0,0,0-4-4h-64A4.005,4.005,0,0,0-1202-1154Zm35,47v-14h-14a1,1,0,0,1-1-1,1,1,0,0,1,1-1h14v-14a1,1,0,0,1,1-1,1,1,0,0,1,1,1v14h14a1,1,0,0,1,1,1,1,1,0,0,1-1,1h-14v14a1,1,0,0,1-1,1A1,1,0,0,1-1167-1107Z" transform="translate(1204 1160)"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="76" height="76" viewBox="0 0 76 76"><defs><style>.a{fill:#ccced1;}</style></defs><path class="a" d="M-1198-1084a6.007,6.007,0,0,1-6-6v-64a6.007,6.007,0,0,1,6-6h64a6.007,6.007,0,0,1,6,6v64a6.006,6.006,0,0,1-6,6Zm-4-70v64a4,4,0,0,0,4,4h64a4,4,0,0,0,4-4v-64a4,4,0,0,0-4-4h-64A4.005,4.005,0,0,0-1202-1154Zm35,47v-14h-14a1,1,0,0,1-1-1,1,1,0,0,1,1-1h14v-14a1,1,0,0,1,1-1,1,1,0,0,1,1,1v14h14a1,1,0,0,1,1,1,1,1,0,0,1-1,1h-14v14a1,1,0,0,1-1,1A1,1,0,0,1-1167-1107Z" transform="translate(1204 1160)"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920" height="970" viewBox="0 0 1920 970"><defs><style>.a{fill:url(#a);}.b{clip-path:url(#b);}.c{filter:url(#n);}.d{filter:url(#k);}.e{filter:url(#h);}.f{filter:url(#e);}</style><linearGradient id="a" y1="0.383" x2="1" y2="0.589" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f1f8ff"/><stop offset="1" stop-color="#f7fbfe"/></linearGradient><clipPath id="b"><rect class="a" width="1920" height="970"/></clipPath><filter id="e" x="-169" y="375" width="756" height="756" filterUnits="userSpaceOnUse"><feOffset dx="20" dy="-20" input="SourceAlpha"/><feGaussianBlur stdDeviation="30" result="f"/><feFlood flood-color="#211f47" flood-opacity="0.071"/><feComposite operator="in" in2="f"/><feComposite in="SourceGraphic"/></filter><filter id="h" x="1230" y="568" width="433" height="433" filterUnits="userSpaceOnUse"><feOffset dx="2" dy="-10" input="SourceAlpha"/><feGaussianBlur stdDeviation="30" result="i"/><feFlood flood-color="#211f47" flood-opacity="0.071"/><feComposite operator="in" in2="i"/><feComposite in="SourceGraphic"/></filter><filter id="k" x="1440" y="88.44" width="655.121" height="655.121" filterUnits="userSpaceOnUse"><feOffset dx="2" dy="30" input="SourceAlpha"/><feGaussianBlur stdDeviation="30" result="l"/><feFlood flood-color="#211f47" flood-opacity="0.122"/><feComposite operator="in" in2="l"/><feComposite in="SourceGraphic"/></filter><filter id="n" x="422.061" y="2.561" width="350.879" height="350.879" filterUnits="userSpaceOnUse"><feOffset dx="2" dy="10" input="SourceAlpha"/><feGaussianBlur stdDeviation="30" result="o"/><feFlood flood-color="#211f47" flood-opacity="0.122"/><feComposite operator="in" in2="o"/><feComposite in="SourceGraphic"/></filter></defs><g class="b"><rect class="a" width="1920" height="970"/><g class="f" transform="matrix(1, 0, 0, 1, 0, 0)"><circle class="a" cx="288" cy="288" r="288" transform="translate(-99 485)"/></g><g class="e" transform="matrix(1, 0, 0, 1, 0, 0)"><circle class="a" cx="126.5" cy="126.5" r="126.5" transform="translate(1318 668)"/></g><g class="d" transform="matrix(1, 0, 0, 1, 0, 0)"><rect class="a" width="335.961" height="335.961" rx="30" transform="translate(1528 386) rotate(-45)"/></g><g class="c" transform="matrix(1, 0, 0, 1, 0, 0)"><rect class="a" width="170.879" height="170.879" transform="translate(510.06 82.56)"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Group 21</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
<g id="Group-21" transform="translate(77.000000, 73.000000)">
<g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
<ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
<ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
<path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
<path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
<path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
<g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
<ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
<path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
</g>
</g>
<g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
<ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
<ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
<path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
<g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
<ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
<path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
</g>
<ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
<ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
<ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
<path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
</g>
<g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
<ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
<g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
<ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
<path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
</g>
<path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
<ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
<ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
<path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
</g>
<g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
<g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
<circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
<path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
</g>
<circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
<path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
<path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
<polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
<path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
<path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
<path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
<circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
<circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
<circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
<circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
<circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"><defs><style>.a{fill:#fff;stroke:#707070;}.b{fill:#596380;}.c{clip-path:url(#a);}.d{clip-path:url(#b);}</style><clipPath id="a"><rect class="a" width="14" height="14" transform="translate(796 520)"/></clipPath><clipPath id="b"><rect class="b" width="12" height="12" transform="translate(0)"/></clipPath></defs><g class="c" transform="translate(-796 -520)"><g transform="translate(-100 289.628)"><g class="d" transform="translate(897 231.372)"><path class="b" d="M1182.9,231.267h-3.343v3.745a2.254,2.254,0,0,1,0,4.508v3.75h3.343a2.291,2.291,0,0,0,2.258-2.308V233.58a2.289,2.289,0,0,0-2.258-2.313Zm0,0" transform="translate(-1173.16 -231.269)"/><path class="b" d="M903.133,235.581a1.657,1.657,0,0,0-.531.086v-4.3h-3.343A2.291,2.291,0,0,0,897,233.68v7.381a2.291,2.291,0,0,0,2.258,2.308H902.6v-4.293a1.713,1.713,0,0,0,.531.086,1.791,1.791,0,0,0,0-3.582Zm0,0" transform="translate(-897 -231.372)"/></g></g></g></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1621586617012" class="icon" viewBox="0 0 1146 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6384" xmlns:xlink="http://www.w3.org/1999/xlink" width="17.90625" height="16"><defs><style type="text/css"></style></defs><path d="M0 788.389381a507.469027 108.743363 0 1 0 1014.938053 0 507.469027 108.743363 0 1 0-1014.938053 0Z" fill="#F3F3F8" p-id="6385"></path><path d="M321.880354 246.303717h367.915044l174.714337 220.749026s-174.895575 180.151504-352.328496 179.607788-357.584425-181.238938-357.584425-181.238938z" fill="#FBFBFD" p-id="6386"></path><path d="M797.451327 815.575221H217.486726a63.433628 63.433628 0 0 1-63.433629-63.433628V471.221239h166.558584l14.680354 29.360708A81.738761 81.738761 0 0 0 416.849558 579.964602h199.362831a63.614867 63.614867 0 0 0 63.433629-60.533806L711.72531 471.221239h149.159646v280.920354A63.433628 63.433628 0 0 1 797.451327 815.575221z" fill="#FBFBFD" p-id="6387"></path><path d="M797.451327 806.513274a54.371681 54.371681 0 0 0 54.371682-54.371681v-271.858407h-135.385487L688.707965 522.330619a72.495575 72.495575 0 0 1-72.495576 66.69593H416.849558a90.619469 90.619469 0 0 1-90.61947-86.088496l-11.236814-22.654867H163.115044v271.858407a54.371681 54.371681 0 0 0 54.371682 54.371681h579.964601m0 18.123894H217.486726a72.495575 72.495575 0 0 1-72.495576-72.495575v-289.982301h181.238938l18.123894 36.247788a72.495575 72.495575 0 0 0 72.495576 72.495575h199.362831a54.371681 54.371681 0 0 0 54.371682-54.371682l36.247787-54.371681h163.115045v289.982301a72.495575 72.495575 0 0 1-72.495576 72.495575z" fill="#E2E2EE" p-id="6388"></path><path d="M863.059823 467.958938L684.539469 253.734513H330.398584L151.87823 467.958938l-13.774159-11.599292L322.061593 235.610619h370.814867l183.957522 220.749027z" fill="#E2E2EE" p-id="6389"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="90.000000pt" height="32.000000pt" viewBox="0 0 90.000000 32.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,32.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"><defs><style>.a{fill:#fff;stroke:#707070;}.b{fill:#596380;}.c{clip-path:url(#a);}.d{clip-path:url(#b);}</style><clipPath id="a"><rect class="a" width="14" height="14" transform="translate(786 458)"/></clipPath><clipPath id="b"><rect class="b" width="11" height="14"/></clipPath></defs><g class="c" transform="translate(-786 -458)"><g transform="translate(155.5 328)"><g transform="translate(632 130)"><g class="d" transform="translate(0)"><path class="b" d="M636.689,140.115V141.7a.687.687,0,1,0,1.374,0v-1.584a1.4,1.4,0,0,0,.687-1.21,1.374,1.374,0,1,0-2.748,0,1.4,1.4,0,0,0,.687,1.21Zm-2.061-4.7v-2.1a2.748,2.748,0,1,1,5.5,0v2.1H641.5a1.386,1.386,0,0,1,1.374,1.4V143.1a1.386,1.386,0,0,1-1.374,1.4h-8.243a1.386,1.386,0,0,1-1.374-1.4v-6.288a1.386,1.386,0,0,1,1.374-1.4Zm2.748-3.493a1.386,1.386,0,0,0-1.374,1.4v2.1h2.748v-2.1a1.386,1.386,0,0,0-1.374-1.4Zm0,0" transform="translate(-631.882 -130.511)"/></g></g></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90.667" height="22" viewBox="0 0 90.667 22"><defs><clipPath id="a"><path d="M2404.472,992h-22.8l3.2-22h22.8Z" transform="translate(-2381.676 -970)" fill="#1a53ff"/></clipPath><clipPath id="b"><rect width="62.667" height="16" fill="#262626"/></clipPath></defs><g transform="translate(-30 -21)"><g transform="translate(30 21)"><g clip-path="url(#a)"><path d="M2388.177,1037.5h0l-6.5,5.5h11.4Z" transform="translate(-2381.676 -1021)" fill="#1a53ff" opacity="0.5"/><path d="M2384.881,970l-3.2,22h5.7l.8-5.5h5.7l.8-5.5h5.7l-.8,5.5-.8,5.5h5.7l3.2-22Zm15.9,8.25h-5.7l.8-5.5h5.7Z" transform="translate(-2381.677 -970)" fill="#1a53ff"/></g></g><g transform="translate(-628.729 -2051)"><g transform="translate(686.73 2076)" clip-path="url(#b)"><path d="M930.451,2092.935a2.5,2.5,0,0,0-2.543-1.935h-5.479l-.225,1.6h5.367a1.366,1.366,0,0,1,1.082.476,1.014,1.014,0,0,1-.781,1.657h-3.554a3.383,3.383,0,0,0-3.243,2.844l-.175,1.245a2.414,2.414,0,0,0,2.443,2.845h2.488a3.952,3.952,0,0,0,2.037-.588l-.082.588h1.6l.5-3.556.474-3.378.125-.889h0A2.585,2.585,0,0,0,930.451,2092.935Zm-1.915,3.4-.1.711-.15,1.067a2.329,2.329,0,0,1-2.229,1.956h-2.488a1.057,1.057,0,0,1-1.069-1.244l.175-1.245a1.482,1.482,0,0,1,1.419-1.244h3.554a2.665,2.665,0,0,0,.911-.163Z" transform="translate(-879.269 -2088.333)" fill="#262626"/><path d="M802.041,2091h-3.2a3.383,3.383,0,0,0-3.242,2.844l-.237,1.689-.225,1.6-.237,1.689a2.414,2.414,0,0,0,2.443,2.845h3.2a3.383,3.383,0,0,0,3.242-2.845l.013-.089h-1.6l-.013.089a1.482,1.482,0,0,1-1.418,1.244h-3.2a1.057,1.057,0,0,1-1.069-1.244l.237-1.689h7.285l.225-1.6.237-1.689A2.414,2.414,0,0,0,802.041,2091Zm-5.079,4.533.237-1.689a1.482,1.482,0,0,1,1.419-1.244h3.2a1.057,1.057,0,0,1,1.069,1.244l-.237,1.689Z" transform="translate(-775.657 -2088.333)" fill="#262626"/><path d="M740.041,2091h-3.2a3.383,3.383,0,0,0-3.242,2.844l-.237,1.689-.225,1.6-.237,1.689a2.415,2.415,0,0,0,2.444,2.845h3.2a3.383,3.383,0,0,0,3.242-2.845l.013-.089h-1.6l-.013.089a1.482,1.482,0,0,1-1.418,1.244h-3.2a1.057,1.057,0,0,1-1.069-1.244l.237-1.689h7.285l.225-1.6.237-1.689A2.414,2.414,0,0,0,740.041,2091Zm-5.079,4.533.237-1.689a1.482,1.482,0,0,1,1.418-1.244h3.2a1.057,1.057,0,0,1,1.069,1.244l-.237,1.689Z" transform="translate(-724.674 -2088.333)" fill="#262626"/><path d="M693.933,2076H690.38l-.25,1.778h1.777l-.849,6.044-.325,2.311a1.694,1.694,0,0,1-1.621,1.423H686.98l-.25,1.777h2.132a3.806,3.806,0,0,0,3.648-3.2l1.174-8.355h0Z" transform="translate(-686.73 -2076)" fill="#262626"/><path d="M990.5,2091l-.225,1.6-.325,2.311-.474,3.377-.075.533a1.482,1.482,0,0,1-1.418,1.244h-3.2a1.057,1.057,0,0,1-1.069-1.244l.549-3.911.325-2.311.225-1.6h-1.6l-1.1,7.822a2.414,2.414,0,0,0,2.443,2.845h3.2a3.094,3.094,0,0,0,1.284-.29l-.041.29a1.268,1.268,0,0,1-1.216,1.066H982.1l-.225,1.6h5.686a3.171,3.171,0,0,0,3.04-2.666l.4-2.845.075-.533L992.1,2091Z" transform="translate(-929.43 -2088.333)" fill="#262626"/><path d="M862.644,2091h-3.2a3.094,3.094,0,0,0-1.285.29l.041-.29h-1.6l-.4,2.844-.7,4.978-.774,5.511h1.6l.415-2.956a2.574,2.574,0,0,0,1.2.29h3.2a3.383,3.383,0,0,0,3.242-2.845l.7-4.978A2.414,2.414,0,0,0,862.644,2091Zm.145,7.822a1.482,1.482,0,0,1-1.419,1.244h-3.2a1.057,1.057,0,0,1-1.069-1.244l.7-4.978a1.482,1.482,0,0,1,1.418-1.244h3.2a1.057,1.057,0,0,1,1.069,1.244Z" transform="translate(-824.879 -2088.333)" fill="#262626"/></g></g></g></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1621851766037" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2360" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><defs><style type="text/css"></style></defs><path d="M243.2 512c0-49.664-39.936-89.6-89.6-89.6S64 462.336 64 512s39.936 89.6 89.6 89.6 89.6-39.936 89.6-89.6z m179.2 0c0 49.664 39.936 89.6 89.6 89.6s89.6-39.936 89.6-89.6-39.936-89.6-89.6-89.6-89.6 39.936-89.6 89.6z m358.4 0c0 49.664 39.936 89.6 89.6 89.6S960 561.664 960 512s-39.936-89.6-89.6-89.6c-49.152 0-89.6 39.936-89.6 89.6z" p-id="2361" fill="#2c2c2c"></path></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="20.001" height="20" viewBox="0 0 20.001 20"><defs><style>.a{fill:#252626;}</style></defs><path class="a" d="M-3862-1142a3,3,0,0,1-3-3v-14a3,3,0,0,1,3-3h14a3,3,0,0,1,3,3v14a3,3,0,0,1-3,3Zm-1-17v14a1,1,0,0,0,1,1h14a1,1,0,0,0,1-1v-14a1,1,0,0,0-1-1h-14A1,1,0,0,0-3863-1159Zm11,12v-2a1,1,0,0,1,1-1,1,1,0,0,1,1,1v2a1,1,0,0,1-1,1A1,1,0,0,1-3852-1147Zm-4,0v-10a1,1,0,0,1,1-1,1,1,0,0,1,1,1v10a1,1,0,0,1-1,1A1,1,0,0,1-3856-1147Zm-4,0v-7a1,1,0,0,1,1-1,1,1,0,0,1,1,1v7a1,1,0,0,1-1,1A1,1,0,0,1-3860-1147Z" transform="translate(3865 1162)"/></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1619595883977" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3229" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M495.055 647.042a26.196 26.196 0 0 1-18.583-7.697L250.689 413.561c-10.263-10.263-10.263-26.903 0-37.166 10.263-10.263 26.903-10.263 37.166 0l207.2 207.2 207.2-207.2c10.263-10.263 26.904-10.263 37.167 0 10.262 10.263 10.262 26.903 0 37.166L513.638 639.345a26.196 26.196 0 0 1-18.583 7.697z" fill="#2c2c2c" p-id="3230"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1619597015272" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5736" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M617.6 233.6c12.8-12.8 32-12.8 44.8 0 12.8 12.8 12.8 28.8 3.2 41.6l-3.2 3.2-233.6 233.6 233.6 233.6c12.8 12.8 12.8 28.8 3.2 41.6l-3.2 3.2c-12.8 12.8-28.8 12.8-41.6 3.2l-3.2-3.2-256-256c-12.8-12.8-12.8-28.8-3.2-41.6l3.2-3.2 256-256z" fill="#2c2c2c" p-id="5737"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1619597331494" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1762" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M406.4 233.6c-12.8-12.8-32-12.8-44.8 0-12.8 12.8-12.8 28.8-3.2 41.6l3.2 3.2 233.6 233.6-233.6 233.6c-12.8 12.8-12.8 28.8-3.2 41.6l3.2 3.2c12.8 12.8 28.8 12.8 41.6 3.2l3.2-3.2 256-256c12.8-12.8 12.8-28.8 3.2-41.6l-3.2-3.2-256-256z" fill="#2c2c2c" p-id="1763"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1619595944852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4607" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M495.055 308.698a26.196 26.196 0 0 0-18.583 7.697L250.689 542.179c-10.263 10.263-10.263 26.903 0 37.166s26.903 10.263 37.166 0l207.2-207.2 207.2 207.2c10.263 10.263 26.904 10.263 37.167 0 10.262-10.263 10.262-26.903 0-37.166L513.638 316.395a26.196 26.196 0 0 0-18.583-7.697z" fill="#2c2c2c" p-id="4608"></path></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"><defs><style>.a,.b{fill:#1a53ff;}.a{stroke:#707070;}.c{clip-path:url(#a);}.d{clip-path:url(#b);}</style><clipPath id="a"><rect class="a" width="14" height="14" transform="translate(796 520)"/></clipPath><clipPath id="b"><rect class="b" width="12" height="12" transform="translate(0)"/></clipPath></defs><g class="c" transform="translate(-796 -520)"><g transform="translate(-100 289.628)"><g class="d" transform="translate(897 231.372)"><path class="b" d="M1182.9,231.267h-3.343v3.745a2.254,2.254,0,0,1,0,4.508v3.75h3.343a2.291,2.291,0,0,0,2.258-2.308V233.58a2.289,2.289,0,0,0-2.258-2.313Zm0,0" transform="translate(-1173.16 -231.269)"/><path class="b" d="M903.133,235.581a1.657,1.657,0,0,0-.531.086v-4.3h-3.343A2.291,2.291,0,0,0,897,233.68v7.381a2.291,2.291,0,0,0,2.258,2.308H902.6v-4.293a1.713,1.713,0,0,0,.531.086,1.791,1.791,0,0,0,0-3.582Zm0,0" transform="translate(-897 -231.372)"/></g></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"><defs><style>.a,.b{fill:#1a53ff;}.a{stroke:#707070;}.c{clip-path:url(#a);}.d{clip-path:url(#b);}</style><clipPath id="a"><rect class="a" width="14" height="14" transform="translate(786 458)"/></clipPath><clipPath id="b"><rect class="b" width="11" height="14"/></clipPath></defs><g class="c" transform="translate(-786 -458)"><g transform="translate(155.5 328)"><g transform="translate(632 130)"><g class="d" transform="translate(0)"><path class="b" d="M636.689,140.115V141.7a.687.687,0,1,0,1.374,0v-1.584a1.4,1.4,0,0,0,.687-1.21,1.374,1.374,0,1,0-2.748,0,1.4,1.4,0,0,0,.687,1.21Zm-2.061-4.7v-2.1a2.748,2.748,0,1,1,5.5,0v2.1H641.5a1.386,1.386,0,0,1,1.374,1.4V143.1a1.386,1.386,0,0,1-1.374,1.4h-8.243a1.386,1.386,0,0,1-1.374-1.4v-6.288a1.386,1.386,0,0,1,1.374-1.4Zm2.748-3.493a1.386,1.386,0,0,0-1.374,1.4v2.1h2.748v-2.1a1.386,1.386,0,0,0-1.374-1.4Zm0,0" transform="translate(-631.882 -130.511)"/></g></g></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"><defs><style>.a,.b{fill:#1a53ff;}.a{stroke:#707070;}.c{clip-path:url(#a);}.d{clip-path:url(#b);}</style><clipPath id="a"><rect class="a" width="14" height="14" transform="translate(793 387)"/></clipPath><clipPath id="b"><rect class="b" width="13" height="14" transform="translate(0 0)"/></clipPath></defs><g class="c" transform="translate(-793 -387)"><g transform="translate(216.5 256)"><g class="d" transform="translate(577 131)"><path class="b" d="M740.84,134.733A3.714,3.714,0,1,0,744.554,131a3.724,3.724,0,0,0-3.714,3.733Zm0,0" transform="translate(-738.054 -131)"/><path class="b" d="M581.643,622.52h3.714a4.631,4.631,0,0,1,3.283,1.367,4.679,4.679,0,0,1,1.36,3.3v.933H577v-.933a4.679,4.679,0,0,1,1.36-3.3,4.631,4.631,0,0,1,3.283-1.367Zm0,0" transform="translate(-577 -614.12)"/></g></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"><defs><style>.a,.b{fill:#596380;}.a{stroke:#707070;}.c{clip-path:url(#a);}.d{clip-path:url(#b);}</style><clipPath id="a"><rect class="a" width="14" height="14" transform="translate(793 387)"/></clipPath><clipPath id="b"><rect class="b" width="13" height="14" transform="translate(0 0)"/></clipPath></defs><g class="c" transform="translate(-793 -387)"><g transform="translate(216.5 256)"><g class="d" transform="translate(577 131)"><path class="b" d="M740.84,134.733A3.714,3.714,0,1,0,744.554,131a3.724,3.724,0,0,0-3.714,3.733Zm0,0" transform="translate(-738.054 -131)"/><path class="b" d="M581.643,622.52h3.714a4.631,4.631,0,0,1,3.283,1.367,4.679,4.679,0,0,1,1.36,3.3v.933H577v-.933a4.679,4.679,0,0,1,1.36-3.3,4.631,4.631,0,0,1,3.283-1.367Zm0,0" transform="translate(-577 -614.12)"/></g></g></g></svg>
\ No newline at end of file
<template>
<global-footer class="footer custom-render">
<template v-slot:links>
</template>
<template v-slot:copyright>
Copyright © 2023 <a href="http://www.juhezhifu.com" target="_blank">juhezhifu.com</a>. All rights reserved.
</template>
</global-footer>
</template>
<script>
import { GlobalFooter } from '@ant-design-vue/pro-layout'
export default {
name: 'ProGlobalFooter',
components: {
GlobalFooter
}
}
</script>
<template>
<a-dropdown placement="bottomRight">
<span class="ant-pro-account-avatar">
<a-avatar size="small" :src="greetImg" class="antd-pro-global-header-index-avatar" />
<span>{{ currentUserName }}</span>
</span>
<template v-slot:overlay>
<a-menu class="ant-pro-drop-down menu" :selected-keys="[]">
<a-menu-item v-if="$access('ENT_C_USERINFO')" key="settings" @click="handleToSettings">
<a-icon type="setting" />
账户设置
</a-menu-item>
<a-menu-divider />
<a-menu-item key="logout" @click="handleLogout">
<a-icon type="logout" />
退出登录
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<script>
export default {
name: 'AvatarDropdown',
props: {
},
data: function () {
return {
// greetImg: '', // 头像图片地址
sex: ''
}
},
computed: {
// 返回用户名
currentUserName () {
return this.$store.state.user.userName
},
// 返回头像
greetImg () {
return this.$store.state.user.avatarImgPath
}
},
methods: {
handleToSettings () {
this.$router.push({ name: 'ENT_C_USERINFO' })
},
handleLogout: function (e) {
this.$infoBox.confirmPrimary('确认退出?', '', () => {
this.$store.dispatch('Logout').then(() => {
this.$router.push({ name: 'login' })
})
})
}
}
}
</script>
<style lang="less" scoped>
.ant-pro-drop-down {
/deep/ .action {
margin-right: 8px;
}
/deep/ .ant-dropdown-menu-item {
min-width: 160px;
}
}
</style>
<template>
<div :class="wrpCls">
<avatar-dropdown :menu="showMenu" :current-user="currentUser" :class="prefixCls" />
</div>
</template>
<script>
import AvatarDropdown from './AvatarDropdown'
// import store from '@/store'
export default {
name: 'RightContent',
components: {
AvatarDropdown
},
props: {
prefixCls: {
type: String,
default: 'ant-pro-global-header-index-action'
},
isMobile: {
type: Boolean,
default: () => false
},
topMenu: {
type: Boolean,
required: true
},
theme: {
type: String,
required: true
}
},
data () {
return {
showMenu: true,
currentUser: {}
}
},
computed: {
wrpCls () {
return {
'ant-pro-global-header-index-right': true,
[`ant-pro-global-header-index-${(this.isMobile || !this.topMenu) ? 'light' : this.theme}`]: true
}
}
},
mounted () {
// console.log(store)
this.currentUser = {
name: 'dd'
}
}
}
</script>
<template>
<div class="loading">
<div>
<a-spin size="large" />
</div>
</div>
</template>
<script>
export default {
name: 'GlobalLoad',
data () {
return {}
}
}
</script>
<style scoped>
.loading{
position: fixed;
top:0;
left:0;
z-index:100;
width: 100%;
height: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.25);
}
</style>
<template>
<div>
<a-row :gutter="[24,24]" style="width:100%">
<!-- 卡片默认新增框 -->
<a-col
:xxl="24/span.xxl"
:xl="24/span.xl"
:lg="24/span.lg"
:md="24/span.md"
:sm="24/span.sm"
:xs="24/span.xs"
@click="$emit('addJeepayCard')"
v-if="addAuthority"
>
<div class="jeepay-card-add" :style="{'height': height + 'px'}">
<div class="jeepay-card-add-top">
<img src="~@/assets/svg/add-icon.svg" alt="add-icon" class="jeepay-card-add-icon">
<img src="~@/assets/svg/add-icon-hover.svg" alt="add-icon" class="jeepay-card-add-icon-hover">
</div>
<div class="jeepay-card-add-text">
新建{{ name }}
</div>
</div>
</a-col>
<!-- 数据 -->
<a-col
v-for="(item, key) in cardList"
:key="key"
:xxl="24/span.xxl"
:xl="24/span.xl"
:lg="24/span.lg"
:md="24/span.md"
:sm="24/span.sm"
:xs="24/span.xs"
>
<slot name="cardContentSlot" :record="item"></slot>
<slot name="cardOpSlot" :record="item"></slot>
</a-col>
</a-row>
</div>
</template>
<script>
export default {
name: 'JeepayCard',
props: {
span: { type: Object, default: () => ({ xxl: 6, xl: 4, lg: 4, md: 3, sm: 2, xs: 1 }) },
height: { type: Number, default: 200 },
name: { type: String, default: '' },
addAuthority: { type: Boolean, default: false },
reqCardListFunc: { type: Function, default: () => () => ({}) }
},
data () {
return {
cardList: []
}
},
created () {
this.refCardList()
},
methods: {
refCardList () {
const that = this
this.reqCardListFunc().then(resData => {
that.cardList = resData
})
}
}
}
</script>
<style lang="less" scoped>
.jeepay-card-add {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 2px dashed rgba(0, 0, 0, 0.15);
background: rgba(0, 0, 0, 0.03);
border-radius: 6px;
box-sizing: border-box;
cursor: pointer;
}
.jeepay-card-add-top {
width: 80px;
height: 80px;
position: relative;
}
.jeepay-card-add:hover {
border-color: rgba(25,83,255,0.3);
background: rgba(25,83,255,0.06);
transition: all 0.3s ease-in-out;
}
.jeepay-card-add:hover .jeepay-card-add-icon {
opacity: 0;
transition: all 0.2s ease-in-out;
}
.jeepay-card-add:hover .jeepay-card-add-icon-hover {
opacity: 1;
transition: all 0.5s ease-in-out;
}
.jeepay-card-add:hover .jeepay-card-add-text {
color: rgba(25,83,255,1);
transition: all 0.3s ease-in-out;
}
.jeepay-card-add-icon {
position: absolute;
width: 80px;
height: 80px;
opacity: 1;
}
.jeepay-card-add-icon-hover {
position: absolute;
width: 80px;
height: 80px;
opacity: 0;
}
.jeepay-card-add-text {
padding-top: 5px;
font-size: 13px;
color: rgba(0, 0, 0, 0.35);
}
</style>
<!--
Jeepay 通用表格, 支持基础分页, 检索
@author terrfly
@site https://www.jeepay.vip
@date 2021/5/8 07:18
-->
<template>
<div>
<a-table
:columns="tableColumns"
:data-source="apiResData.records"
:pagination="pagination"
:loading="showLoading"
@change="handleTableChange"
:row-selection="rowSelection"
:rowKey="rowKey"
:scroll="{ x: scrollX }"
:customRow="(record, index) => {
if(!tableRowCrossColor){
return {};
}
return { style: { 'background-color': index % 2 == 0 ? '#FCFCFC' : '#FFFFFF'} }
}"
>
<!-- 自定义列插槽, 参考:https://github.com/feseed/admin-antd-vue/blob/master/src/components/ShTable.vue -->
<!-- eslint-disable-next-line -->
<template v-for="colCustom in columnsCustomSlots" :slot="colCustom.customRender" slot-scope="record">
<slot :name="colCustom.customRender" :record="record"></slot>
</template>
</a-table>
</div>
</template>
<script>
export default {
name: 'JeepayTable', // 定义组件名称
// 传递数据参数 ( 父-->子 参数 )
props: {
initData: { type: Boolean, default: true }, // 初始化列表数据, 默认true
tableColumns: Array, // 表格数组列
reqTableDataFunc: { type: Function }, // 请求列表数据
currentChange: { type: Function, default: (v1, v2) => {} }, // 更新当前选择行事件, 默认空函数
searchData: Object, // 搜索条件参数
pageSize: { type: Number, default: 10 }, // 默认每页条数
rowSelection: Object, // checkbox选择
rowKey: { type: [String, Function] }, // 定义rowKey 如果不定义将会出现(树状结构出问题, checkbox不消失等)
scrollX: { type: Number, default: 500 }, // 表格显示滚动条的宽度
tableRowCrossColor: { type: Boolean, default: false } // 是隔行换色
},
data () {
return {
apiResData: { total: 0, records: [] }, // 接口返回数据
iPage: { pageNumber: 1, pageSize: this.pageSize }, // 默认table 分页/排序请求后端格式
pagination: { total: 0, current: 1, pageSize: this.pageSize, showSizeChanger: true, showTotal: total => `共${total}条` }, // ATable 分页配置项
showLoading: false
}
},
// 计算属性
computed: {
columnsCustomSlots () { // 自定义列插槽 1. 过滤器仅获取到包含slot属性的元素, 2. 返回slot数组
return this.tableColumns.filter(item => item.scopedSlots).map(item => item.scopedSlots)
}
},
mounted () {
if (this.initData) { // 是否自动加载数据
this.refTable(true)
}
},
methods: {
handleTableChange (pagination, filters, sorter) { // 分页、排序、筛选变化时触发
this.pagination = pagination
this.iPage = {
pageSize: pagination.pageSize, // 每页条数
pageNumber: pagination.current, // 当前页码
sortField: sorter.columnKey, // 排序字段
sortOrder: sorter.order, // 排序顺序
...filters // 过滤数据
}
this.refTable()
},
// 查询数据
refTable (isToFirst = false) {
const that = this
if (isToFirst) {
this.iPage.pageNumber = 1
this.pagination.current = 1
}
// 更新检索数据
this.showLoading = true
this.reqTableDataFunc(Object.assign({}, this.iPage, this.searchData)).then(resData => {
this.pagination.total = resData.total // 更新总数量
this.apiResData = resData // 列表数据更新
this.showLoading = false // 关闭loading
// 数据为0 ,并且为当前页面没有在第一页则需要自动跳转到上一页(解决,删除第二页数据全部删除后无数据的情况 )
if (resData.records.length === 0 && this.iPage.pageNumber > 1) {
that.$nextTick(() => {
// 最大页码
const maxPageNumber = (resData.total / this.iPage.pageSize) + ((resData.total % this.iPage.pageSize) === 0 ? 0 : 1)
if (maxPageNumber === 0) { // 已经无数据
return false
}
// 跳转到的页码
const toPageSize = (this.iPage.pageNumber - 1) > maxPageNumber ? maxPageNumber : (this.iPage.pageNumber - 1)
this.iPage.pageNumber = toPageSize
this.pagination.current = toPageSize
that.refTable(false)
})
}
// 请求成功后,关闭查询按钮的loading
that.$emit('btnLoadClose')
}).catch(res => {
this.showLoading = false
that.$emit('btnLoadClose')
}) // 关闭loading
}
}
}
</script>
<style lang="less">
// 调整antdv table默认padding高度
.ant-table-fixed{
tr{
th{
padding: 8px 8px !important;
}
th:first-child{ // 第一个表格 左填充16, 其他为8
padding-left: 16px !important;
}
td{
padding: 8px 8px !important;
}
td:first-child{
padding-left: 16px !important;
}
}
}
</style>
<!--
Jeepay 通用状态切换按钮, 支持switch和badge两个格式, 根据权限进行判断
@author terrfly
@site https://www.jeepay.vip
@date 2021/5/8 07:18
-->
<template>
<div>
<template v-if="!showSwitchType">
<div v-if="state == 0" ><a-badge status="error" text="停用" /></div>
<div v-else-if="state == 1" ><a-badge status="processing" text="启用" /></div>
<div v-else ><a-badge status="warning" text="未知" /></div>
</template>
<template v-if="showSwitchType">
<a-switch class="els" checked-children="启用" un-checked-children="停用" :checked="switchChecked" @change="onChangeInner" />
</template>
</div>
</template>
<script>
export default {
name: 'JeepayTableColState', // 定义组件名称
// 传递数据参数 ( 父-->子 参数 )
props: {
state: { type: Number, default: -1 }, // 初始化列表数据, 默认true
showSwitchType: { type: Boolean, default: false }, // 默认 badge
onChange: { type: Function, default: (checked) => { return new Promise(resolve => { resolve() }) } } // change回调事件
},
data: function () {
return { switchChecked: false }
},
mounted () {
this.switchChecked = this.state === 1
},
watch: {
state: function (o, n) {
this.switchChecked = this.state === 1
}
},
methods: {
onChangeInner: function (checked) {
const that = this
this.switchChecked = checked
// 回调输出 0 和 1; 成功不需要处理, 失败需要经状态变更为原始状态
this.onChange((checked ? 1 : 0)).then().catch(res => {
that.$nextTick(() => { that.switchChecked = !checked })
})
}
}
}
</script>
<!--
Jeepay 通用列,添加更多菜单项
@author terrfly
@site https://www.jeepay.vip
@date 2021/5/8 07:18
-->
<script>
export default {
name: 'JeepayTableColumns', // 定义组件名称
render (createElement, context) {
const slots = []
this.$slots.default.map(item => {
if (item.tag) {
slots.push(item)
}
return false
})
if (slots.length <= 3) { // 小于等于三个直接渲染
return createElement(
'div',
{ style: 'display:flex; justify-content: space-evenly;' },
slots // 子节点数组
)
} else {
const firstEL = [slots[0], slots[1]]
const menuEL = []
for (let i = 2; i < slots.length; i++) {
menuEL.push(<a-menu-item>{slots[i]}</a-menu-item>)
}
return <div style="display:flex; justify-content: space-evenly;"> {firstEL}
<a-dropdown>
<a-button class="ant-dropdown-link" type="link" style="">更多<a-icon type="down" /></a-button>
<a-menu slot="overlay">
{menuEL}
</a-menu>
</a-dropdown>
</div>
}
}
}
</script>
<style lang="less" scoped>
//当前页面的按钮, 减少padding
button { padding: 8px !important;}
</style>
<template>
<div class="jee-text-up table-head-layout">
<a-input required="required" :value="msg" @input="$emit('input', $event.target.value)">
</a-input>
<label>{{ placeholder }}</label>
</div>
</template>
<script>
export default {
name: 'JeepayTextUp',
// props: ['msg', 'placeholder']
props: {
msg: { type: String, default: '' },
placeholder: { type: String, default: '' }
}
}
</script>
<style scoped lang="less">
// 文字上移 效果
.jee-text-up {
position: relative;
input {
outline: 0;
text-indent: 60px;
transition: all .3s ease-in-out;
}
input::-webkit-input-placeholder {
color: #BFBFBF;
text-indent: 0;
}
input + label {
pointer-events: none;
position: absolute;
left: 0;
bottom: 6px;
padding: 2px 11px;
color: #BFBFBF;
font-size: 13px;
text-transform: uppercase;
transition: all .3s ease-in-out;
border-radius: 3px;
background: rgba(122, 184, 147, 0);
height: 20px;
line-height: 20px;
display: flex;
justify-content: center;
align-items: center;
}
// 三角形
input + label:after {
position: absolute;
content: "";
width: 0;
height: 0;
top: 100%;
left: 50%;
margin-left: -3px;
border-left: 3px solid transparent;
border-right: 3px solid transparent;
transition: all .3s ease-in-out;
}
input:focus,
input:active,
input:valid + label {
text-indent: 0;
background: #fff;
}
input:focus + label,
input:active + label,
input:valid + label {
color: #fff;
background: @jee-theme;
transform: translateY(-33px);
}
input:focus + label:after,
input:active + label:after {
border-top: 4px solid @jee-theme;
}
input:valid {
text-indent: 0; //文字不下移
}
input:valid + label{
background: #dadada; // 更换背景色
}
input:valid + label:after{ // 更换背景色
border-top: 4px solid #dadada;
}
}
// 文字上移效果 初版
// .jee-text-up {
// position: relative;
// .jee-text-label {
// position: absolute;
// z-index: 1;
// left: 15px;
// top: 0px;
// transition: all .3s;
// color: #bfbfbf;
// pointer-events: none;
// height: 20px;
// line-height: 20px;
// }
// input:focus + .jee-text-label, input:valid + .jee-text-label {
// top: -35px;
// padding: 1px 10px;
// border-radius: 5px;
// background: @jee-theme;
// color: #fff;
// }
// }
</style>
<template>
<div>
<a-upload
name="file"
:action="action"
:headers="headers"
:accept="accept"
:showUploadList="false"
:multiple="true"
:before-upload="beforeUpload"
@change="handleChange"
>
<slot name="uploadSlot" :loading="loading"></slot>
<!-- <img v-if="fileUrl && type === 'image'" :src="fileUrl" />
<a-input v-else-if="fileUrl && type === 'file'" :value="fileUrl" />
<a-button style="marginLeft:5px;"> <a-icon :type="loading ? 'loading' : 'upload'" /> {{ loading ? '正在上传' : '点击上传' }} </a-button> -->
</a-upload>
</div>
</template>
<script>
import appConfig from '@/config/appConfig'
import storage from '@/utils/jeepayStorageWrapper'
function getHeaders () {
const headers = {}
headers[appConfig.ACCESS_TOKEN_NAME] = storage.getToken() // token
return headers
}
export default {
name: 'JeepayUpload',
props: {
action: { type: String, default: '' },
accept: { type: String, default: '' },
size: { type: Number, default: 10 }, // 文件大小限制
num: { type: Number, default: 1 } // 文件数量限制
},
data () {
return {
loading: false, // 上传状态
fileList: [],
headers: getHeaders() // 放入token
}
},
created () {
},
methods: {
// 上传回调
handleChange (info) {
// 限制文件数量
/* let fileList = [...info.fileList]
fileList = fileList.length > this.num ? fileList.splice(0 - this.num) : fileList // 取最新加入的元素
fileList = fileList.map(file => {
if (file.response) {
file.url = file.response.data
}
return file
}) */
const res = info.file.response
if (info.file.status === 'uploading') {
this.loading = true
}
if (info.file.status === 'done') {
if (res.code !== 0) {
this.$message.error(res.msg)
}
this.loading = false
this.$emit('uploadSuccess', res.data)
} else if (info.file.status === 'error') {
console.log(info)
this.$message.error(`上传失败`)
}
},
// 上传图片前的校验
beforeUpload (file) {
const validate = file.size / 1024 / 1024 < this.size
if (!validate) {
this.$message.error('文件应小于' + this.size + 'M!')
}
return validate
}
}
}
</script>
/* Make clicks pass-through */
#nprogress {
pointer-events: none;
}
#nprogress .bar {
background: @primary-color;
position: fixed;
z-index: 1031;
top: 0;
left: 0;
width: 100%;
height: 2px;
}
/* Fancy blur effect */
#nprogress .peg {
display: block;
position: absolute;
right: 0px;
width: 100px;
height: 100%;
box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color;
opacity: 1.0;
-webkit-transform: rotate(3deg) translate(0px, -4px);
-ms-transform: rotate(3deg) translate(0px, -4px);
transform: rotate(3deg) translate(0px, -4px);
}
/* Remove these to get rid of the spinner */
#nprogress .spinner {
display: block;
position: fixed;
z-index: 1031;
top: 15px;
right: 15px;
}
#nprogress .spinner-icon {
width: 18px;
height: 18px;
box-sizing: border-box;
border: solid 2px transparent;
border-top-color: @primary-color;
border-left-color: @primary-color;
border-radius: 50%;
-webkit-animation: nprogress-spinner 400ms linear infinite;
animation: nprogress-spinner 400ms linear infinite;
}
.nprogress-custom-parent {
overflow: hidden;
position: relative;
}
.nprogress-custom-parent #nprogress .spinner,
.nprogress-custom-parent #nprogress .bar {
position: absolute;
}
@-webkit-keyframes nprogress-spinner {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes nprogress-spinner {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/**
* 全局配置信息, 包含网站标题, 动态组件定义
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/8 07:18
*/
/** 应用配置项 **/
export default {
APP_TITLE: 'Jeepay运营平台', // 设置浏览器title
ACCESS_TOKEN_NAME: 'iToken' // 设置请求token的名字, 用于请求header 和 localstorage中存在名称
}
/**
* 与后端开发人员的路由名称及配置项
* 组件名称 :{ 默认跳转路径(如果后端配置则已动态配置为准), 组件渲染 }
* */
export const asyncRouteDefine = {
'CurrentUserInfo': { defaultPath: '/current/userinfo', component: () => import('@/views/current/UserinfoPage') }, // 用户设置
'MainPage': { defaultPath: '/main', component: () => import('@/views/dashboard/Analysis') },
'SysUserPage': { defaultPath: '/users', component: () => import('@/views/sysuser/SysUserPage') },
'RolePage': { defaultPath: '/roles', component: () => import('@/views/role/RolePage') },
'EntPage': { defaultPath: '/ents', component: () => import('@/views/ent/EntPage') },
'PayWayPage': { defaultPath: '/payways', component: () => import('@/views/payconfig/payWay/List') },
'IfDefinePage': { defaultPath: '/ifdefines', component: () => import('@/views/payconfig/payIfDefine/List') },
'IsvListPage': { defaultPath: '/isv', component: () => import('@/views/isv/IsvList') }, // 服务商列表
'MchListPage': { defaultPath: '/mch', component: () => import('@/views/mch/MchList') }, // 商户列表
'MchAppPage': { defaultPath: '/apps', component: () => import ('@/views/mchApp/List') }, // 商户应用列表
'PayOrderListPage': { defaultPath: '/payOrder', component: () => import('@/views/order/pay/PayOrderList') }, // 支付订单列表
'RefundOrderListPage': { defaultPath: '/refundOrder', component: () => import('@/views/order/refund/RefundOrderList') }, // 退款订单列表
'TransferOrderListPage': { defaultPath: '/transferOrder', component: () => import('@/views/order/transfer/TransferOrderList') }, // 转账订单
'MchNotifyListPage': { defaultPath: '/notify', component: () => import('@/views/order/notify/MchNotifyList') }, // 商户通知列表
'SysConfigPage': { defaultPath: '/config', component: () => import('@/views/sys/config/SysConfig') }, // 系统配置
'SysLogPage': { defaultPath: '/log', component: () => import('@/views/sys/log/SysLog') } // 系统日志
}
import { printANSI } from '@/utils/screenLog'
export default function Initializer () {
printANSI() // 请自行移除该行. please remove this line
}
import Vue from 'vue'
// base library
import {
ConfigProvider,
Layout,
Input,
InputNumber,
Button,
Switch,
Radio,
Checkbox,
Select,
Card,
Form,
FormModel,
Row,
Col,
Modal,
Table,
Tabs,
Icon,
Badge,
Popover,
Dropdown,
List,
Avatar,
Breadcrumb,
Steps,
Spin,
Menu,
Drawer,
Tooltip,
Alert,
Tag,
Divider,
DatePicker,
TimePicker,
Upload,
Progress,
Skeleton,
Popconfirm,
PageHeader,
Result,
Statistic,
Descriptions,
Space,
Pagination,
message,
notification,
Tree
} from 'ant-design-vue'
import Viser from 'viser-vue'
// ext library
import VueCropper from 'vue-cropper'
Vue.use(ConfigProvider)
Vue.use(Layout)
Vue.use(Input)
Vue.use(InputNumber)
Vue.use(Button)
Vue.use(Switch)
Vue.use(Radio)
Vue.use(Checkbox)
Vue.use(Select)
Vue.use(Card)
Vue.use(Form)
Vue.use(FormModel)
Vue.use(Row)
Vue.use(Col)
Vue.use(Modal)
Vue.use(Table)
Vue.use(Tabs)
Vue.use(Icon)
Vue.use(Badge)
Vue.use(Popover)
Vue.use(Dropdown)
Vue.use(List)
Vue.use(Avatar)
Vue.use(Breadcrumb)
Vue.use(Steps)
Vue.use(Spin)
Vue.use(Menu)
Vue.use(Drawer)
Vue.use(Tooltip)
Vue.use(Alert)
Vue.use(Tag)
Vue.use(Divider)
Vue.use(DatePicker)
Vue.use(TimePicker)
Vue.use(Upload)
Vue.use(Progress)
Vue.use(Skeleton)
Vue.use(Popconfirm)
Vue.use(PageHeader)
Vue.use(Result)
Vue.use(Statistic)
Vue.use(Descriptions)
Vue.use(Space)
Vue.use(Pagination)
Vue.use(Tree)
Vue.prototype.$confirm = Modal.confirm
Vue.prototype.$message = message
Vue.prototype.$notification = notification
Vue.prototype.$info = Modal.info
Vue.prototype.$success = Modal.success
Vue.prototype.$error = Modal.error
Vue.prototype.$warning = Modal.warning
Vue.use(Viser)
Vue.use(VueCropper)
process.env.NODE_ENV !== 'production' && console.warn('[antd-pro] NOTICE: Antd use lazy-load.')
import Vue from 'vue'
// base library
import Antd from 'ant-design-vue'
import Viser from 'viser-vue'
import VueCropper from 'vue-cropper'
import 'ant-design-vue/dist/antd.less'
// ext library
import VueClipboard from 'vue-clipboard2'
import './directives/action'
VueClipboard.config.autoSetContainer = true
Vue.use(Antd)
Vue.use(Viser)
Vue.use(VueClipboard)
Vue.use(VueCropper)
process.env.NODE_ENV !== 'production' && console.warn('[antd-pro] WARNING: Antd now use fulled imported.')
@import '../node_modules/ant-design-vue/es/style/themes/default.less';
// @import './default.less';
html,
body,
#app, #root {
height: 100%;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Microsoft YaHei,PingFang SC,Hiragino Sans GB,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
letter-spacing: 0.4px;
}
// jee主题颜色class列表, 用于文字颜色
.jee-theme {
color: @jee-theme; //主题色
}
.jee-back {
color: @jee-back; //主要背景色
}
.jee-card-back {
color: @jee-card-back; //卡片底色
}
.jee-theme-mask {
color: @jee-theme-mask; //主体遮罩色(10% 透明度)
}
.jee-strengthen {
color: @jee-strengthen;//强化色
}
.jee-theme-hover {
color: @jee-theme-hover;//主题Hover
}
.jee-warning {
color: @jee-warning; //危险,强化警告色
}
.jee-inside-link {
color: @jee-inside-link; //内部链接
}
.jee-external-link {
color: @jee-external-link; //外部链接
}
// jee主题颜色class列表, 用于文字颜色
.jee-theme {
color: @jee-theme; //主题色
}
.jee-back {
color: @jee-back; //主要背景色
}
.jee-card-back {
color: @jee-card-back; //卡片底色
}
.jee-theme-mask {
color: @jee-theme-mask; //主体遮罩色(10% 透明度)
}
.jee-strengthen {
color: @jee-strengthen;//强化色
}
.jee-theme-hover {
color: @jee-theme-hover;//主题Hover
}
.jee-warning {
color: @jee-warning; //危险,强化警告色
}
.jee-inside-link {
color: @jee-inside-link; //内部链接
}
.jee-external-link {
color: @jee-external-link; //外部链接
}
// jee主题颜色class列表, 用于背景颜色
.jee-theme-back-color {
background-color: @jee-theme; //主题色
}
.jee-back-color {
background-color: @jee-back; //主要背景色
}
.jee-card-back-color {
background-color: @jee-card-back; //卡片底色
}
.jee-theme-mask-back-color {
background-color: @jee-theme-mask; //主体遮罩色(10% 透明度)
}
.jee-strengthen-back-color {
background-color: @jee-strengthen;//强化色
}
.jee-theme-hover-back-color {
background-color: @jee-theme-hover;//主题Hover
}
.jee-warning-back-color {
background-color: @jee-warning; //危险,强化警告色
}
.jee-inside-link-back-color {
background-color: @jee-inside-link; //内部链接
}
.jee-external-link-back-color {
background-color: @jee-external-link; //外部链接
}
.colorWeak {
filter: invert(80%);
}
.ant-layout{
.layout-basic {
height: 100vh;
min-height: 100vh;
}
}
canvas {
display: block;
}
body {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: #f0f2f5;
}
ul, ol {
list-style: none;
}
// 滚动条高度 和宽度
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
// 滚动条颜色
::-webkit-scrollbar-thumb {
background: #B3B3B3;
}
// 滑块区域底色
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.03)
}
// 滚动条hover色
::-webkit-scrollbar-thumb:hover {
background: #A6A6A6;
}
// 滚动条选中色
::-webkit-scrollbar-thumb:active {
background: #8C8C8C;
}
// 结合 表格组件中的 :scroll ,让表格在收缩时,展示滚动条
.ant-table-body{
overflow-x: auto !important;
}
// /*显示滚动条上方以及下方的渐增按钮*/
// ::-webkit-scrollbar-button:start:decrement,
// ::-webkit-scrollbar-button:end:increment {
// display: block;
// }
// /* 定义垂直滚动条渐增按扭的样式 */
// ::-webkit-scrollbar-button:vertical:end:increment {
// background-image: url(~@/assets/svg/scroll_down.svg);
// background-size: cover;
// background-position: center;
// }
// /* 定义垂直滚动条渐减按扭的样式 */
// ::-webkit-scrollbar-button:vertical:start:decrement {
// background-image: url(~@/assets/svg/scroll_up.svg);
// background-size: cover;
// background-position: center;
// }
// /* 定义水平滚动条渐增按扭的样式 */
// ::-webkit-scrollbar-button:horizontal:end:increment {
// background-image: url(~@/assets/svg/scroll_right.svg);
// background-size: cover;
// background-position: center;
// }
// /* 定义水平滚动条渐减按扭的样式 */
// ::-webkit-scrollbar-button:horizontal:start:decrement {
// background-image: url(~@/assets/svg/scroll_left.svg);
// background-size: cover;
// background-position: center;
// }
// 隐藏面包屑底下的标题
.ant-page-header-heading {
display: none;
}
// 数据列表 样式
.table-alert {
margin-bottom: 16px;
}
// 数据列表 操作
.table-operator {
margin-bottom: 18px;
button {
margin-right: 8px;
}
}
// 数据列表 搜索条件
.table-page-search-wrapper {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
padding: 30px;
padding-bottom: 0;
border-bottom: 1px solid #e8e8e8;
background: #fafafa;
.ant-form-inline {
.ant-form-item {
display: flex;
// margin-bottom: 24px;
margin-right: 0;
.ant-form-item-control-wrapper {
flex: 1 1;
display: inline-block;
vertical-align: middle;
}
> .ant-form-item-label {
line-height: 32px;
padding-right: 8px;
width: auto;
}
.ant-form-item-control {
height: 32px;
line-height: 32px;
}
}
}
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
}
@media (max-width: @screen-xs) {
.ant-table {
width: 100%;
overflow-x: auto;
&-thead > tr,
&-tbody > tr {
> th,
> td {
white-space: pre;
> span {
display: block;
}
}
}
}
}
// 修改侧边栏宽度为230
.ant-pro-sider-menu-sider {
// min-width: 80px !important;
// max-width: 230px !important;
// 去掉侧边栏阴影
.light {
box-shadow: none;
}
}
// 删除表格的内边距
.ant-card-body {
padding: 0 !important;
}
// 增加内容区域的边框圆角
.ant-card {
border-radius: 10px;
overflow: hidden;
}
// 登录页输入框fcous hover事件,边框为jee主题蓝
.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
border-color: @jee-theme
}
.ant-input:focus {
border-color: @jee-theme
}
// 抽屉,按钮板块,居中
.drawer-btn-center {
position: absolute;
right: 0px;
bottom: 0px;
width: 100%;
border-top: 1px solid rgb(233, 233, 233);
padding: 10px 16px;
background: rgb(255, 255, 255);
text-align: center;
z-index: 2;
&:first-child {
margin-right: 80px;
}
button {
margin: 0;
padding: 3px 20px;
}
}
.els {
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap
}
// 内容区域去掉最外层的magin 24px ,改为 padding 15px
.ant-pro-basicLayout-content {
margin: 0 ;
padding: 15px;
}
// 表格页面的间距
.ant-table-pagination.ant-pagination {
margin: 20px;
}
// 去掉表格边框线
.ant-card-bordered {
border:none !important;
}
.ant-table-align-left {
padding-left: 38px;
}
// 向下的30外边距
.mg-b-30 {
margin-bottom: 30px
}
// 表格,搜索框板块布局
.table-head-ground {
display: flex;
justify-content: start;
flex-wrap: wrap;
.table-layer {
display: flex;
flex-wrap: wrap;
flex-grow: 1;
flex-shrink: 1;
}
}
.table-head-layout {
min-width: 220px;
max-width: 240px;
flex-grow: 1;
flex-shrink: 1;
margin-bottom:30px !important;
margin-right: 16px !important;
}
// 404 500 403
.result-err {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
overflow: auto;
div {
margin: 20px 0;
text-align:center;
font-size: 16px;
p.big-text {
font-size: 36px;
font-weight: 700;
}
}
}
\ No newline at end of file
/**
* Http请求包装对象
* 参考: iview https://githubtest.com/icarusion/iview-admin/blob/master/src/libs/axios.js
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/8 07:18
*/
import axios from 'axios'
import storage from '@/utils/jeepayStorageWrapper'
import appConfig from '@/config/appConfig'
import Vue from 'vue'
import store from '@/store/index'
class HttpRequest {
constructor (baseUrl = process.env.VUE_APP_API_BASE_URL) {
this.baseUrl = baseUrl
this.queue = {} // 发送队列, 格式为: {请求url: true}, 可以做一些验证之类
}
// 基础配置信息
baseConfig () {
const headers = {}
headers[appConfig.ACCESS_TOKEN_NAME] = storage.getToken()
return {
baseURL: this.baseUrl,
headers: headers
}
}
destroy (url, showLoading) {
delete this.queue[url]
}
interceptors (instance, url, showErrorMsg, showLoading) {
// 请求拦截
instance.interceptors.request.use(config => {
// 添加全局的loading...
if (!Object.keys(this.queue).length && showLoading) {
store.commit('showLoading') // 加载中显示loading组件
}
this.queue[url] = true
return config
}, error => {
store.commit('hideLoading') // 报错关闭loading组件
return Promise.reject(error)
})
// 响应拦截
instance.interceptors.response.use(res => {
this.destroy(url, showLoading)
if (showLoading) {
store.commit('hideLoading') // 报错关闭loading组件
}
const resData = res.data // 接口实际返回数据 格式为:{code: '', msg: '', data: ''}, res.data 是axios封装对象的返回数据;
if (resData.code !== 0) { // 相应结果不为0, 说明异常
if (showErrorMsg) {
Vue.prototype.$message.error(resData.msg) // 显示异常信息
}
return Promise.reject(resData)
} else {
return resData.data
}
}, error => {
this.destroy(url, showLoading)
if (showLoading) {
store.commit('hideLoading') // 报错关闭loading组件
}
let errorInfo = error.response && error.response.data && error.response.data.data
if (!errorInfo) {
errorInfo = error.response.data
}
if (error.response.status === 401) { // 无访问权限,会话超时, 提示用户信息 & 退出系统
const toLoginTimeout = setTimeout(function () {
store.dispatch('Logout').then(() => {
window.location.reload()
})
}, 3000)
Vue.prototype.$infoBox.confirmDanger(
'会话超时,请重新登录', '3s后将自动退出...',
() => {
store.dispatch('Logout').then(() => {
window.location.reload()
})
},
() => {
clearTimeout(toLoginTimeout)
},
{ okText: '重新登录', cancelText: '关闭对话' })
} else {
if (showErrorMsg) {
Vue.prototype.$message.error(JSON.stringify(errorInfo)) // 显示异常信息
}
}
return Promise.reject(errorInfo)
})
}
// interceptorsFlag: 是否进行自定义拦截器处理,默认为: true
// showErrorMsg 发送请求出现异常是否全局提示错误信息
// showLoading 发送请求前后显示全局loading
request (options, interceptorsFlag = true, showErrorMsg = true, showLoading = false) {
const instance = axios.create()
options = Object.assign(this.baseConfig(), options)
if (interceptorsFlag) { // 注入 req, respo 拦截器
this.interceptors(instance, options.url, showErrorMsg, showLoading)
}
return instance(options)
}
}
export default HttpRequest
import HttpRequest from '@/http/HttpRequest'
const request = new HttpRequest()
export default request
@import "~ant-design-vue/es/style/themes/default.less";
// 清除头部栏下方阴影
.ant-layout-header, .ant-pro-basicLayout .ant-layout-header:not(.ant-pro-top-menu) {
background: initial;
}
// 清除头部栏下方阴影 修改背景色
.ant-pro-global-header {
background: initial;
box-shadow: initial;
}
// 面包屑导航部分 修改背景色
.ant-pro-page-header-wrap-page-header-warp {
background: initial;
}
//左上角 logo 图标样式
.ant-pro-sider-menu-logo {
padding-left: 30px;
}
.ant-pro-sider-menu-logo svg {
height: 26px;
width: initial;
}
.ant-pro-global-header-index-right {
margin-right: 8px;
&.ant-pro-global-header-index-dark {
.ant-pro-global-header-index-action {
color: hsla(0, 0%, 100%, .85);
&:hover {
background: #1890ff;
}
}
}
.ant-pro-account-avatar {
.antd-pro-global-header-index-avatar {
margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0;
margin-right: 8px;
color: @primary-color;
vertical-align: top;
background: rgba(255, 255, 255, 0.85);
}
}
.menu {
.anticon {
margin-right: 8px;
}
.ant-dropdown-menu-item {
min-width: 100px;
}
}
}
<template>
<pro-layout
:menus="menus"
:collapsed="collapsed"
:mediaQuery="query"
:isMobile="isMobile"
:handleMediaQuery="handleMediaQuery"
:handleCollapse="handleCollapse"
:i18nRender="false"
v-bind="settings"
:breadcrumbRender="handleBreadcrumbRender"
:siderWidth="210"
>
<!-- 1.0.0+ 版本 pro-layout 提供 API,
我们推荐使用这种方式进行 LOGO 和 title 自定义
-->
<template v-slot:menuHeaderRender>
<div>
<!-- 当侧边栏卷起来的时候,切换仅有J字母的图标 -->
<img src="@/assets/logo-j.svg" alt="jeequan">
<!-- 在这里可以添加title,我们以图片的方式替代文字 -->
<img v-show="!collapsed" src="@/assets/svg/jeepay.svg" alt="jeepay" style="width:90px;margin: 5px 0 0 5px">
</div>
</template>
<!-- 1.0.0+ 版本 pro-layout 提供 API,
增加 Header 左侧内容区自定义
-->
<template v-slot:headerContentRender>
<div class="ant-pro-global-header-trigger" @click="routeReload()">
<a-tooltip title="刷新页面">
<a-icon type="reload" style="font-size: 18px;cursor: pointer;" />
</a-tooltip>
</div>
</template>
<template v-slot:rightContentRender>
<right-content :top-menu="settings.layout === 'topmenu'" :is-mobile="isMobile" :theme="settings.theme" />
</template>
<!-- custom footer / 自定义Footer -->
<template v-slot:footerRender>
<global-footer />
</template>
<router-view v-if="isRouterAlive"/>
</pro-layout>
</template>
<script>
// import { SettingDrawer, updateTheme } from '@ant-design-vue/pro-layout'
import { mapState } from 'vuex'
import RightContent from '@/components/GlobalHeader/RightContent'
import GlobalFooter from '@/components/GlobalFooter'
import appConfig from '@/config/appConfig'
export default {
name: 'BasicLayout',
components: {
// SettingDrawer,
RightContent,
GlobalFooter
},
data () {
return {
isRouterAlive: true,
// preview.pro.antdv.com only use.
isProPreviewSite: process.env.VUE_APP_PREVIEW === 'true' && process.env.NODE_ENV !== 'development',
// end
// base
menus: [],
// 侧栏收起状态
collapsed: false,
title: appConfig.APP_TITLE,
settings: {
// 布局类型
layout: 'sidemenu', // 'sidemenu', 'topmenu'
contentWidth: 'Fluid', // Fixed , Fluid 内容区布局: 固定 | 流式
theme: 'light', // 主题 'dark' | 'light'
// 主色调
primaryColor: '#1a53ff', // 默认主题色, 如果修改颜色不生效,请清理 localStorage
fixedHeader: false, // 固定 Header
fixSiderbar: true, // 固定左侧菜单栏
colorWeak: false, // 色盲模式将
hideHintAlert: false,
hideCopyButton: false
},
// 媒体查询
query: {},
// 是否手机模式
isMobile: false
}
},
computed: {
...mapState({
// 动态主路由
mainMenu: state => state.asyncRouter.addRouters
})
},
created () {
const routes = this.mainMenu.find(item => item.path === '/')
this.menus = (routes && routes.children) || []
// 处理侧栏收起状态
// this.$watch('collapsed', () => {
// this.$store.commit(SIDEBAR_TYPE, this.collapsed)
// })
// this.$watch('isMobile', () => {
// this.$store.commit(TOGGLE_MOBILE_TYPE, this.isMobile)
// })
},
mounted () {
const userAgent = navigator.userAgent
if (userAgent.indexOf('Edge') > -1) {
this.$nextTick(() => {
this.collapsed = !this.collapsed
setTimeout(() => {
this.collapsed = !this.collapsed
}, 16)
})
}
// first update color
// TIPS: THEME COLOR HANDLER!! PLEASE CHECK THAT!!
// if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') {
// updateTheme(this.settings.primaryColor)
// }
},
methods: {
handleMediaQuery (val) {
this.query = val
if (this.isMobile && !val['screen-xs']) {
this.isMobile = false
return
}
if (!this.isMobile && val['screen-xs']) {
this.isMobile = true
this.collapsed = false
}
},
handleCollapse (val) {
this.collapsed = val
},
handleBreadcrumbRender (rrr) {
if (rrr.route.path.startsWith('/ENT')) {
return <span>{rrr.route.breadcrumbName}</span>
}
return <router-link to={rrr.route.path || '/'}><span>{rrr.route.breadcrumbName}</span></router-link>
},
routeReload () { // 刷新页面函数
this.isRouterAlive = false
this.$nextTick(() => { this.isRouterAlive = true })
}
}
}
</script>
<style lang="less">
@import "./BasicLayout.less";
</style>
<template>
<div>
<router-view />
</div>
</template>
<script>
export default {
name: 'BlankLayout'
}
</script>
<style scoped>
</style>
<template>
<page-header-wrapper>
<router-view />
</page-header-wrapper>
</template>
<script>
export default {
name: 'PageView'
}
</script>
<script>
export default {
name: 'RouteView',
props: {
keepAlive: {
type: Boolean,
default: true
}
},
data () {
return {}
},
render () {
const { $route: { meta } } = this
const inKeep = (
<keep-alive>
<router-view />
</keep-alive>
)
const notKeep = (
<router-view />
)
// 这里增加了 multiTab 的判断,当开启了 multiTab 时
// 应当全部组件皆缓存,否则会导致切换页面后页面还原成原始状态
// 若确实不需要,可改为 return meta.keepAlive ? inKeep : notKeep
if (!meta.keepAlive) {
return notKeep
}
return this.keepAlive || meta.keepAlive ? inKeep : notKeep
}
}
</script>
<template>
<div id="userLayout" :class="['user-layout-wrapper']">
<div class="container">
<div class="user-layout-lang">
</div>
<div class="user-layout-content">
<div class="top">
<div class="header">
<a href="/">
<img src="~@/assets/logo.svg" class="logo" alt="logo">
</a>
</div>
<div class="desc">
<img src="~@/assets/svg/operate.svg" class="logo" alt="logo">
<span>运营平台</span>
</div>
</div>
<router-view />
<div class="footer">
<!-- <div class="links">-->
<!-- <a href="_self">帮助</a>-->
<!-- <a href="_self">隐私</a>-->
<!-- <a href="_self">条款</a>-->
<!-- </div>-->
<!-- <div class="copyright">
Copyright &copy; 2021 juhezhifu.com
</div> -->
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'UserLayout',
components: {
},
mounted () {
document.body.classList.add('userLayout')
},
beforeDestroy () {
document.body.classList.remove('userLayout')
}
}
</script>
<style lang="less" scoped>
#userLayout.user-layout-wrapper {
height: 100%;
&.mobile {
.container {
.main {
max-width: 368px;
width: 98%;
}
}
}
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
min-height: 100%;
background: #f0f2f5 url(~@/assets/svg/background.svg) no-repeat 50%;
background-size: cover;
//padding: 50px 0 84px;
position: relative;
.user-layout-lang {
width: 100%;
// height: 40px;
// line-height: 44px;
height: 0;
text-align: right;
}
.user-layout-content {
.top {
text-align: center;
.header {
height: 44px;
line-height: 44px;
margin-bottom:80px;
.badge {
position: absolute;
display: inline-block;
line-height: 1;
vertical-align: middle;
margin-left: -12px;
margin-top: -10px;
opacity: 0.8;
}
.logo {
height: 44px;
vertical-align: top;
border-style: none;
}
.title {
font-size: 33px;
color: rgba(0, 0, 0, .85);
font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-weight: 600;
position: relative;
top: 2px;
}
}
.desc {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
margin-bottom: 40px;
font-size: 20px;
font-family: PingFang SC, PingFang SC-Medium;
font-weight: 500;
color: #252626;
letter-spacing: 1px;
display: flex;
justify-content: center;
align-items: center;
height: 28px;
line-height: 28px;
span {
margin-left: 10px;
}
}
}
.main {
min-width: 260px;
width: 368px;
margin: 0 auto;
}
.footer {
// position: absolute;
width: 100%;
bottom: 0;
padding: 0 16px;
margin: 48px 0 24px;
text-align: center;
.links {
margin-bottom: 8px;
font-size: 14px;
a {
color: rgba(0, 0, 0, 0.45);
transition: all 0.3s;
&:not(:last-child) {
margin-right: 40px;
}
}
}
.copyright {
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
}
}
}
a {
text-decoration: none;
}
}
}
</style>
import UserLayout from './UserLayout'
import BlankLayout from './BlankLayout'
import BasicLayout from './BasicLayout'
import RouteView from './RouteView'
import PageView from './PageView'
export { UserLayout, BasicLayout, BlankLayout, RouteView, PageView }
// with polyfills
import 'core-js/stable'
import 'regenerator-runtime/runtime'
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/'
import ProLayout, { PageHeaderWrapper } from '@ant-design-vue/pro-layout'
import bootstrap from './core/bootstrap'
import './core/lazy_use' // use lazy load components
import './permission' // permission control 路由守卫
import './utils/filter' // global filter
import './global.less' // global style
import 'ant-design-vue/dist/antd.less'
import infoBox from '@/utils/infoBox'
import VueClipboard from 'vue-clipboard2' // 复制插件
Vue.config.productionTip = false
// mount axios to `Vue.$http` and `this.$http`
// use pro-layout components
Vue.component('pro-layout', ProLayout)
Vue.component('page-container', PageHeaderWrapper)
Vue.component('page-header-wrapper', PageHeaderWrapper)
Vue.use(VueClipboard) // 复制插件
/**
* @description 全局注册权限验证
*/
Vue.prototype.$access = (entId) => {
// eslint-disable-next-line eqeqeq
return store.state.user.accessList.some(item => item == entId)
}
Vue.prototype.$infoBox = infoBox
new Vue({
router,
store,
// init localstorage, vuex
created: bootstrap,
render: h => h(App)
}).$mount('#app')
import router from './router'
import store from './store'
import storage from '@/utils/jeepayStorageWrapper'
import NProgress from 'nprogress' // progress bar
import '@/components/NProgress/nprogress.less' // progress bar custom style
import { setDocumentTitle } from '@/utils/domUtil'
import { getInfo } from '@/api/login'
import appConfig from '@/config/appConfig'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const allowList = ['login', 'register', 'registerResult'] // no redirect allowList
const loginRoutePath = '/user/login'
// 路由守卫
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${appConfig.APP_TITLE}`)) // 设置浏览器标题
// 如果在免登录页面则直接放行
if (allowList.includes(to.name)) {
// 在免登录名单,直接进入
next()
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
return false
}
// 不包含Token 则直接跳转到登录页面
if (!storage.getToken()) {
next({ path: loginRoutePath, query: { redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
return false
}
// 以下为包含Token的情况
// 如果用户信息不存在, 则重新获取 [用户登录成功 & 强制刷新浏览器时 会执行该函数]
if (!store.state.user.userId) {
// request login userInfo
getInfo().then(bizData => {
store.commit('SET_USER_INFO', bizData) // 调用vuex设置用户基本信息
// 动态添加路由
store.dispatch('GenerateRoutes', {}).then(() => {
router.addRoutes(store.state.asyncRouter.addRouters)
})
next()
}).catch(() => {
// 失败时,获取用户信息失败时,调用登出,来清空历史保留信息
store.dispatch('Logout').then(() => {
next({ path: loginRoutePath, query: { redirect: to.fullPath } })
})
})
} else {
next()
}
})
router.afterEach(() => {
NProgress.done() // finish progress bar
})
import { BasicLayout, BlankLayout, PageView, RouteView } from '@/layouts'
import store from '@/store'
import { asyncRouteDefine } from '@/config/appConfig'
// 前端路由表 = 基础定义 + 动态组件
const constantRouterComponents = Object.assign({
// 基础页面 layout 必须引入
BasicLayout: { component: BasicLayout },
BlankLayout: { component: BlankLayout },
RouteView: { component: RouteView },
PageView: { component: PageView },
'403': () => import('@/views/exception/403'),
'404': () => import('@/views/exception/404'),
'500': () => import('@/views/exception/500')
}, asyncRouteDefine)
// 前端未找到页面路由
const notFoundRouter = {
path: '*', component: () => import('@/views/exception/404')
}
// 根级菜单
const rootRouter = {
name: 'index',
path: '/',
component: BasicLayout,
redirect: redirectFunc, // 根页面【/】默认跳转 地址
children: [],
meta: { title: '主页' }
}
// 动态跳转路径 func
function redirectFunc () {
let mainPageUri = ''
store.state.user.allMenuRouteTree.forEach(item => {
if (item.entId === 'ENT_C_MAIN') { // 当前用户是否拥有主页权限, 如果有直接跳转到该路径
mainPageUri = item.menuUri
return false
}
})
if (mainPageUri) {
return mainPageUri
}
return getOneUri(store.state.user.allMenuRouteTree)
}
// 获取到第一个uri (递归查找)
function getOneUri (item) {
let result = ''
for (let i = 0; i < item.length; i++) {
if (item[i].menuUri && item[i].entType === 'ML') {
return item[i].menuUri
}
if (item[i].children) {
result = getOneUri(item[i].children)
if (result) {
return result
}
}
}
return result
}
/**
* 动态生成菜单
* @param token
* @returns {Promise<Router>}
*/
export const generatorDynamicRouter = () => {
return new Promise((resolve, reject) => {
// 根据树状结构生成路由格式
rootRouter.children = generator(store.state.user.allMenuRouteTree)
// 构建完整路由
resolve([rootRouter, notFoundRouter])
})
}
/**
* 格式化树形结构数据 生成 vue-router 层级路由表
*
* @param routerMap
* @returns {*}
*/
export const generator = (allMenuRouteTreeArray) => {
const menuResult = []
// 遍历map
allMenuRouteTreeArray.map(item => {
const defComponent = constantRouterComponents[item.componentName || item.entId]
// 找不到组件 || 其他菜单
if (!defComponent) {
return
}
// 跳转uri
let path = item.menuUri || defComponent.defaultPath
// 没有配置path, 如果为目录则允许为空, 否则不在加载此配置
if (!path) {
if (item.children && item.children.length > 0) {
path = `/${item.entId}`
} else {
return // 不再加载此配置项
}
}
const currentRouter = {
// 如果路由设置了 path,则作为默认 path,否则 路由地址 为默认配置
path: path,
// 路由名称,建议唯一
name: item.entId,
// 该路由对应页面的 组件 :方案2 (动态加载)
component: ((defComponent && defComponent.component) || (() => import(`@/views/${item.componentName}`))),
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
meta: {
title: item.entName,
icon: item.menuIcon,
keepAlive: false
},
hidden: item.entType === 'MO' // 当其他菜单时需要隐藏显示
}
// 是否有子菜单,并递归处理
if (item.children && item.children.length > 0) {
// Recursion
currentRouter.children = generator(item.children)
}
menuResult.push(currentRouter)
})
return menuResult
}
import Vue from 'vue'
import Router from 'vue-router'
import { UserLayout } from '@/layouts'
// hack router push callback
// [解决 vue-router跳转相同路径报错 ]
const originalPush = Router.prototype.push
Router.prototype.push = function push (location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
Vue.use(Router)
// 纯静态路由配置项
const constantRouterMap = [
{
path: '/user',
component: UserLayout,
children: [
{ path: 'login', name: 'login', component: () => import('@/views/user/Login') }
]
}
]
export default new Router({
mode: 'history',
routes: constantRouterMap
})
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
// default router permission control
import asyncRouter from './modules/async-router'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
user, // 用户相关状态机
asyncRouter // 动态菜单
},
state: {
// 定义全局loading 为false
globalLoading: false
},
mutations: {
// 显示与关闭 全局 loading
showLoading (state) {
state.globalLoading = true
},
hideLoading (state) {
state.globalLoading = false
}
},
actions: {
}
})
/**
* 向后端请求用户的菜单,动态生成路由
*/
import { generatorDynamicRouter } from '@/router/generator-routers'
const asyncRouter = {
state: {
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
}
},
actions: {
GenerateRoutes ({ commit }, data) {
return new Promise(resolve => {
generatorDynamicRouter().then(routers => {
commit('SET_ROUTERS', routers)
resolve()
})
})
}
}
}
export default asyncRouter
import storage from '@/utils/jeepayStorageWrapper'
import { login, logout } from '@/api/login'
import appConfig from '@/config/appConfig'
const user = {
state: {
token: '',
userName: '', // 真实姓名
userId: '', // 用户ID
avatarImgPath: '', // 头像
allMenuRouteTree: [], // 全部动态 router
accessList: [], // 用户权限集合
isAdmin: '', // 是否是超级管理员
loginUsername: '', // 登录用户名
state: '', // 用户状态
sysType: '', // 所属系统
telphone: '', // 手机号
sex: '' // 性别
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
// 设置头像
SET_AVATAR (state, avatarPath) {
state.avatarImgPath = avatarPath
},
// 设置用户信息
SET_USER_INFO: (state, userInfo) => {
state.userId = userInfo.sysUserId // 用户ID
state.userName = userInfo.realname // 真实姓名
state.avatarImgPath = userInfo.avatarUrl // 头像
state.accessList = userInfo.entIdList // 权限集合
state.allMenuRouteTree = userInfo.allMenuRouteTree // 全部路由集合
state.isAdmin = userInfo.isAdmin // 是否是超级管理员
state.loginUsername = userInfo.loginUsername // 登录用户名
state.state = userInfo.state // 用户状态
state.sysType = userInfo.sysType // 所属系统
state.telphone = userInfo.telphone // 手机号
state.sex = userInfo.sex // 性别
}
},
actions: {
// 登录
Login ({ commit }, { loginParams, isSaveStorage }) {
return new Promise((resolve, reject) => {
login(loginParams).then(bizData => {
storage.setToken(bizData[appConfig.ACCESS_TOKEN_NAME], isSaveStorage)
commit('SET_TOKEN', bizData[appConfig.ACCESS_TOKEN_NAME])
resolve()
}).catch(error => {
reject(error)
})
})
},
// 登出
Logout ({ commit, state }) {
return new Promise((resolve) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
storage.cleanToken()
location.reload() // 退出时 重置缓存
resolve()
}).catch(() => {
resolve()
}).finally(() => {
})
})
}
}
}
export default user
export const setDocumentTitle = function (title) {
document.title = title
const ua = navigator.userAgent
// eslint-disable-next-line
const regex = /\bMicroMessenger\/([\d\.]+)/
if (regex.test(ua) && /ip(hone|od|ad)/i.test(ua)) {
const i = document.createElement('iframe')
i.src = '/favicon.ico'
i.style.display = 'none'
i.onload = function () {
setTimeout(function () {
i.remove()
}, 9)
}
document.body.appendChild(i)
}
}
import Vue from 'vue'
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
Vue.filter('NumberFormat', function (value) {
if (!value) {
return '0'
}
const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') // 将整数部分逢三一断
return intPartFormat
})
Vue.filter('dayjs', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
return moment(dataStr).format(pattern)
})
Vue.filter('moment', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
return moment(dataStr).format(pattern)
})
/**
* 通用信息弹层
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/8 07:18
*/
import { Modal } from 'ant-design-vue'
// 确认提示: 标题, 内容, 点击确定回调函数, 取消回调, 扩展参数
export const confirmResult = {
confirm: function (title, content, okFunc, cancelFunc = (() => {}), extConfig = {}) {
return Modal.confirm(
Object.assign({
okText: '确定',
cancelText: '取消',
title: title || '提示',
content: content,
onOk: okFunc,
onCancel: cancelFunc,
confirmLoading: true
}, extConfig))
},
confirmPrimary: function (title, content, okFunc, cancelFunc = (() => {}), extConfig = {}) {
return this.confirm(title, content, okFunc, cancelFunc, Object.assign({ okType: 'primary' }, extConfig))
},
confirmDanger: function (title, content, okFunc, cancelFunc = (() => {}), extConfig = {}) {
return this.confirm(title, content, okFunc, cancelFunc, Object.assign({ okType: 'danger' }, extConfig))
},
modalError: function (title, content, okFunc = (() => {})) {
return Modal.error({ title: title, content: content, onOk: okFunc })
},
modalSuccess: function (title, content, okFunc = (() => {})) {
return Modal.success({ title: title, content: content, onOk: okFunc })
},
modalWarning: function (title, content, okFunc = (() => {})) {
return Modal.warning({ title: title, content: content, onOk: okFunc })
}
}
export default confirmResult
/**
* storage 存储包装类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/8 07:18
*/
import storage from 'store'
import appConfig from '@/config/appConfig'
var SESSION_TOKEN = ''
const wrapper = {
/* 获取当前Token **/
getToken: () => {
return SESSION_TOKEN || storage.get(appConfig.ACCESS_TOKEN_NAME)
},
/* 清空Token **/
cleanToken: () => {
SESSION_TOKEN = ''
storage.remove(appConfig.ACCESS_TOKEN_NAME)
},
/* 设置token信息 **/
setToken (tokenVal, isSaveStorage) {
SESSION_TOKEN = tokenVal
if (isSaveStorage) {
storage.set(appConfig.ACCESS_TOKEN_NAME, tokenVal, 7 * 24 * 60 * 60 * 1000)
}
}
}
export default wrapper
/* eslint-disable */
export const printANSI = () => {
let text = ``
console.log(`%c${text}`, 'color: #fc4d50')
console.log('%c', 'color: #fff; font-size: 14px; font-weight: 300; text-shadow:#000 1px 0 0,#000 0 1px 0,#000 -1px 0 0,#000 0 -1px 0;')
}
export function timeFix () {
const time = new Date()
const hour = time.getHours()
return hour < 9 ? '早上好' : hour <= 11 ? '上午好' : hour <= 13 ? '中午好' : hour < 20 ? '下午好' : '晚上好'
}
export function isIE () {
const bw = window.navigator.userAgent
const compare = (s) => bw.indexOf(s) >= 0
const ie11 = (() => 'ActiveXObject' in window)()
return compare('MSIE') || ie11
}
.textOverflow() {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
word-break: break-all;
}
.textOverflowMulti(@line: 3, @bg: #fff) {
position: relative;
max-height: @line * 1.5em;
margin-right: -1em;
padding-right: 1em;
overflow: hidden;
line-height: 1.5em;
text-align: justify;
&::before {
position: absolute;
right: 14px;
bottom: 0;
padding: 0 1px;
background: @bg;
content: '...';
}
&::after {
position: absolute;
right: 14px;
width: 1em;
height: 1em;
margin-top: 0.2em;
background: white;
content: '';
}
}
// mixins for clearfix
// ------------------------
.clearfix() {
zoom: 1;
&::before,
&::after {
display: table;
content: ' ';
}
&::after {
clear: both;
height: 0;
font-size: 0;
visibility: hidden;
}
}
\ No newline at end of file
<template>
<a-modal
title="修改头像"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
:width="800"
:footer="null"
@cancel="cancelHandel">
<a-row>
<a-col :xs="24" :md="12" :style="{height: '350px'}">
<vue-cropper
ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
@realTime="realTime"
>
</vue-cropper>
</a-col>
<a-col :xs="24" :md="12" :style="{height: '350px'}">
<div class="avatar-upload-preview">
<img :src="previews.url" :style="previews.img"/>
</div>
</a-col>
</a-row>
<br>
<a-row>
<a-col :lg="2" :md="2">
<a-upload name="file" :beforeUpload="beforeUpload" :showUploadList="false">
<a-button icon="upload">选择图片</a-button>
</a-upload>
</a-col>
<a-col :lg="{span: 1, offset: 2}" :md="2">
<a-button icon="plus" @click="changeScale(1)"/>
</a-col>
<a-col :lg="{span: 1, offset: 1}" :md="2">
<a-button icon="minus" @click="changeScale(-1)"/>
</a-col>
<a-col :lg="{span: 1, offset: 1}" :md="2">
<a-button icon="undo" @click="rotateLeft"/>
</a-col>
<a-col :lg="{span: 1, offset: 1}" :md="2">
<a-button icon="redo" @click="rotateRight"/>
</a-col>
<a-col :lg="{span: 2, offset: 6}" :md="2">
<a-button type="primary" @click="finish('blob')">保存</a-button>
</a-col>
</a-row>
</a-modal>
</template>
<script>
import { upload, updateUserInfo } from '@/api/manage'
import store from '@/store'
export default {
data () {
return {
recordId: store.state.user.userId, // 拿到ID
userLoad: upload.icon, // 图片上传地址
visible: false,
id: null,
confirmLoading: false,
fileList: [],
uploading: false,
options: {
// img: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
img: '',
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true
},
previews: {}
}
},
methods: {
edit (id) {
this.visible = true
this.id = id
/* 获取原始头像 */
},
close () {
this.id = null
this.visible = false
},
cancelHandel () {
this.close()
},
changeScale (num) {
num = num || 1
this.$refs.cropper.changeScale(num)
},
rotateLeft () {
this.$refs.cropper.rotateLeft()
},
rotateRight () {
this.$refs.cropper.rotateRight()
},
beforeUpload (file) {
const reader = new FileReader()
// 把Array Buffer转化为blob 如果是base64不需要
// 转化为base64
reader.readAsDataURL(file)
reader.onload = () => {
this.options.img = reader.result
}
// 转化为blob
// reader.readAsArrayBuffer(file)
return false
},
// 上传图片(点击上传按钮)
finish (type) {
console.log('finish')
const _this = this
// 通过FormData构造函数创建一个空对象
const formData = new FormData()
// 输出
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
// 通过该方法可以获取当前文件的一个内存URL
const img = window.URL.createObjectURL(data)
this.model = true
this.modelSrc = img
formData.append('avatarUrl', img)
// this.$http.post('https://www.mocky.io/v2/5cc8019d300000980a055e76', formData, { contentType: false, processData: false, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
updateUserInfo(formData)
// .then(res => {
// console.log(res)
// }).catch(err => {
// console.log(err)
// })
.then((response) => {
console.log('upload response:', response)
// var res = response.data
// if (response.status === 'done') {
// _this.imgFile = ''
// _this.headImg = res.realPathList[0] // 完整路径
// _this.uploadImgRelaPath = res.relaPathList[0] // 非完整路径
// _this.$message.success('上传成功')
// this.visible = false
// }
_this.$message.success('上传成功')
_this.$emit('ok', response.url)
_this.visible = false
}).catch(err => {
console.log(err)
})
console.log(_this.userLoad, _this.recordId, this.modelSrc)
})
} else {
this.$refs.cropper.getCropData((data) => {
this.model = true
this.modelSrc = data
})
}
},
okHandel () {
const vm = this
vm.confirmLoading = true
setTimeout(() => {
vm.confirmLoading = false
vm.close()
vm.$message.success('上传头像成功')
}, 2000)
},
realTime (data) {
this.previews = data
}
}
}
</script>
<style lang="less" scoped>
.avatar-upload-preview {
position: absolute;
top: 50%;
transform: translate(50%, -50%);
width: 180px;
height: 180px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
</style>
<template>
<div style="background: #fff;border-radius:10px">
<a-tabs @change="selectTabs">
<a-tab-pane key="1" tab="基本信息">
<div class="account-settings-info-view">
<a-row :gutter="16">
<a-col :md="16" :lg="16">
<a-form-model ref="infoFormModel" :model="saveObject" :label-col="{span: 9}" :wrapper-col="{span: 10}" :rules="rules">
<a-form-model-item label="用户登录名:">
<a-input v-model="saveObject.loginUsername" disabled/>
</a-form-model-item>
<a-form-model-item label="用户姓名:" prop="realname">
<a-input v-model="saveObject.realname" />
</a-form-model-item>
<a-form-model-item label="手机号:" prop="telphone">
<a-input v-model="saveObject.telphone" disabled/>
</a-form-model-item>
<a-form-model-item label="请选择性别:">
<a-radio-group v-model="saveObject.sex">
<a-radio :value="1"></a-radio>
<a-radio :value="2"></a-radio>
</a-radio-group>
</a-form-model-item>
</a-form-model>
<a-form-item style="display:flex;justify-content:center">
<a-button type="primary" @click="changeInfo" icon="check-circle" :loading="btnLoading">更新基本信息</a-button>
</a-form-item>
</a-col>
<a-col :md="8" :lg="8" :style="{ minHeight: '180px',margin:'0 auto' }">
<!-- 原始的头像上传,带有图片裁剪功能 -->
<!-- <div class="ant-upload-preview" @click="$refs.modal.edit(1)" > -->
<div class="ant-upload-preview" >
<!-- <a-icon type="cloud-upload-o" class="upload-icon"/> -->
<!-- <div class="mask">
<a-icon type="plus" />
</div> -->
<img
:src="saveObject.avatarUrl"
style="border: 1px solid rgba(0,0,0,0.08)"/>
<JeepayUpload
style="
margin-top:10px"
:action="action"
accept=".jpg, .jpeg, .png"
@uploadSuccess="uploadSuccess($event, '')"
>
<template slot="uploadSlot" slot-scope="{loading}">
<a-button style="marginLeft:5px;"> <a-icon :type="loading ? 'loading' : 'upload'" /> {{ loading ? '正在上传' : '更换头像' }} </a-button>
</template>
</JeepayUpload>
</div>
</a-col>
</a-row>
<!-- 图片裁剪组件 <avatar-modal ref="modal" @ok="setavatar"/> -->
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="安全信息">
<div class="account-settings-info-view">
<a-row :gutter="16">
<a-col :md="16" :lg="16">
<a-form-model ref="pwdFormModel" :model="updateObject" :label-col="{span: 9}" :wrapper-col="{span: 10}" :rules="rulesPass">
<a-form-model-item label="原密码:" prop="originalPwd">
<a-input-password autocomplete="new-password" v-model="updateObject.originalPwd" placeholder="请输入原密码" />
</a-form-model-item>
<a-form-model-item label="新密码:" prop="newPwd">
<a-input-password autocomplete="new-password" v-model="updateObject.newPwd" placeholder="请输入新密码" />
</a-form-model-item>
<a-form-model-item label="确认新密码:" prop="confirmPwd">
<a-input-password autocomplete="new-password" v-model="updateObject.confirmPwd" placeholder="确认新密码" />
</a-form-model-item>
</a-form-model>
<a-form-item style="display:flex;justify-content:center">
<a-button type="primary" icon="safety-certificate" @click="confirm" :loading="btnLoading">更新密码</a-button>
</a-form-item>
</a-col>
</a-row>
</div>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script>
import JeepayUpload from '@/components/JeepayUpload/JeepayUpload'
import { getUserInfo, updateUserInfo, updateUserPass, upload } from '@/api/manage'
import AvatarModal from './AvatarModal'
import store from '@/store'
import { getInfo } from '@/api/login'
import { Base64 } from 'js-base64'
export default {
components: {
AvatarModal,
JeepayUpload
},
data () {
return {
action: upload.avatar, // 上传图标地址
btnLoading: false,
saveObject: {
loginUsername: '', // 登录名
realname: '', // 真实姓名
telphone: '',
sex: '',
avatarUrl: '' // 用户头像
},
// avatarUrl: store.state.user.avatarImgPath,
updateObject: {
originalPwd: '', // 原密码
newPwd: '', // 新密码
confirmPwd: '' // 确认密码
},
recordId: store.state.user.userId, // 拿到ID
rules: {
realname: [{ required: true, message: '请输入真实姓名', trigger: 'blur' }]
},
rulesPass: {
originalPwd: [{ required: true, message: '请输入原密码', trigger: 'blur' }],
newPwd: [{ min: 6, max: 12, required: true, message: '请输入6-12位新密码', trigger: 'blur' }],
confirmPwd: [{ required: true, message: '请确认输入新密码', trigger: 'blur' }, {
validator: (rule, value, callBack) => {
this.updateObject.newPwd === value ? callBack() : callBack('新密码与确认密码不一致')
}
}]
}
}
},
computed: {
},
created () {
this.detail()
},
methods: {
setavatar (url) {
this.option.img = url
},
detail () { // 获取基本信息
const that = this
getUserInfo().then(res => {
that.saveObject = res
console.log(res)
})
},
changeInfo () { // 更新基本信息事件
const that = this
this.$refs.infoFormModel.validate(valid => {
if (valid) { // 验证通过
this.$infoBox.confirmPrimary('确认更新信息吗?', '', () => {
that.btnLoading = true // 打开按钮上的 loading
that.$store.commit('showLoading') // 关闭全局刷新
// 请求接口
updateUserInfo(that.saveObject).then(res => {
that.btnLoading = false // 关闭按钮刷新
that.$store.commit('hideLoading') // 关闭全局刷新
return getInfo()
}).then(bizData => {
bizData.avatarUrl = that.saveObject.avatarUrl
bizData.realname = that.saveObject.realname
store.commit('SET_USER_INFO', bizData) // 调用vuex设置用户基本信息
that.$message.success('修改成功')
}).catch(err => {
that.$store.commit('hideLoading') // 关闭全局刷新
that.btnLoading = false
console.log(err)
that.$message.error('修改失败')
})
})
}
})
},
confirm (e) { // 确认更新密码
const that = this
this.$refs.pwdFormModel.validate(valid => {
if (valid) { // 验证通过
this.$infoBox.confirmPrimary('确认更新密码吗?', '', () => {
// 请求接口
that.btnLoading = true // 打开按钮上的 loading
that.confirmLoading = true // 显示loading
that.updateObject.recordId = that.recordId // 用户ID
that.updateObject.originalPwd = Base64.encode(that.updateObject.originalPwd)
that.updateObject.confirmPwd = Base64.encode(that.updateObject.confirmPwd)
this.$delete(this.updateObject, 'newPwd')
updateUserPass(that.updateObject).then(res => {
that.$message.success('修改成功')
// 退出登录
this.$store.dispatch('Logout').then(() => {
this.$router.push({ name: 'login' })
})
}).catch(res => {
that.confirmLoading = false
that.btnLoading = false
})
})
}
})
},
selectTabs () { // 清空必填提示
this.updateObject.originalPwd = ''
this.updateObject.newPwd = ''
this.updateObject.confirmPwd = ''
console.log(this.updateObject)
},
// 上传文件成功回调方法,参数value为文件地址,name是自定义参数
uploadSuccess (value, name) {
this.saveObject.avatarUrl = value
this.$forceUpdate()
}
}
}
</script>
<style lang="less" scoped>
.avatar-upload-wrapper {
height: 200px;
width: 100%;
}
.ant-upload-preview {
text-align:center ;
position: relative;
margin: 0 auto;
width: 100%;
// max-width: 180px;
border-radius: 50%;
// box-shadow: 0 0 4px #ccc;
.upload-icon {
position: absolute;
top: 0;
right: 10px;
font-size: 1.4rem;
padding: 0.5rem;
background: rgba(222, 221, 221, 0.7);
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.2);
}
.mask {
opacity: 0;
position: absolute;
background: rgba(0,0,0,0.4);
cursor: pointer;
transition: opacity 0.4s;
&:hover {
opacity: 1;
}
i {
font-size: 2rem;
position: absolute;
top: 50%;
left: 50%;
margin-left: -1rem;
margin-top: -1rem;
color: #d6d6d6;
}
}
img, .mask {
width: 150px;
height: 150px;
border-radius: 50%;
overflow: hidden;
}
}
</style>
<template>
<div class="empty">
<img src="@/assets/svg/empty.svg" alt="" style="width:100px;">
<p style="padding-right:5px;">暂无数据</p>
</div>
</template>
<script>
export default {
name: 'Empty'
}
</script>
<style scoped lang="less">
.empty {
width: 100%;
height:300px; // 与环状图一个高度
display: flex;
justify-content:center;
align-items: center;
flex-direction: column;
text-align:center;
}
</style>
#chart-card {
width: 100%;
}
#chart-card .top-left {
min-height: 250px;
}
#chart-card .chart-data {
min-height: 100px;
height: 100%;
width: 100%;
border-radius: 6px;
background-color: #fff;
}
#chart-card .chart-top,
#chart-card .chart-bottom {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#chart-card .chart-top .middle-smaller,
#chart-card .chart-bottom .middle-smaller,
#chart-card .chart-top .middle-larger,
#chart-card .chart-bottom .middle-larger {
height: 100%;
}
#chart-card .chart-top .top-left,
#chart-card .chart-bottom .top-left {
min-height: 238px;
}
#chart-card .chart-item {
width: 100%;
box-sizing: border-box;
padding: 12px;
}
@media screen and (max-width: 767px) {
#chart-card .chart-top .top-left {
order: 1;
}
#chart-card .chart-top .top-middle {
order: 2;
width: 100%;
}
#chart-card .chart-top .top-middle .middle-top,
#chart-card .chart-top .top-middle .middle-bottom {
display: flex;
flex-direction: column;
}
#chart-card .chart-top .top-middle .middle-top .middle-larger,
#chart-card .chart-top .top-middle .middle-bottom .middle-larger,
#chart-card .chart-top .top-middle .middle-top .middle-smaller,
#chart-card .chart-top .top-middle .middle-bottom .middle-smaller {
width: 100%;
}
#chart-card .chart-top .top-right {
order: 0;
}
}
@media screen and (min-width: 768px) {
#chart-card .top-left,
#chart-card .top-middle {
order: 1;
}
#chart-card .top-middle {
width: 100%;
}
#chart-card .top-middle .middle-top,
#chart-card .top-middle .middle-bottom {
display: flex;
flex-direction: row;
}
#chart-card .top-middle .middle-top .middle-larger,
#chart-card .top-middle .middle-bottom .middle-larger {
flex-grow: 1;
}
#chart-card .top-middle .middle-top .middle-smaller,
#chart-card .top-middle .middle-bottom .middle-smaller {
max-width: 170px;
min-width: 150px;
}
#chart-card .top-right {
order: 0;
}
}
@media screen and (min-width: 1200px) {
#chart-card .top-left {
order: 1;
width: 50%;
}
#chart-card .top-middle {
width: 50%;
order: 2;
}
#chart-card .top-middle .middle-top,
#chart-card .top-middle .middle-bottom {
display: flex;
flex-direction: row;
}
#chart-card .top-middle .middle-top .middle-larger,
#chart-card .top-middle .middle-bottom .middle-larger {
flex-grow: 1;
}
#chart-card .top-middle .middle-top .middle-smaller,
#chart-card .top-middle .middle-bottom .middle-smaller {
max-width: 170px;
min-width: 150px;
}
#chart-card .top-right {
width: 100%;
order: 0;
}
}
@media screen and (min-width: 1500px) {
#chart-card {
flex-direction: row;
}
#chart-card .chart-top {
width: 100%;
order: 0;
flex-wrap: nowrap;
}
#chart-card .chart-top .top-left,
#chart-card .chart-top .top-middle {
width: 500px;
min-width: 460px;
order: 0;
}
#chart-card .chart-top .top-middle {
order: 1;
}
#chart-card .chart-top .top-middle .middle-top,
#chart-card .chart-top .top-middle .middle-bottom {
display: flex;
width: 100%;
height: 50%;
flex-wrap: nowrap;
}
#chart-card .chart-top .top-middle .middle-smaller {
min-width: 170px;
}
#chart-card .chart-top .top-middle .middle-larger {
width: 200px;
flex-grow: 1;
}
#chart-card .chart-top .top-right {
order: 2;
flex-grow: 1;
}
#chart-card .chart-bottom {
order: 1;
width: 100%;
flex-wrap: nowrap;
}
#chart-card .chart-bottom .bottom-right {
flex-shrink: 1;
max-width: 500px;
min-width: 330px;
}
#chart-card .chart-bottom .bottom-left {
min-width: 900px;
flex-grow: 1;
}
}
#chart-card {
width: 100%;
.top-left {
min-height: 250px;
}
.chart-data {
min-height: 100px;
height: 100%;
width: 100%;
border-radius: 6px;
background-color: #fff;
}
.chart-top, .chart-bottom {
display: flex;
flex-direction: row;
flex-wrap: wrap;
.middle-smaller, .middle-larger { // 较小的区域
height: 100%;
}
.top-left {
min-height: 238px;
}
}
.chart-item {
width: 100%;
box-sizing: border-box;
padding: 12px;
}
}
@media screen and (max-width:767px){
#chart-card {
.chart-top {
.top-left {
order: 1;
}
.top-middle {
order: 2;
width: 100%;
.middle-top, .middle-bottom {
display: flex;
flex-direction: column;
.middle-larger, .middle-smaller {
width: 100%;
}
}
}
.top-right {
order: 0;
}
}
}
}
@media screen and (min-width:768px){
#chart-card {
.top-left, .top-middle {
order: 1;
}
.top-middle {
width: 100%;
.middle-top, .middle-bottom {
display: flex;
flex-direction: row;
.middle-larger {
flex-grow: 1; // 设置为1,存在剩余空间放大
}
.middle-smaller {
max-width: 170px;
min-width: 150px;
}
}
}
.top-right {
order: 0;
}
}
}
@media screen and (min-width:1200px){
#chart-card {
.top-left {
order: 1;
width: 50%;
}
.top-middle {
width: 50%;
order: 2;
.middle-top, .middle-bottom {
display: flex;
flex-direction: row;
.middle-larger {
flex-grow: 1; // 设置为1,存在剩余空间放大
}
.middle-smaller {
max-width: 170px;
min-width: 150px;
}
}
}
.top-right {
width: 100%;
order: 0;
}
}
}
@media screen and (min-width:1500px){
#chart-card {
flex-direction: row;
.chart-top {
width:100%;
order: 0;
flex-wrap: nowrap; // 禁止换行
.top-left, .top-middle {
width:500px;
min-width: 460px;
order: 0;
}
.top-middle {
order: 1;
.middle-top, .middle-bottom {
display: flex;
width: 100%;
height: 50%;
flex-wrap: nowrap; // 禁止换行
}
.middle-smaller { // 较小的区域
min-width: 170px;
}
.middle-larger { // 较大的区域
width: 200px;
flex-grow: 1; // 设置为1,存在剩余空间放大
}
}
.top-right {
order: 2;
flex-grow: 1; // 设置为1,存在剩余空间放大
}
}
.chart-bottom {
order: 1;
width:100%;
flex-wrap: nowrap;
.bottom-right {
flex-shrink: 1;
max-width: 500px;
min-width: 330px;
}
.bottom-left {
min-width: 900px;
flex-grow: 1; // 设置为1,存在剩余空间放大
}
}
}
}
\ No newline at end of file
<template>
<a-modal v-model="isShow" :title=" isAdd ? '新增菜单' : '修改菜单' " @ok="handleOkFunc" :confirmLoading="confirmLoading">
<a-form-model ref="infoFormModel" :model="saveObject" :label-col="{span: 6}" :wrapper-col="{span: 15}" :rules="rules">
<a-form-model-item label="资源名称:" prop="entName">
<a-input v-model="saveObject.entName" />
</a-form-model-item>
<a-form-model-item label="路径地址:" prop="menuUri">
<a-input v-model="saveObject.menuUri" />
</a-form-model-item>
<a-form-model-item label="排序(正序显示):" prop="entSort">
<a-input v-model="saveObject.entSort" />
</a-form-model-item>
<a-form-model-item label="快速开始:" prop="quickJump">
<a-radio-group v-model="saveObject.quickJump" :disabled="saveObject.menuType == 'PB' || !saveObject.menuUri">
<a-radio :value="1"></a-radio>
<a-radio :value="0"></a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="状态:" prop="state">
<a-radio-group v-model="saveObject.state">
<a-radio :value="1">启用</a-radio>
<a-radio :value="0">停用</a-radio>
</a-radio-group>
</a-form-model-item>
</a-form-model>
</a-modal>
</template>
<script>
import { API_URL_ENT_LIST, req, getEntBySysType } from '@/api/manage'
export default {
props: {
callbackFunc: { type: Function }
},
data () {
return {
confirmLoading: false, // 显示确定按钮loading图标
isAdd: true, // 新增 or 修改页面标识
isShow: false, // 是否显示弹层/抽屉
saveObject: {}, // 数据对象
recordId: null, // 更新对象ID
sysType: 'MGR', // 菜单类型
rules: {
entName: [
{ required: true, message: '请输入资源名称', trigger: 'blur' }
]
}
}
},
created () {
},
methods: {
show: function (recordId, sysType) { // 弹层打开事件
this.isAdd = !recordId
this.sysType = sysType
this.saveObject = {} // 数据清空
this.confirmLoading = false // 关闭loading
if (this.$refs.infoFormModel !== undefined) {
this.$refs.infoFormModel.resetFields()
}
const that = this
if (!this.isAdd) { // 修改信息 延迟展示弹层
that.recordId = recordId
getEntBySysType(recordId, sysType).then(res => { that.saveObject = res })
this.isShow = true
} else {
that.isShow = true // 立马展示弹层信息
}
},
handleOkFunc: function () { // 点击【确认】按钮事件
const that = this
this.$refs.infoFormModel.validate(valid => {
if (valid) { // 验证通过
// 请求接口
that.confirmLoading = true // 显示loading
if (that.isAdd) {
} else {
req.updateById(API_URL_ENT_LIST, that.recordId, that.saveObject).then(res => {
that.$message.success('修改成功')
that.isShow = false
that.callbackFunc() // 刷新列表
}).catch(res => { that.confirmLoading = false })
}
}
})
}
}
}
</script>
<template>
<page-header-wrapper>
<a-card>
<div class="table-page-search-wrapper">
<a-form layout="inline" style="margin-bottom:30px">
<a-row :gutter="16">
<a-col :sm="18">
<a-row :gutter="16">
<a-col :md="6">
<a-form-item label="">
<a-select v-model="querySysType" placeholder="选择系统菜单" @change="refTable" class="table-head-layout">
<a-select-option value="MGR">显示菜单:运营平台</a-select-option>
<a-select-option value="MCH">显示菜单:商户系统</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</a-col>
</a-row>
</a-form>
</div>
<a-table
:columns="tableColumns"
:data-source="dataSource"
:pagination="false"
:loading="loading"
rowKey="entId"
:scroll="{ x: 1450 }">
<template slot="stateSlot" slot-scope="record">
<JeepayTableColState :state="record.state" :showSwitchType="$access('ENT_UR_ROLE_ENT_EDIT')" :onChange="(state) => { return updateState(record.entId, state)}"/>
</template>
<template slot="opSlot" slot-scope="record"> <!-- 操作列插槽 -->
<JeepayTableColumns>
<a v-if="$access('ENT_UR_ROLE_ENT_EDIT')" @click="editFunc(record.entId)">修改</a>
</JeepayTableColumns>
</template>
</a-table>
</a-card>
<!-- 新增 / 修改 页面组件 -->
<InfoAddOrEdit ref="infoAddOrEdit" :callbackFunc="refTable" />
</page-header-wrapper>
</template>
<script>
import { getEntTree, API_URL_ENT_LIST, reqLoad } from '@/api/manage'
import JeepayTableColState from '@/components/JeepayTable/JeepayTableColState'
import JeepayTableColumns from '@/components/JeepayTable/JeepayTableColumns'
import InfoAddOrEdit from './AddOrEdit'
const tableColumns = [
{ title: '资源权限ID', dataIndex: 'entId' }, // key为必填项,用于标志该列的唯一
{ title: '资源名称', dataIndex: 'entName' },
{ title: '图标', dataIndex: 'menuIcon' },
{ title: '路径', dataIndex: 'menuUri' },
{ title: '组件名称', dataIndex: 'componentName' },
{ title: '类型', dataIndex: 'entType' },
{ title: '状态', scopedSlots: { customRender: 'stateSlot' }, align: 'center' },
{ title: '排序', dataIndex: 'entSort' },
{ title: '修改时间', dataIndex: 'updatedAt' },
{ title: '操作', width: '100px', fixed: 'right', align: 'center', scopedSlots: { customRender: 'opSlot' } }
]
export default {
name: 'EntPage',
components: { JeepayTableColState, JeepayTableColumns, InfoAddOrEdit },
data () {
return {
querySysType: 'MGR', // 默认查询运营平台
tableColumns: tableColumns,
dataSource: [],
loading: false
}
},
mounted () {
this.refTable() // 刷新页面
},
methods: {
refTable: function () {
const that = this
that.loading = true
getEntTree(that.querySysType).then(res => {
that.dataSource = res
that.loading = false
})
},
updateState: function (recordId, state) {
const that = this
return reqLoad.updateById(API_URL_ENT_LIST, recordId, { state: state, sysType: that.querySysType }).then(res => {
that.$message.success('更新成功')
that.refTable() // 刷新页面
})
},
editFunc: function (recordId) { // 业务通用【修改】 函数
this.$refs.infoAddOrEdit.show(recordId, this.querySysType)
}
}
}
</script>
<template>
<div class="result-err">
<img src="~@/assets/svg/403.svg" alt="">
<div>
抱歉,您无权访问此页。
</div>
<a-button type="primary" @click="toHome" style="margin-top:30px">
返回首页
</a-button>
</div>
</template>
<script>
export default {
name: 'Exception403',
methods: {
toHome () {
this.$router.push({ path: '/' })
}
}
}
</script>
<template>
<div class="result-err">
<img src="~@/assets/svg/404.svg" alt="">
<div>
抱歉,您访问的页面不存在。
</div>
<a-button type="primary" @click="toHome" style="margin-top:30px">
返回首页
</a-button>
</div>
</template>
<script>
export default {
name: 'Exception404',
methods: {
toHome () {
this.$router.push({ path: '/' })
}
}
}
</script>
<template>
<div class="result-err">
<img src="~@/assets/svg/500.svg" alt="">
<div>
对不起,服务器错误。
</div>
<a-button type="primary" @click="toHome" style="margin-top:30px">
返回首页
</a-button>
</div>
</template>
<script>
export default {
name: 'Exception500',
methods: {
toHome () {
this.$router.push({ path: '/' })
}
}
}
</script>
<template>
<a-drawer
:maskClosable="false"
:visible="visible"
:title=" isAdd ? '新增服务商' : '修改服务商' "
@close="onClose"
:body-style="{ paddingBottom: '80px' }"
width="40%"
>
<a-form-model ref="infoFormModel" :model="saveObject" layout="vertical" :rules="rules">
<a-row justify="space-between" type="flex">
<a-col :span="10">
<a-form-model-item label="服务商名称" prop="isvName">
<a-input
placeholder="请输入服务商名称"
v-model="saveObject.isvName"
/>
</a-form-model-item>
</a-col>
<a-col :span="10">
<a-form-model-item label="服务商简称" prop="isvShortName">
<a-input
placeholder="请输入服务商简称"
v-model="saveObject.isvShortName"
/>
</a-form-model-item>
</a-col>
</a-row>
<a-row justify="space-between" type="flex">
<a-col :span="10">
<a-form-model-item label="联系人姓名" prop="contactName">
<a-input
placeholder="请输入联系人姓名"
v-model="saveObject.contactName"
/>
</a-form-model-item>
</a-col>
<a-col :span="10">
<a-form-model-item label="联系人手机号" prop="contactTel">
<a-input
placeholder="请输入联系人手机号"
v-model="saveObject.contactTel"
>
</a-input>
</a-form-model-item>
</a-col>
</a-row>
<a-row justify="space-between" type="flex">
<a-col :span="10">
<a-form-model-item label="联系人邮箱" prop="contactEmail">
<a-input
placeholder="请输入联系人邮箱"
v-model="saveObject.contactEmail"
>
</a-input>
</a-form-model-item>
</a-col>
<a-col :span="10">
<a-form-model-item label="状态" prop="state">
<a-radio-group v-model="saveObject.state" :defaultValue="1">
<a-radio :value="1">
启用
</a-radio>
<a-radio :value="0">
禁用
</a-radio>
</a-radio-group>
</a-form-model-item>
</a-col>
</a-row>
<a-row justify="space-between" type="flex">
<a-col :span="24">
<a-form-model-item label="备注" prop="remark">
<a-input v-model="saveObject.remark" placeholder="请输入备注" type="textarea" />
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
<div class="drawer-btn-center">
<a-button icon="close" @click="onClose" style="margin-right:8px">
取消
</a-button>
<a-button type="primary" style="margin-right:8px" icon="check" @click="handleOkFunc" :loading="btnLoading">
保存
</a-button>
</div>
</a-drawer>
</template>
<script>
import { API_URL_ISV_LIST, req } from '@/api/manage'
export default {
props: {
callbackFunc: { type: Function }
},
data () {
return {
btnLoading: false,
isAdd: true, // 新增 or 修改页面标志
saveObject: {}, // 数据对象
recordId: null, // 更新对象ID
visible: false, // 是否显示弹层/抽屉
rules: {
isvName: [ { required: true, message: '请输入服务商名称', trigger: 'blur' } ],
isvShortName: [ { required: true, message: '请输入服务商简称', trigger: 'blur' } ],
contactEmail: [{ required: false, pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/, message: '请输入正确的邮箱地址', trigger: 'blur' }],
contactTel: [{ required: false, pattern: /^1\d{10}$/, message: '请输入正确的手机号', trigger: 'blur' }]
}
}
},
created () {
},
methods: {
show: function (recordId) { // 弹层打开事件
this.isAdd = !recordId
this.saveObject = { 'state': 1 } // 数据清空
if (this.$refs.infoFormModel !== undefined) {
this.$refs.infoFormModel.resetFields()
}
const that = this
if (!this.isAdd) { // 修改信息 延迟展示弹层
that.recordId = recordId
req.getById(API_URL_ISV_LIST, recordId).then(res => {
that.saveObject = res
})
this.visible = true
} else {
that.visible = true // 立马展示弹层信息
}
},
handleOkFunc: function () { // 点击【确认】按钮事件
const that = this
this.$refs.infoFormModel.validate(valid => {
if (valid) { // 验证通过
that.btnLoading = true
// 请求接口
if (that.isAdd) {
req.add(API_URL_ISV_LIST, that.saveObject).then(res => {
that.$message.success('新增成功')
that.visible = false
that.callbackFunc() // 刷新列表
that.btnLoading = false
}).catch(res => {
that.btnLoading = false
})
} else {
req.updateById(API_URL_ISV_LIST, that.recordId, that.saveObject).then(res => {
that.$message.success('修改成功')
that.visible = false
that.callbackFunc() // 刷新列表
that.btnLoading = false
}).catch(res => {
that.btnLoading = false
})
}
}
})
},
onClose () {
this.visible = false
},
searchFunc: function () { // 点击【查询】按钮点击事件
this.$refs.infoTable.refTable(true)
}
}
}
</script>
<template>
<page-header-wrapper>
<a-card>
<div class="table-page-search-wrapper">
<a-form layout="inline" class="table-head-ground">
<div class="table-layer">
<jeepay-text-up :placeholder="'服务商号'" :msg="searchData.isvNo" v-model="searchData.isvNo" />
<jeepay-text-up :placeholder="'服务商名称'" :msg="searchData.isvName" v-model="searchData.isvName" />
<a-form-item label="" class="table-head-layout">
<a-select v-model="searchData.state" placeholder="服务商状态" default-value="">
<a-select-option value="">全部</a-select-option>
<a-select-option value="0">禁用</a-select-option>
<a-select-option value="1">启用</a-select-option>
</a-select>
</a-form-item>
<span class="table-page-search-submitButtons">
<a-button type="primary" icon="search" @click="queryFunc" :loading="btnLoading">搜索</a-button>
<a-button style="margin-left: 8px" icon="reload" @click="() => this.searchData = {}">重置</a-button>
</span>
</div>
</a-form>
<div>
<a-button icon="plus" v-if="$access('ENT_ISV_INFO_ADD')" type="primary" @click="addFunc" class="mg-b-30">新建</a-button>
</div>
</div>
<!-- 列表渲染 -->
<JeepayTable
@btnLoadClose="btnLoading=false"
ref="infoTable"
:initData="true"
:reqTableDataFunc="reqTableDataFunc"
:tableColumns="tableColumns"
:searchData="searchData"
rowKey="isvNo"
>
<template slot="isvNameSlot" slot-scope="{record}"><b>{{ record.isvName }}</b></template> <!-- 自定义插槽 -->
<template slot="stateSlot" slot-scope="{record}">
<a-badge :status="record.state === 0?'error':'processing'" :text="record.state === 0?'禁用':'启用'" />
</template>
<template slot="opSlot" slot-scope="{record}"> <!-- 操作列插槽 -->
<JeepayTableColumns>
<a-button type="link" v-if="$access('ENT_ISV_INFO_EDIT')" @click="editFunc(record.isvNo)">修改</a-button>
<a-button type="link" v-if="$access('ENT_ISV_PAY_CONFIG_LIST')" @click="showPayIfConfigList(record.isvNo)">支付配置</a-button>
<a-button type="link" v-if="$access('ENT_ISV_INFO_DEL')" style="color: red" @click="delFunc(record.isvNo)">删除</a-button>
</JeepayTableColumns>
</template>
</JeepayTable>
</a-card>
<!-- 新增页面组件 -->
<InfoAddOrEdit ref="infoAddOrEdit" :callbackFunc="searchFunc"/>
<!-- 支付参数配置页面组件 -->
<IsvPayIfConfigList ref="isvPayIfConfigList" />
</page-header-wrapper>
</template>
<script>
import JeepayTable from '@/components/JeepayTable/JeepayTable'
import JeepayTextUp from '@/components/JeepayTextUp/JeepayTextUp' // 文字上移组件
import JeepayTableColumns from '@/components/JeepayTable/JeepayTableColumns'
import { API_URL_ISV_LIST, req } from '@/api/manage'
import InfoAddOrEdit from './AddOrEdit'
import IsvPayIfConfigList from './IsvPayIfConfigList'
// eslint-disable-next-line no-unused-vars
const tableColumns = [
{ key: 'isvName', width: '200px', title: '服务商名称', fixed: 'left', scopedSlots: { customRender: 'isvNameSlot' } },
{ key: 'isvNo', title: '服务商号', dataIndex: 'isvNo' },
{ key: 'state', title: '服务商状态', scopedSlots: { customRender: 'stateSlot' } },
{ key: 'createdAt', dataIndex: 'createdAt', title: '创建日期' },
{ key: 'op', title: '操作', width: '260px', fixed: 'right', align: 'center', scopedSlots: { customRender: 'opSlot' } }
]
export default {
name: 'IsvListPage',
components: { JeepayTable, JeepayTableColumns, InfoAddOrEdit, IsvPayIfConfigList, JeepayTextUp },
data () {
return {
btnLoading: false,
tableColumns: tableColumns,
searchData: {}
}
},
mounted () {
},
methods: {
queryFunc () {
this.btnLoading = true
this.$refs.infoTable.refTable(true)
},
// 请求table接口数据
reqTableDataFunc: (params) => {
return req.list(API_URL_ISV_LIST, params)
},
delFunc: function (recordId) {
const that = this
this.$infoBox.confirmDanger('确认删除?', '请确认该服务商下未分配商户', () => {
req.delById(API_URL_ISV_LIST, recordId).then(res => {
that.$refs.infoTable.refTable(false)
this.$message.success('删除成功')
})
})
},
searchFunc: function () { // 点击【查询】按钮点击事件
this.$refs.infoTable.refTable(true)
},
addFunc: function () { // 业务通用【新增】 函数
this.$refs.infoAddOrEdit.show()
},
editFunc: function (recordId) { // 业务通用【修改】 函数
this.$refs.infoAddOrEdit.show(recordId)
},
showPayIfConfigList: function (recordId) { // 支付参数配置
this.$refs.isvPayIfConfigList.show(recordId)
}
}
}
</script>
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment