fix bugs
This commit is contained in:
16
src/App.vue
Normal file
16
src/App.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
15
src/api/common.js
Normal file
15
src/api/common.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from '@/axios';
|
||||
|
||||
/**
|
||||
* 文件流返回
|
||||
* @param url 接口地址
|
||||
* @param params 接口参数
|
||||
*/
|
||||
export const exportBlob = (url, params) => {
|
||||
return request({
|
||||
url: url,
|
||||
params: params,
|
||||
method: 'get',
|
||||
responseType: 'blob',
|
||||
});
|
||||
};
|
||||
59
src/api/desk/notice.js
Normal file
59
src/api/desk/notice.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-desk/notice/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
cryptoToken: false,
|
||||
cryptoData: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-desk/notice/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
cryptoToken: false,
|
||||
cryptoData: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-desk/notice/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
cryptoToken: false,
|
||||
cryptoData: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-desk/notice/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
cryptoToken: false,
|
||||
cryptoData: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const getNotice = id => {
|
||||
return request({
|
||||
url: '/blade-desk/notice/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
cryptoToken: false,
|
||||
cryptoData: false,
|
||||
});
|
||||
};
|
||||
12
src/api/export.js
Normal file
12
src/api/export.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import request from '@/api/request';
|
||||
// 上传图片 图片上传
|
||||
export const uploadImage = data => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/endpoint/put-file',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
};
|
||||
78
src/api/job/jobinfo.js
Normal file
78
src/api/job/jobinfo.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const change = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/change',
|
||||
method: 'post',
|
||||
params: {
|
||||
id: row.id,
|
||||
enable: row.enable,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const run = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/run',
|
||||
method: 'post',
|
||||
params: {
|
||||
id: row.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const sync = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-info/sync',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
57
src/api/job/jobserver.js
Normal file
57
src/api/job/jobserver.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-job/job-server/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-job/job-server/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-job/job-server/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-server/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-server/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const sync = row => {
|
||||
return request({
|
||||
url: '/blade-job/job-server/sync',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
62
src/api/logs.js
Normal file
62
src/api/logs.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getUsualList = (current, size) => {
|
||||
return request({
|
||||
url: '/blade-log/usual/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getApiList = (current, size) => {
|
||||
return request({
|
||||
url: '/blade-log/api/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getErrorList = (current, size) => {
|
||||
return request({
|
||||
url: '/blade-log/error/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getUsualLogs = id => {
|
||||
return request({
|
||||
url: '/blade-log/usual/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
export const getApiLogs = id => {
|
||||
return request({
|
||||
url: '/blade-log/api/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
export const getErrorLogs = id => {
|
||||
return request({
|
||||
url: '/blade-log/error/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
257
src/api/martial/competition.js
Normal file
257
src/api/martial/competition.js
Normal file
@@ -0,0 +1,257 @@
|
||||
import request from '@/router/axios';
|
||||
|
||||
// ==================== 武术赛事订单管理接口 ====================
|
||||
|
||||
/**
|
||||
* 订单分页查询
|
||||
* @param {Number} current - 当前页,默认1
|
||||
* @param {Number} size - 每页条数,默认10
|
||||
* @param {Object} params - 查询参数
|
||||
*/
|
||||
export const getOrderList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/order/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
...params
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
* @param {Number} id - 订单主键ID
|
||||
*/
|
||||
export const getOrderDetail = (id) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/order/detail',
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
* @param {Object} data - 订单数据
|
||||
*/
|
||||
export const addOrder = (data) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/order/save',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改订单
|
||||
* @param {Object} data - 订单数据
|
||||
*/
|
||||
export const updateOrder = (data) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/order/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除订单
|
||||
* @param {String} ids - 订单ID,多个用逗号分隔
|
||||
*/
|
||||
export const removeOrder = (ids) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/order/remove',
|
||||
method: 'post',
|
||||
params: { ids }
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 赛事报名详情接口 ====================
|
||||
|
||||
/**
|
||||
* 获取报名详情
|
||||
* @param {Number} id - 报名详情ID
|
||||
*/
|
||||
export const getRegistrationDetail = (id) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/registration/detail',
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参赛人员统计
|
||||
* @param {Number} registrationId - 报名详情ID
|
||||
*/
|
||||
export const getParticipantList = (registrationId) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/participant/list',
|
||||
method: 'get',
|
||||
params: { registrationId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目时间统计
|
||||
* @param {Number} registrationId - 报名详情ID
|
||||
*/
|
||||
export const getProjectTimeList = (registrationId) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/project-time/list',
|
||||
method: 'get',
|
||||
params: { registrationId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全额统计
|
||||
* @param {Number} registrationId - 报名详情ID
|
||||
*/
|
||||
export const getAmountStatsList = (registrationId) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/amount-stats/list',
|
||||
method: 'get',
|
||||
params: { registrationId }
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 赛事编排管理接口 ====================
|
||||
|
||||
/**
|
||||
* 编排分页查询
|
||||
* @param {Number} current - 当前页
|
||||
* @param {Number} size - 每页条数
|
||||
* @param {Object} params - 查询参数
|
||||
*/
|
||||
export const getScheduleList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/schedule/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
...params
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存编排
|
||||
* @param {Object} data - 编排数据
|
||||
*/
|
||||
export const saveSchedule = (data) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/schedule/save',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认完成编排
|
||||
* @param {Number} id - 编排ID
|
||||
*/
|
||||
export const confirmSchedule = (id) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/schedule/confirm',
|
||||
method: 'post',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 调度管理接口 ====================
|
||||
|
||||
/**
|
||||
* 调度分页查询
|
||||
* @param {Number} current - 当前页
|
||||
* @param {Number} size - 每页条数
|
||||
* @param {Object} params - 查询参数
|
||||
*/
|
||||
export const getDispatchList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/dispatch/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
current,
|
||||
size,
|
||||
...params
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记完赛
|
||||
* @param {Number} id - 调度ID
|
||||
*/
|
||||
export const markComplete = (id) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/dispatch/complete',
|
||||
method: 'post',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记裁判
|
||||
* @param {Number} id - 调度ID
|
||||
*/
|
||||
export const markReferee = (id) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/dispatch/referee',
|
||||
method: 'post',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 场地管理接口 ====================
|
||||
|
||||
/**
|
||||
* 场地列表查询
|
||||
* @param {Number} competitionId - 赛事ID
|
||||
*/
|
||||
export const getVenueList = (competitionId) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/venue/list',
|
||||
method: 'get',
|
||||
params: { competitionId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增场地
|
||||
* @param {Object} data - 场地数据
|
||||
*/
|
||||
export const addVenue = (data) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/venue/save',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改场地
|
||||
* @param {Object} data - 场地数据
|
||||
*/
|
||||
export const updateVenue = (data) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/venue/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除场地
|
||||
* @param {String} ids - 场地ID,多个用逗号分隔
|
||||
*/
|
||||
export const removeVenue = (ids) => {
|
||||
return request({
|
||||
url: '/api/blade-martial/venue/remove',
|
||||
method: 'post',
|
||||
params: { ids }
|
||||
})
|
||||
}
|
||||
22
src/api/report/report.js
Normal file
22
src/api/report/report.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-report/report/rest/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-report/report/rest/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
84
src/api/request.js
Normal file
84
src/api/request.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import axios from 'axios';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { getToken } from 'utils/auth';
|
||||
|
||||
// 创建 axios 实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_URL || '/api', // 从环境变量获取基础URL
|
||||
timeout: 15000, // 请求超时时间
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
},
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// 在请求发送之前做一些处理,例如添加 token
|
||||
const token = getToken();
|
||||
console.log('%c [ token ]: ', 'color: #bf2c9f; background: pink; font-size: 13px;', 'token');
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
config.headers['Blade-Auth'] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
// 处理请求错误
|
||||
console.error('请求错误:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
// 如果是导出接口,直接返回response
|
||||
if (response.config.responseType === 'blob') {
|
||||
return response;
|
||||
}
|
||||
|
||||
const res = response.data;
|
||||
|
||||
// 这里可以根据后端接口规范定义响应处理逻辑
|
||||
// 例如:如果后端返回 code 不为 200,则显示错误信息
|
||||
if (res.code !== 200) {
|
||||
ElMessage.error(res.message || '请求失败');
|
||||
return Promise.reject(new Error(res.message || '请求失败'));
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
error => {
|
||||
console.error('响应错误:', error);
|
||||
|
||||
// 处理 HTTP 错误状态
|
||||
let message = '请求失败';
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
message = '未授权,请重新登录';
|
||||
// 可以在这里处理登录过期逻辑
|
||||
break;
|
||||
case 403:
|
||||
message = '拒绝访问';
|
||||
break;
|
||||
case 404:
|
||||
message = '请求错误,未找到该资源';
|
||||
break;
|
||||
case 500:
|
||||
message = '服务器端出错';
|
||||
break;
|
||||
default:
|
||||
message = `连接错误${error.response.status}`;
|
||||
}
|
||||
} else {
|
||||
message = '网络连接异常,请稍后重试';
|
||||
}
|
||||
|
||||
ElMessage.error(message);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
49
src/api/resource/attach.js
Normal file
49
src/api/resource/attach.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-resource/attach/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-resource/attach/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-resource/attach/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-resource/attach/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-resource/attach/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
59
src/api/resource/oss.js
Normal file
59
src/api/resource/oss.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const enable = id => {
|
||||
return request({
|
||||
url: '/blade-resource/oss/enable',
|
||||
method: 'post',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
71
src/api/resource/sms.js
Normal file
71
src/api/resource/sms.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const enable = id => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/enable',
|
||||
method: 'post',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const send = (code, phones, params) => {
|
||||
return request({
|
||||
url: '/blade-resource/sms/endpoint/send-message',
|
||||
method: 'post',
|
||||
params: {
|
||||
code,
|
||||
phones,
|
||||
params,
|
||||
},
|
||||
});
|
||||
};
|
||||
45
src/api/system/autocode/part.js
Normal file
45
src/api/system/autocode/part.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import request from '@/axios';
|
||||
|
||||
// 查询规则组成
|
||||
export function listPart(query) {
|
||||
return request({
|
||||
url: '/system/autocode/part/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询规则组成详细
|
||||
export function getPart(partId) {
|
||||
return request({
|
||||
url: '/system/autocode/part/' + partId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 新增规则组成
|
||||
export function addPart(data) {
|
||||
return request({
|
||||
url: '/system/autocode/part',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改规则组成
|
||||
export function updatePart(data) {
|
||||
return request({
|
||||
url: '/system/autocode/part',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除规则组成
|
||||
export function delPart(partIds) {
|
||||
return request({
|
||||
url: '/system/autocode/part/' + partIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
98
src/api/system/autocode/rule.js
Normal file
98
src/api/system/autocode/rule.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getParentList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/system/autocode/rule/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getChildList = (current, size, ruleId, params) => {
|
||||
return request({
|
||||
url: '/system/autocode/part/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
ruleId: ruleId,
|
||||
},
|
||||
})
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/system/autocode/rule/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/system/autocode/rule',
|
||||
method: 'post',
|
||||
data: row
|
||||
})
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/system/autocode/rule',
|
||||
method: 'put',
|
||||
data: row
|
||||
})
|
||||
};
|
||||
export function getRule(ruleId) {
|
||||
return request({
|
||||
url: '/system/autocode/rule/' + ruleId,
|
||||
method: 'get'
|
||||
})
|
||||
};
|
||||
export const getDictTree = () => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/tree?code=DICT',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
export const getDictionary = params => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/dictionary',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
export const removePart = ids => {
|
||||
return request({
|
||||
url: '/system/autocode/part/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
};
|
||||
|
||||
export const addPart = row => {
|
||||
return request({
|
||||
url: '/system/autocode/part',
|
||||
method: 'post',
|
||||
data: row
|
||||
})
|
||||
};
|
||||
|
||||
export const updatePart = row => {
|
||||
return request({
|
||||
url: '/system/autocode/part',
|
||||
method: 'put',
|
||||
data: row
|
||||
})
|
||||
};
|
||||
export function getPart(partId) {
|
||||
return request({
|
||||
url: '/system/autocode/part/' + partId,
|
||||
method: 'get'
|
||||
})
|
||||
};
|
||||
49
src/api/system/client.js
Normal file
49
src/api/system/client.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/client/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-system/client/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/client/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/client/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/client/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
80
src/api/system/dept.js
Normal file
80
src/api/system/dept.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dept/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getLazyList = (parentId, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dept/lazy-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
parentId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/dept/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/dept/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/dept/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getDept = id => {
|
||||
return request({
|
||||
url: '/blade-system/dept/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDeptTree = tenantId => {
|
||||
return request({
|
||||
url: '/blade-system/dept/tree',
|
||||
method: 'get',
|
||||
params: {
|
||||
tenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDeptLazyTree = parentId => {
|
||||
return request({
|
||||
url: '/blade-system/dept/lazy-tree',
|
||||
method: 'get',
|
||||
params: {
|
||||
parentId,
|
||||
},
|
||||
});
|
||||
};
|
||||
88
src/api/system/dict.js
Normal file
88
src/api/system/dict.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dict/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getParentList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dict/parent-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getChildList = (current, size, parentId, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dict/child-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
parentId: parentId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/dict/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/dict/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/dict/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getDict = id => {
|
||||
return request({
|
||||
url: '/blade-system/dict/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
export const getDictTree = () => {
|
||||
return request({
|
||||
url: '/blade-system/dict/tree?code=DICT',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
export const getDictionary = params => {
|
||||
return request({
|
||||
url: '/blade-system/dict/dictionary',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
88
src/api/system/dictbiz.js
Normal file
88
src/api/system/dictbiz.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getParentList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/parent-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getChildList = (current, size, parentId, params) => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/child-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
parentId: parentId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getDict = id => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
export const getDictTree = () => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/tree?code=DICT',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
export const getDictionary = params => {
|
||||
return request({
|
||||
url: '/blade-system/dict-biz/dictionary',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
108
src/api/system/menu.js
Normal file
108
src/api/system/menu.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/menu/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getLazyList = (parentId, params) => {
|
||||
return request({
|
||||
url: '/blade-system/menu/lazy-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
parentId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getLazyMenuList = (parentId, params) => {
|
||||
return request({
|
||||
url: '/blade-system/menu/lazy-menu-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
parentId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getMenuList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/menu/menu-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getMenuTree = tenantId => {
|
||||
return request({
|
||||
url: '/blade-system/menu/tree',
|
||||
method: 'get',
|
||||
params: {
|
||||
tenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/menu/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/menu/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/menu/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getMenu = id => {
|
||||
return request({
|
||||
url: '/blade-system/menu/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getTopMenu = () =>
|
||||
request({
|
||||
url: '/blade-system/menu/top-menu',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
export const getRoutes = topMenuId =>
|
||||
request({
|
||||
url: '/blade-system/menu/routes',
|
||||
method: 'get',
|
||||
params: {
|
||||
topMenuId,
|
||||
},
|
||||
});
|
||||
49
src/api/system/param.js
Normal file
49
src/api/system/param.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/param/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-system/param/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/param/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/param/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/param/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
59
src/api/system/post.js
Normal file
59
src/api/system/post.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/post/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getPostList = tenantId => {
|
||||
return request({
|
||||
url: '/blade-system/post/select',
|
||||
method: 'get',
|
||||
params: {
|
||||
tenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-system/post/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/post/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/post/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/post/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
88
src/api/system/role.js
Normal file
88
src/api/system/role.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/role/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
export const grantTree = () => {
|
||||
return request({
|
||||
url: '/blade-system/menu/grant-tree',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
export const grant = (roleIds, menuIds, dataScopeIds, apiScopeIds) => {
|
||||
return request({
|
||||
url: '/blade-system/role/grant',
|
||||
method: 'post',
|
||||
data: {
|
||||
roleIds,
|
||||
menuIds,
|
||||
dataScopeIds,
|
||||
apiScopeIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/role/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/role/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/role/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getRole = roleIds => {
|
||||
return request({
|
||||
url: '/blade-system/menu/role-tree-keys',
|
||||
method: 'get',
|
||||
params: {
|
||||
roleIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getRoleTree = tenantId => {
|
||||
return request({
|
||||
url: '/blade-system/role/tree',
|
||||
method: 'get',
|
||||
params: {
|
||||
tenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getRoleTreeById = roleId => {
|
||||
return request({
|
||||
url: '/blade-system/role/tree-by-id',
|
||||
method: 'get',
|
||||
params: {
|
||||
roleId,
|
||||
},
|
||||
});
|
||||
};
|
||||
97
src/api/system/scope.js
Normal file
97
src/api/system/scope.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getListDataScope = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/data-scope/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const removeDataScope = ids => {
|
||||
return request({
|
||||
url: '/blade-system/data-scope/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const addDataScope = row => {
|
||||
return request({
|
||||
url: '/blade-system/data-scope/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const updateDataScope = row => {
|
||||
return request({
|
||||
url: '/blade-system/data-scope/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getMenuDataScope = id => {
|
||||
return request({
|
||||
url: '/blade-system/data-scope/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getListApiScope = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/api-scope/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const removeApiScope = ids => {
|
||||
return request({
|
||||
url: '/blade-system/api-scope/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const addApiScope = row => {
|
||||
return request({
|
||||
url: '/blade-system/api-scope/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const updateApiScope = row => {
|
||||
return request({
|
||||
url: '/blade-system/api-scope/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getMenuApiScope = id => {
|
||||
return request({
|
||||
url: '/blade-system/api-scope/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
102
src/api/system/tenant.js
Normal file
102
src/api/system/tenant.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const setting = (ids, form) => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/setting',
|
||||
method: 'post',
|
||||
params: {
|
||||
...form,
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const datasource = (tenantId, datasourceId) => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/datasource',
|
||||
method: 'post',
|
||||
params: {
|
||||
tenantId,
|
||||
datasourceId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const info = domain => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/info',
|
||||
method: 'get',
|
||||
params: {
|
||||
domain,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const packageInfo = tenantId => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/package-detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
tenantId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const packageSetting = (tenantId, packageId) => {
|
||||
return request({
|
||||
url: '/blade-system/tenant/package-setting',
|
||||
method: 'post',
|
||||
params: {
|
||||
tenantId,
|
||||
packageId,
|
||||
},
|
||||
});
|
||||
};
|
||||
49
src/api/system/tenantpackage.js
Normal file
49
src/api/system/tenantpackage.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/tenant-package/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-system/tenant-package/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/tenant-package/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/tenant-package/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/tenant-package/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
77
src/api/system/topmenu.js
Normal file
77
src/api/system/topmenu.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-system/topmenu/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-system/topmenu/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/topmenu/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/topmenu/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/topmenu/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const grantTree = () => {
|
||||
return request({
|
||||
url: '/blade-system/menu/grant-top-tree',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
export const getTopTree = topMenuIds => {
|
||||
return request({
|
||||
url: '/blade-system/menu/top-tree-keys',
|
||||
method: 'get',
|
||||
params: {
|
||||
topMenuIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const grant = (topMenuIds, menuIds) => {
|
||||
return request({
|
||||
url: '/blade-system/topmenu/grant',
|
||||
method: 'post',
|
||||
data: {
|
||||
topMenuIds,
|
||||
menuIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
130
src/api/system/user.js
Normal file
130
src/api/system/user.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params, deptId) => {
|
||||
return request({
|
||||
url: '/blade-system/user/page',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
deptId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-system/user/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-system/user/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-system/user/update',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const updatePlatform = (userId, userType, userExt) => {
|
||||
return request({
|
||||
url: '/blade-system/user/update-platform',
|
||||
method: 'post',
|
||||
params: {
|
||||
userId,
|
||||
userType,
|
||||
userExt,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getUser = id => {
|
||||
return request({
|
||||
url: '/blade-system/user/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getUserPlatform = id => {
|
||||
return request({
|
||||
url: '/blade-system/user/platform-detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getUserInfo = () => {
|
||||
return request({
|
||||
url: '/blade-system/user/info',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
export const resetPassword = userIds => {
|
||||
return request({
|
||||
url: '/blade-system/user/reset-password',
|
||||
method: 'post',
|
||||
params: {
|
||||
userIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const updatePassword = (oldPassword, newPassword, newPassword1) => {
|
||||
return request({
|
||||
url: '/blade-system/user/update-password',
|
||||
method: 'post',
|
||||
params: {
|
||||
oldPassword,
|
||||
newPassword,
|
||||
newPassword1,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const updateInfo = row => {
|
||||
return request({
|
||||
url: '/blade-system/user/update-info',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const grant = (userIds, roleIds) => {
|
||||
return request({
|
||||
url: '/blade-system/user/grant',
|
||||
method: 'post',
|
||||
params: {
|
||||
userIds,
|
||||
roleIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const unlock = userIds => {
|
||||
return request({
|
||||
url: '/blade-system/user/unlock',
|
||||
method: 'post',
|
||||
params: {
|
||||
userIds,
|
||||
},
|
||||
});
|
||||
};
|
||||
69
src/api/tool/code.js
Normal file
69
src/api/tool/code.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-develop/code/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const build = ids => {
|
||||
return request({
|
||||
url: '/blade-develop/code/gen-code',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
system: 'saber',
|
||||
},
|
||||
});
|
||||
};
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-develop/code/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-develop/code/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-develop/code/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const copy = id => {
|
||||
return request({
|
||||
url: '/blade-develop/code/copy',
|
||||
method: 'post',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getCode = id => {
|
||||
return request({
|
||||
url: '/blade-develop/code/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
49
src/api/tool/datasource.js
Normal file
49
src/api/tool/datasource.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-develop/datasource/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-develop/datasource/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-develop/datasource/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-develop/datasource/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-develop/datasource/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
110
src/api/tool/model.js
Normal file
110
src/api/tool/model.js
Normal file
@@ -0,0 +1,110 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const getList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-develop/model/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getDetail = id => {
|
||||
return request({
|
||||
url: '/blade-develop/model/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = ids => {
|
||||
return request({
|
||||
url: '/blade-develop/model/remove',
|
||||
method: 'post',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const add = row => {
|
||||
return request({
|
||||
url: '/blade-develop/model/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const update = row => {
|
||||
return request({
|
||||
url: '/blade-develop/model/submit',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const getTableList = datasourceId => {
|
||||
return request({
|
||||
url: '/blade-develop/model/table-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
datasourceId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getTableInfo = (modelId, datasourceId) => {
|
||||
return request({
|
||||
url: '/blade-develop/model/table-info',
|
||||
method: 'get',
|
||||
params: {
|
||||
modelId,
|
||||
datasourceId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getTableInfoByName = (tableName, datasourceId) => {
|
||||
return request({
|
||||
url: '/blade-develop/model/table-info',
|
||||
method: 'get',
|
||||
params: {
|
||||
tableName,
|
||||
datasourceId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getModelPrototype = (modelId, datasourceId) => {
|
||||
return request({
|
||||
url: '/blade-develop/model/model-prototype',
|
||||
method: 'get',
|
||||
params: {
|
||||
modelId,
|
||||
datasourceId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const submitModelPrototype = row => {
|
||||
return request({
|
||||
url: '/blade-develop/model-prototype/submit-list',
|
||||
method: 'post',
|
||||
data: row,
|
||||
});
|
||||
};
|
||||
|
||||
export const prototypeDetail = modelId => {
|
||||
return request({
|
||||
url: '/blade-develop/model-prototype/select',
|
||||
method: 'get',
|
||||
params: {
|
||||
modelId,
|
||||
},
|
||||
});
|
||||
};
|
||||
146
src/api/user.js
Normal file
146
src/api/user.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import request from '@/axios';
|
||||
|
||||
import website from '@/config/website';
|
||||
|
||||
export const loginByUsername = (tenantId, deptId, roleId, username, password, type, key, code) =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/token',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Tenant-Id': tenantId,
|
||||
'Dept-Id': website.switchMode ? deptId : '',
|
||||
'Role-Id': website.switchMode ? roleId : '',
|
||||
'Captcha-Key': key,
|
||||
'Captcha-Code': code,
|
||||
},
|
||||
params: {
|
||||
tenantId,
|
||||
username,
|
||||
password,
|
||||
grant_type: website.captchaMode ? 'captcha' : 'password',
|
||||
scope: 'all',
|
||||
type,
|
||||
},
|
||||
});
|
||||
|
||||
export const loginBySocial = (tenantId, source, code, state) =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/token',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Tenant-Id': tenantId,
|
||||
},
|
||||
params: {
|
||||
tenantId,
|
||||
source,
|
||||
code,
|
||||
state,
|
||||
grant_type: 'social',
|
||||
scope: 'all',
|
||||
},
|
||||
});
|
||||
|
||||
export const loginBySso = (state, code) =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/token',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Tenant-Id': state,
|
||||
},
|
||||
params: {
|
||||
tenantId: state,
|
||||
code,
|
||||
grant_type: 'authorization_code',
|
||||
scope: 'all',
|
||||
redirect_uri: website.redirectUri,
|
||||
},
|
||||
});
|
||||
|
||||
export const refreshToken = (refresh_token, tenantId, deptId, roleId) =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/token',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Tenant-Id': tenantId,
|
||||
'Dept-Id': website.switchMode ? deptId : '',
|
||||
'Role-Id': website.switchMode ? roleId : '',
|
||||
},
|
||||
params: {
|
||||
tenantId,
|
||||
refresh_token,
|
||||
grant_type: 'refresh_token',
|
||||
scope: 'all',
|
||||
},
|
||||
});
|
||||
|
||||
export const registerUser = (tenantId, name, account, password, phone, email) =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/token',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Tenant-Id': tenantId,
|
||||
},
|
||||
params: {
|
||||
name,
|
||||
username: account,
|
||||
account,
|
||||
password,
|
||||
phone,
|
||||
email,
|
||||
grant_type: 'register',
|
||||
scope: 'all',
|
||||
},
|
||||
});
|
||||
|
||||
export const registerGuest = (form, oauthId) =>
|
||||
request({
|
||||
url: '/blade-system/user/register-guest',
|
||||
method: 'post',
|
||||
params: {
|
||||
tenantId: form.tenantId,
|
||||
name: form.name,
|
||||
account: form.account,
|
||||
password: form.password,
|
||||
oauthId,
|
||||
},
|
||||
});
|
||||
|
||||
export const getButtons = () =>
|
||||
request({
|
||||
url: '/blade-system/menu/buttons',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
export const getCaptcha = () =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/captcha',
|
||||
method: 'get',
|
||||
authorization: false,
|
||||
});
|
||||
|
||||
export const logout = () =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/logout',
|
||||
method: 'get',
|
||||
authorization: false,
|
||||
});
|
||||
|
||||
export const getUserInfo = () =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/user-info',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
export const sendLogs = list =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/logout',
|
||||
method: 'post',
|
||||
data: list,
|
||||
});
|
||||
|
||||
export const clearCache = () =>
|
||||
request({
|
||||
url: '/blade-auth/oauth/clear-cache',
|
||||
method: 'get',
|
||||
authorization: false,
|
||||
});
|
||||
33
src/api/work/process.js
Normal file
33
src/api/work/process.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import request from '@/axios';
|
||||
|
||||
// =====================参数===========================
|
||||
|
||||
export const historyFlowList = processInstanceId => {
|
||||
return request({
|
||||
url: '/blade-flow/process/history-flow-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
processInstanceId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// =====================请假流程===========================
|
||||
|
||||
export const leaveProcess = data => {
|
||||
return request({
|
||||
url: '/blade-desk/process/leave/start-process',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const leaveDetail = businessId => {
|
||||
return request({
|
||||
url: '/blade-desk/process/leave/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
businessId,
|
||||
},
|
||||
});
|
||||
};
|
||||
79
src/api/work/work.js
Normal file
79
src/api/work/work.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import request from '@/axios';
|
||||
|
||||
export const startList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-flow/work/start-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const claimList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-flow/work/claim-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const todoList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-flow/work/todo-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const sendList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-flow/work/send-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const doneList = (current, size, params) => {
|
||||
return request({
|
||||
url: '/blade-flow/work/done-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
current,
|
||||
size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const claimTask = taskId => {
|
||||
return request({
|
||||
url: '/blade-flow/work/claim-task',
|
||||
method: 'post',
|
||||
params: {
|
||||
taskId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const completeTask = data => {
|
||||
return request({
|
||||
url: '/blade-flow/work/complete-task',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
130
src/axios.js
Normal file
130
src/axios.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* 全站http配置
|
||||
*
|
||||
* axios参数说明
|
||||
* isSerialize是否开启form表单提交
|
||||
* isToken是否需要token
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import store from '@/store/';
|
||||
import router from '@/router/';
|
||||
import { serialize } from 'utils/util';
|
||||
import { getToken } from 'utils/auth';
|
||||
import { isURL } from 'utils/validate';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import website from '@/config/website';
|
||||
import NProgress from 'nprogress'; // progress bar
|
||||
import 'nprogress/nprogress.css'; // progress bar style
|
||||
import { Base64 } from 'js-base64';
|
||||
import { baseUrl } from '@/config/env';
|
||||
import crypto from '@/utils/crypto';
|
||||
|
||||
axios.defaults.timeout = 10000;
|
||||
//返回其他状态吗
|
||||
axios.defaults.validateStatus = function (status) {
|
||||
return status >= 200 && status <= 500; // 默认的
|
||||
};
|
||||
//跨域请求,允许保存cookie
|
||||
axios.defaults.withCredentials = true;
|
||||
// NProgress Configuration
|
||||
NProgress.configure({
|
||||
showSpinner: false,
|
||||
});
|
||||
//HTTPrequest拦截
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
// start progress bar
|
||||
NProgress.start();
|
||||
//地址为已经配置状态则不添加前缀
|
||||
if (!isURL(config.url) && !config.url.startsWith(baseUrl)) {
|
||||
console.log(
|
||||
'%c [ ]: ',
|
||||
'color: #bf2c9f; background: pink; font-size: 13px;',
|
||||
'baseUrl',
|
||||
baseUrl,
|
||||
'config.url',
|
||||
config.url
|
||||
);
|
||||
config.url = baseUrl + config.url;
|
||||
}
|
||||
//安全请求header
|
||||
config.headers['Blade-Requested-With'] = 'BladeHttpRequest';
|
||||
//headers判断是否需要
|
||||
const authorization = config.authorization === false;
|
||||
if (!authorization) {
|
||||
config.headers['Authorization'] = `Basic ${Base64.encode(
|
||||
`${website.clientId}:${website.clientSecret}`
|
||||
)}`;
|
||||
}
|
||||
//headers判断请求是否携带token
|
||||
const meta = config.meta || {};
|
||||
const isToken = meta.isToken === false;
|
||||
//headers传递token是否加密
|
||||
const cryptoToken = config.cryptoToken === true;
|
||||
//判断传递数据是否加密
|
||||
const cryptoData = config.cryptoData === true;
|
||||
const token = getToken();
|
||||
if (token && !isToken) {
|
||||
config.headers[website.tokenHeader] = cryptoToken
|
||||
? 'crypto ' + crypto.encryptAES(token, crypto.cryptoKey)
|
||||
: 'bearer ' + token;
|
||||
}
|
||||
// 开启报文加密
|
||||
if (cryptoData) {
|
||||
if (config.params) {
|
||||
const data = crypto.encryptAES(JSON.stringify(config.params), crypto.aesKey);
|
||||
config.params = { data };
|
||||
}
|
||||
if (config.data) {
|
||||
config.text = true;
|
||||
config.data = crypto.encryptAES(JSON.stringify(config.data), crypto.aesKey);
|
||||
}
|
||||
}
|
||||
//headers中配置text请求
|
||||
if (config.text === true) {
|
||||
config.headers['Content-Type'] = 'text/plain';
|
||||
}
|
||||
//headers中配置serialize为true开启序列化
|
||||
if (config.method === 'post' && meta.isSerialize === true) {
|
||||
config.data = serialize(config.data);
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
//HTTPresponse拦截
|
||||
axios.interceptors.response.use(
|
||||
res => {
|
||||
NProgress.done();
|
||||
const status = res.data.code || res.status;
|
||||
const statusWhiteList = website.statusWhiteList || [];
|
||||
const message = res.data.msg || res.data.error_description || '系统错误';
|
||||
const config = res.config;
|
||||
const cryptoData = config.cryptoData === true;
|
||||
//如果在白名单里则自行catch逻辑处理
|
||||
if (statusWhiteList.includes(status)) return Promise.reject(res);
|
||||
//如果是401则跳转到登录页面
|
||||
if (status === 401) store.dispatch('FedLogOut').then(() => router.push({ path: '/login' }));
|
||||
// 如果请求为非200否者默认统一处理
|
||||
if (status !== 200) {
|
||||
ElMessage({
|
||||
message: message,
|
||||
type: 'error',
|
||||
});
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
// 解析加密报文
|
||||
if (cryptoData) {
|
||||
res.data = JSON.parse(crypto.decryptAES(res.data, crypto.aesKey));
|
||||
}
|
||||
return res;
|
||||
},
|
||||
error => {
|
||||
NProgress.done();
|
||||
return Promise.reject(new Error(error));
|
||||
}
|
||||
);
|
||||
|
||||
export default axios;
|
||||
128
src/components/basic-block/main.vue
Normal file
128
src/components/basic-block/main.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div class="basic-block" :style="styleName">
|
||||
<div class="box" :style="boxStyleName">
|
||||
<router-link :to="to">
|
||||
<span v-text="text"></span>
|
||||
<p v-text="dept"></p>
|
||||
<i :class="icon"></i>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'basicBlock',
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
},
|
||||
background: {
|
||||
type: String,
|
||||
},
|
||||
to: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
},
|
||||
dept: {
|
||||
type: String,
|
||||
},
|
||||
time: {
|
||||
type: [Number, String],
|
||||
},
|
||||
gutter: {
|
||||
type: [Number, String],
|
||||
default: 5,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
},
|
||||
width: {
|
||||
type: [Number, String],
|
||||
},
|
||||
height: {
|
||||
type: [Number, String],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
styleName() {
|
||||
return {
|
||||
animationDelay: `${this.time / 25}s`,
|
||||
width: `${this.width}px`,
|
||||
height: `${this.height}px`,
|
||||
margin: `${this.gutter}px`,
|
||||
};
|
||||
},
|
||||
boxStyleName() {
|
||||
return {
|
||||
backgroundColor: this.color,
|
||||
backgroundImage: `url('${this.background}')`,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.basic-block {
|
||||
opacity: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
animation: mymove 1s;
|
||||
animation-fill-mode: forwards;
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: all 1s;
|
||||
background-size: cover;
|
||||
|
||||
&:hover {
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
width: 80%;
|
||||
font-size: 10px;
|
||||
color: #eee;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
font-size: 50px !important;
|
||||
}
|
||||
|
||||
@keyframes mymove {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
57
src/components/basic-container/main.vue
Normal file
57
src/components/basic-container/main.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="basic-container" :style="styleName" :class="{ 'basic-container--block': block }">
|
||||
<el-card class="basic-container__card">
|
||||
<slot></slot>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'basicContainer',
|
||||
props: {
|
||||
radius: {
|
||||
type: [String, Number],
|
||||
default: 10,
|
||||
},
|
||||
background: {
|
||||
type: String,
|
||||
},
|
||||
block: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
styleName() {
|
||||
return {
|
||||
borderRadius: `${this.radius}px`,
|
||||
background: this.background,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.basic-container {
|
||||
padding: 10px 6px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&--block {
|
||||
height: 100%;
|
||||
|
||||
.basic-container__card {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__card {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
140
src/components/basic-video/main.vue
Normal file
140
src/components/basic-video/main.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div :style="styleName" class="basic-video">
|
||||
<div class="basic-video__border">
|
||||
<span :style="borderStyleName"></span>
|
||||
<span :style="borderStyleName"></span>
|
||||
<span :style="borderStyleName"></span>
|
||||
<span :style="borderStyleName"></span>
|
||||
</div>
|
||||
<img :style="imgStyleName" class="basic-video__img" :src="background" />
|
||||
<video class="basic-video__main" ref="main" autoplay muted></video>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RecordVideo from './plugin';
|
||||
|
||||
export default {
|
||||
name: 'basic-video',
|
||||
props: {
|
||||
background: {
|
||||
type: String,
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: 500,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
styleName() {
|
||||
return {
|
||||
width: `${this.width}px`,
|
||||
};
|
||||
},
|
||||
imgStyleName() {
|
||||
return {
|
||||
width: `${this.width / 2}px`,
|
||||
};
|
||||
},
|
||||
borderStyleName() {
|
||||
return {
|
||||
width: `${this.width / 15}px`,
|
||||
height: `${this.width / 15}px`,
|
||||
borderWidth: `${5}px`,
|
||||
};
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
videoObj: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.videoObj = new RecordVideo(this.$refs.main);
|
||||
const videoPromise = this.videoObj.init();
|
||||
videoPromise.then(() => {
|
||||
this.videoObj.mediaRecorder.addEventListener('stop', this.getData, false);
|
||||
});
|
||||
},
|
||||
startRecord() {
|
||||
this.videoObj.startRecord();
|
||||
},
|
||||
stopRecord() {
|
||||
this.videoObj.stopRecord();
|
||||
},
|
||||
getData() {
|
||||
const blob = new Blob(this.videoObj.chunks, {
|
||||
type: 'video/mp4',
|
||||
});
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.addEventListener('loadend', () => {
|
||||
var video_base64 = reader.result;
|
||||
this.$emit('data-change', video_base64);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.basic-video {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&__border {
|
||||
span {
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-width: 4px;
|
||||
color: #0073eb;
|
||||
border-style: solid;
|
||||
|
||||
&:nth-child(1) {
|
||||
left: 15px;
|
||||
top: 15px;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
border-left: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
bottom: 15px;
|
||||
left: 15px;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__img {
|
||||
width: 100px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&__main {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
88
src/components/basic-video/plugin.js
Normal file
88
src/components/basic-video/plugin.js
Normal file
@@ -0,0 +1,88 @@
|
||||
export default class RecordVideo {
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param {Object} videoObj 视频对象
|
||||
*/
|
||||
constructor(videoObj) {
|
||||
this.video = videoObj;
|
||||
this.mediaRecorder = null;
|
||||
this.chunks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @return {Object} promise
|
||||
*/
|
||||
init() {
|
||||
// 返回Promise对象
|
||||
// resolve 正常处理
|
||||
// reject 处理异常情况
|
||||
return new Promise((resovle, reject) => {
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({
|
||||
audio: true,
|
||||
video: true,
|
||||
// video: {
|
||||
// width: this.videoWidth,
|
||||
// height: this.videoHeight
|
||||
// }
|
||||
})
|
||||
// 返回一个媒体内容的流
|
||||
.then(stream => {
|
||||
// 检测是否支持 srcObject,该属性在新的浏览器支持
|
||||
if ('srcObject' in this.video) {
|
||||
this.video.srcObject = stream;
|
||||
} else {
|
||||
// 兼容旧的浏览器
|
||||
this.video.src = window.URL.createObjectURL(stream);
|
||||
}
|
||||
|
||||
// 当视频的元数据已经加载时触发
|
||||
this.video.addEventListener('loadmetadata', () => {
|
||||
this.video.play();
|
||||
});
|
||||
this.mediaRecorder = new MediaRecorder(stream);
|
||||
this.mediaRecorder.addEventListener('dataavailable', e => {
|
||||
this.chunks.push(e.data);
|
||||
});
|
||||
resovle();
|
||||
})
|
||||
// 异常抓取,包括用于禁用麦克风、摄像头
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频开始录制
|
||||
*/
|
||||
startRecord() {
|
||||
if (this.mediaRecorder.state === 'inactive') {
|
||||
this.mediaRecorder.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频结束录制
|
||||
*/
|
||||
stopRecord() {
|
||||
if (this.mediaRecorder.state === 'recording') {
|
||||
this.mediaRecorder.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测当前浏览器对否支持
|
||||
*
|
||||
* @return {boolean} 当前浏览器是否支持
|
||||
*/
|
||||
isSupport() {
|
||||
const flag = navigator.mediaDevices && navigator.mediaDevices.getUserMedia;
|
||||
if (flag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/components/error-page/403.vue
Normal file
23
src/components/error-page/403.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="error-page">
|
||||
<div class="img" style="background-image: url('/img/403.svg')"></div>
|
||||
<div class="content">
|
||||
<h1>403</h1>
|
||||
<div class="desc">抱歉,你无权访问该页面</div>
|
||||
<div class="actions">
|
||||
<router-link :to="{ path: '/' }">
|
||||
<el-button type="primary">返回首页</el-button>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'error-403',
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './style.scss';
|
||||
</style>
|
||||
23
src/components/error-page/404.vue
Normal file
23
src/components/error-page/404.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="error-page">
|
||||
<div class="img" style="background-image: url('/img/404.svg')"></div>
|
||||
<div class="content">
|
||||
<h1>404</h1>
|
||||
<div class="desc">抱歉,你访问的页面不存在</div>
|
||||
<div class="actions">
|
||||
<router-link :to="{ path: '/' }">
|
||||
<el-button type="primary">返回首页</el-button>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'error-404',
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './style.scss';
|
||||
</style>
|
||||
23
src/components/error-page/500.vue
Normal file
23
src/components/error-page/500.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="error-page">
|
||||
<div class="img" style="background-image: url('/img/500.svg')"></div>
|
||||
<div class="content">
|
||||
<h1>500</h1>
|
||||
<div class="desc">抱歉,服务器出错了</div>
|
||||
<div class="actions">
|
||||
<router-link :to="{ path: '/' }">
|
||||
<el-button type="primary">返回首页</el-button>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'error-500',
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './style.scss';
|
||||
</style>
|
||||
35
src/components/error-page/style.scss
Normal file
35
src/components/error-page/style.scss
Normal file
@@ -0,0 +1,35 @@
|
||||
.error-page {
|
||||
background: #f0f2f5;
|
||||
margin-top: -30px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.img {
|
||||
margin-right: 80px;
|
||||
height: 360px;
|
||||
width: 100%;
|
||||
max-width: 430px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.content {
|
||||
h1 {
|
||||
color: #434e59;
|
||||
font-size: 72px;
|
||||
font-weight: 600;
|
||||
line-height: 72px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
src/components/iframe/main.vue
Normal file
82
src/components/iframe/main.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<iframe :src="src" class="iframe" ref="iframe" />
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NProgress from 'nprogress'; // progress bar
|
||||
import 'nprogress/nprogress.css'; // progress bar style
|
||||
export default {
|
||||
name: 'AvueIframe',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
created() {
|
||||
NProgress.configure({ showSpinner: false });
|
||||
},
|
||||
mounted() {
|
||||
this.load();
|
||||
},
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.load();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
src() {
|
||||
return this.$route.query.url.replace(/#/g, '&');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 显示等待框
|
||||
show() {
|
||||
NProgress.start();
|
||||
},
|
||||
// 隐藏等待狂
|
||||
hide() {
|
||||
NProgress.done();
|
||||
},
|
||||
// 加载组件
|
||||
load() {
|
||||
this.show();
|
||||
//超时3s自动隐藏等待狂,加强用户体验
|
||||
let time = 3;
|
||||
const timeFunc = setInterval(() => {
|
||||
time--;
|
||||
if (time == 0) {
|
||||
this.hide();
|
||||
clearInterval(timeFunc);
|
||||
}
|
||||
}, 1000);
|
||||
this.iframeInit();
|
||||
},
|
||||
//iframe窗口初始化
|
||||
iframeInit() {
|
||||
const iframe = this.$refs.iframe;
|
||||
const clientHeight = document.documentElement.clientHeight - 150;
|
||||
if (!iframe) return;
|
||||
iframe.style.height = `${clientHeight}px`;
|
||||
if (iframe.attachEvent) {
|
||||
iframe.attachEvent('onload', () => {
|
||||
this.hide();
|
||||
});
|
||||
} else {
|
||||
iframe.onload = () => {
|
||||
this.hide();
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
129
src/components/third-register/main.vue
Normal file
129
src/components/third-register/main.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="账号注册"
|
||||
append-to-body
|
||||
v-model="accountBox"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="false"
|
||||
width="20%"
|
||||
>
|
||||
<el-form :model="form" ref="form" label-width="80px">
|
||||
<el-form-item v-if="tenantMode" label="租户编号">
|
||||
<el-input v-model="form.tenantId" placeholder="请输入租户编号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户姓名">
|
||||
<el-input v-model="form.name" placeholder="请输入用户姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号名称">
|
||||
<el-input v-model="form.account" placeholder="请输入账号名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号密码">
|
||||
<el-input v-model="form.password" placeholder="请输入账号密码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码">
|
||||
<el-input v-model="form.password2" placeholder="请输入确认密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" :loading="loading" @click="handleRegister">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { validatenull } from 'utils/validate';
|
||||
import { registerGuest } from '@/api/user';
|
||||
import { getTopUrl } from 'utils/util';
|
||||
import { info } from '@/api/system/tenant';
|
||||
import { resetRouter } from '@/router/index';
|
||||
|
||||
export default {
|
||||
name: 'thirdRegister',
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
tenantId: '',
|
||||
name: '',
|
||||
account: '',
|
||||
password: '',
|
||||
password2: '',
|
||||
},
|
||||
loading: false,
|
||||
tenantMode: true,
|
||||
accountBox: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo']),
|
||||
},
|
||||
created() {
|
||||
this.getTenant();
|
||||
},
|
||||
mounted() {
|
||||
// 若未登录则弹出框进行绑定
|
||||
if (validatenull(this.userInfo.user_id) || this.userInfo.user_id < 0) {
|
||||
this.form.name = this.userInfo.user_name;
|
||||
this.form.account = this.userInfo.user_name;
|
||||
this.accountBox = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleRegister() {
|
||||
if (this.form.tenantId === '') {
|
||||
this.$message.warning('请先输入租户编号');
|
||||
return;
|
||||
}
|
||||
if (this.form.account === '') {
|
||||
this.$message.warning('请先输入账号名称');
|
||||
return;
|
||||
}
|
||||
if (this.form.password === '' || this.form.password2 === '') {
|
||||
this.$message.warning('请先输入密码');
|
||||
return;
|
||||
}
|
||||
if (this.form.password !== this.form.password2) {
|
||||
this.$message.warning('两次密码输入不一致');
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
registerGuest(this.form, this.userInfo.oauth_id).then(
|
||||
res => {
|
||||
this.loading = false;
|
||||
const data = res.data;
|
||||
if (data.success) {
|
||||
this.accountBox = false;
|
||||
this.$alert('注册申请已提交,请耐心等待管理员通过!', '注册提示').then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
resetRouter();
|
||||
this.$router.push({ path: '/login' });
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.$message.error(data.msg || '提交失败');
|
||||
}
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
getTenant() {
|
||||
let domain = getTopUrl();
|
||||
// 临时指定域名,方便测试
|
||||
//domain = "https://bladex.cn";
|
||||
info(domain).then(res => {
|
||||
const data = res.data;
|
||||
if (data.success && data.data.tenantId) {
|
||||
this.form.tenantId = data.data.tenantId;
|
||||
this.tenantMode = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
2
src/config/env.js
Normal file
2
src/config/env.js
Normal file
@@ -0,0 +1,2 @@
|
||||
let baseUrl = import.meta.env.VITE_APP_API;
|
||||
export { baseUrl };
|
||||
118
src/config/iconList.js
Normal file
118
src/config/iconList.js
Normal file
@@ -0,0 +1,118 @@
|
||||
export default [
|
||||
{
|
||||
label: '通用图标',
|
||||
list: [
|
||||
'iconfont iconicon_roundadd',
|
||||
'iconfont iconicon_compile',
|
||||
'iconfont iconicon_glass',
|
||||
'iconfont iconicon_roundclose',
|
||||
'iconfont iconicon_roundreduce',
|
||||
'iconfont iconicon_delete',
|
||||
'iconfont iconicon_shakehands',
|
||||
'iconfont iconicon_task_done',
|
||||
'iconfont iconicon_voipphone',
|
||||
'iconfont iconicon_safety',
|
||||
'iconfont iconicon_work',
|
||||
'iconfont iconicon_study',
|
||||
'iconfont iconicon_task',
|
||||
'iconfont iconicon_subordinate',
|
||||
'iconfont iconicon_star',
|
||||
'iconfont iconicon_setting',
|
||||
'iconfont iconicon_sms',
|
||||
'iconfont iconicon_share',
|
||||
'iconfont iconicon_secret',
|
||||
'iconfont iconicon_scan_namecard',
|
||||
'iconfont iconicon_principal',
|
||||
'iconfont iconicon_group',
|
||||
'iconfont iconicon_send',
|
||||
'iconfont iconicon_scan',
|
||||
'iconfont iconicon_search',
|
||||
'iconfont iconicon_refresh',
|
||||
'iconfont iconicon_savememo',
|
||||
'iconfont iconicon_QRcode',
|
||||
'iconfont iconicon_im_keyboard',
|
||||
'iconfont iconicon_redpacket',
|
||||
'iconfont iconicon_photo',
|
||||
'iconfont iconicon_qq',
|
||||
'iconfont iconicon_wechat',
|
||||
'iconfont iconicon_phone',
|
||||
'iconfont iconicon_namecard',
|
||||
'iconfont iconicon_notice',
|
||||
'iconfont iconicon_next_arrow',
|
||||
'iconfont iconicon_left',
|
||||
'iconfont iconicon_more',
|
||||
'iconfont iconicon_details',
|
||||
'iconfont iconicon_message',
|
||||
'iconfont iconicon_mobilephone',
|
||||
'iconfont iconicon_im_voice',
|
||||
'iconfont iconicon_GPS',
|
||||
'iconfont iconicon_ding',
|
||||
'iconfont iconicon_exchange',
|
||||
'iconfont iconicon_cspace',
|
||||
'iconfont iconicon_doc',
|
||||
'iconfont iconicon_dispose',
|
||||
'iconfont iconicon_discovery',
|
||||
'iconfont iconicon_community_line',
|
||||
'iconfont iconicon_cloud_history',
|
||||
'iconfont iconicon_coinpurse_line',
|
||||
'iconfont iconicon_airplay',
|
||||
'iconfont iconicon_at',
|
||||
'iconfont iconicon_addressbook',
|
||||
'iconfont iconicon_boss',
|
||||
'iconfont iconicon_addperson',
|
||||
'iconfont iconicon_affiliations_li',
|
||||
'iconfont iconicon_addmessage',
|
||||
'iconfont iconicon_addresslist',
|
||||
'iconfont iconicon_add',
|
||||
'iconfont icongithub',
|
||||
'iconfont icongitee2',
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '系统图标',
|
||||
list: [
|
||||
'iconfont icon-zhongyingwen',
|
||||
'iconfont icon-caidan',
|
||||
'iconfont icon-rizhi1',
|
||||
'iconfont icon-zhuti',
|
||||
'iconfont icon-suoping',
|
||||
'iconfont icon-bug',
|
||||
'iconfont icon-qq1',
|
||||
'iconfont icon-weixin1',
|
||||
'iconfont icon-shouji',
|
||||
'iconfont icon-mima',
|
||||
'iconfont icon-yonghu',
|
||||
'iconfont icon-yanzhengma',
|
||||
'iconfont icon-canshu',
|
||||
'iconfont icon-dongtai',
|
||||
'iconfont icon-iconset0265',
|
||||
'iconfont icon-shujuzhanshi2',
|
||||
'iconfont icon-tuichuquanping',
|
||||
'iconfont icon-rizhi',
|
||||
'iconfont icon-cuowutishitubiao',
|
||||
'iconfont icon-debug',
|
||||
'iconfont icon-iconset0216',
|
||||
'iconfont icon-quanxian',
|
||||
'iconfont icon-quanxian',
|
||||
'iconfont icon-shuaxin',
|
||||
'iconfont icon-bofangqi-suoping',
|
||||
'iconfont icon-quanping',
|
||||
'iconfont icon-navicon',
|
||||
'iconfont icon-biaodan',
|
||||
'iconfont icon-liuliangyunpingtaitubiao08',
|
||||
'iconfont icon-caidanguanli',
|
||||
'iconfont icon-cuowu',
|
||||
'iconfont icon-wxbgongju',
|
||||
'iconfont icon-tuichu',
|
||||
'iconfont icon-daohanglanmoshi02',
|
||||
'iconfont icon-changyonglogo27',
|
||||
'iconfont icon-biaoge',
|
||||
'iconfont icon-baidu1',
|
||||
'iconfont icon-tubiao',
|
||||
'iconfont icon-souhu',
|
||||
'iconfont icon-msnui-360',
|
||||
'iconfont icon-iframe',
|
||||
'iconfont icon-huanyingye',
|
||||
],
|
||||
},
|
||||
];
|
||||
60
src/config/website.js
Normal file
60
src/config/website.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 全局配置文件
|
||||
*/
|
||||
export default {
|
||||
title: 'saber',
|
||||
logo: 'S',
|
||||
key: 'saber', //配置主键,目前用于存储
|
||||
indexTitle: 'Saber Admin',
|
||||
clientId: 'saber3', // 客户端id
|
||||
clientSecret: 'saber3_secret', // 客户端密钥
|
||||
tenantMode: true, // 是否开启租户模式
|
||||
tenantId: '000000', // 管理组租户编号
|
||||
captchaMode: true, // 是否开启验证码模式
|
||||
switchMode: false, // 是否开启部门切换模式
|
||||
lockPage: '/lock',
|
||||
tokenTime: 3000,
|
||||
tokenHeader: 'Blade-Auth',
|
||||
//http的status默认放行不才用统一处理的,
|
||||
statusWhiteList: [],
|
||||
//配置首页不可关闭
|
||||
setting: {
|
||||
sidebar: 'vertical',
|
||||
tag: true,
|
||||
debug: true,
|
||||
collapse: true,
|
||||
search: true,
|
||||
lock: true,
|
||||
screenshot: true,
|
||||
fullscren: true,
|
||||
theme: true,
|
||||
menu: true,
|
||||
},
|
||||
fistPage: {
|
||||
name: '首页',
|
||||
path: '/wel/index',
|
||||
},
|
||||
//配置菜单的属性
|
||||
menu: {
|
||||
iconDefault: 'icon-caidan',
|
||||
label: 'name',
|
||||
path: 'path',
|
||||
icon: 'source',
|
||||
children: 'children',
|
||||
query: 'query',
|
||||
href: 'path',
|
||||
meta: 'meta',
|
||||
},
|
||||
// 流程设计器类型(true->nutflow,false->flowable)
|
||||
designMode: true,
|
||||
// 流程设计器地址(flowable模式)
|
||||
designUrl: 'http://localhost:9999',
|
||||
// 第三方系统授权地址
|
||||
authUrl: 'http://localhost/blade-auth/oauth/render',
|
||||
// 报表设计器地址(cloud端口为8108,boot端口为80)
|
||||
reportUrl: 'http://localhost:8108/ureport',
|
||||
// 单点登录系统认证(blade-auth服务的地)
|
||||
ssoUrl: 'http://localhost:8100/oauth/authorize?client_id=saber3&response_type=code&redirect_uri=',
|
||||
// 单点登录回调地址(Saber服务的登录界面地址)
|
||||
redirectUri: 'http://localhost:2888/login',
|
||||
};
|
||||
341
src/const/tool/model.js
Normal file
341
src/const/tool/model.js
Normal file
@@ -0,0 +1,341 @@
|
||||
export const switchDic = [
|
||||
{
|
||||
label: '',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
value: 1,
|
||||
},
|
||||
];
|
||||
|
||||
export const entityDic = [
|
||||
{
|
||||
label: 'String',
|
||||
value: 'java.lang.String',
|
||||
},
|
||||
{
|
||||
label: 'Integer',
|
||||
value: 'java.lang.Integer',
|
||||
},
|
||||
{
|
||||
label: 'Long',
|
||||
value: 'java.lang.Long',
|
||||
},
|
||||
{
|
||||
label: 'Double',
|
||||
value: 'java.lang.Double',
|
||||
},
|
||||
{
|
||||
label: 'BigDecimal',
|
||||
value: 'java.math.BigDecimal',
|
||||
},
|
||||
{
|
||||
label: 'Boolean',
|
||||
value: 'java.lang.Boolean',
|
||||
},
|
||||
{
|
||||
label: 'Date',
|
||||
value: 'java.util.Date',
|
||||
},
|
||||
];
|
||||
|
||||
export const componentDic = [
|
||||
{
|
||||
label: '单行文本',
|
||||
value: 'input',
|
||||
},
|
||||
{
|
||||
label: '多行文本',
|
||||
value: 'textarea',
|
||||
},
|
||||
{
|
||||
label: '富文本',
|
||||
value: 'editor',
|
||||
},
|
||||
{
|
||||
label: '下拉选项',
|
||||
value: 'select',
|
||||
},
|
||||
{
|
||||
label: '树形下拉选项',
|
||||
value: 'tree',
|
||||
},
|
||||
{
|
||||
label: '单选框',
|
||||
value: 'radio',
|
||||
},
|
||||
{
|
||||
label: '多选框',
|
||||
value: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: '开关框',
|
||||
value: 'switch',
|
||||
},
|
||||
{
|
||||
label: '日期框',
|
||||
value: 'date',
|
||||
},
|
||||
];
|
||||
|
||||
export const queryDic = [
|
||||
{
|
||||
label: '等于',
|
||||
value: 'equal',
|
||||
},
|
||||
{
|
||||
label: '不等于',
|
||||
value: 'notequal',
|
||||
},
|
||||
{
|
||||
label: '大于',
|
||||
value: 'gt',
|
||||
},
|
||||
{
|
||||
label: '大于等于',
|
||||
value: 'ge',
|
||||
},
|
||||
{
|
||||
label: '小于',
|
||||
value: 'lt',
|
||||
},
|
||||
{
|
||||
label: '小于等于',
|
||||
value: 'le',
|
||||
},
|
||||
{
|
||||
label: '区间',
|
||||
value: 'between',
|
||||
},
|
||||
{
|
||||
label: '模糊',
|
||||
value: 'like',
|
||||
},
|
||||
{
|
||||
label: '左模糊',
|
||||
value: 'likeleft',
|
||||
},
|
||||
{
|
||||
label: '右模糊',
|
||||
value: 'likeright',
|
||||
},
|
||||
];
|
||||
|
||||
export const templateDic = [
|
||||
{
|
||||
label: '单表',
|
||||
value: 'crud',
|
||||
},
|
||||
{
|
||||
label: '主子表',
|
||||
value: 'sub',
|
||||
},
|
||||
{
|
||||
label: '树表',
|
||||
value: 'tree',
|
||||
},
|
||||
];
|
||||
|
||||
export const option = {
|
||||
height: 'auto',
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
tip: false,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
grid: true,
|
||||
selection: true,
|
||||
menuWidth: 250,
|
||||
column: [
|
||||
{
|
||||
label: '数据源',
|
||||
prop: 'datasourceId',
|
||||
search: true,
|
||||
span: 24,
|
||||
type: 'select',
|
||||
dicUrl: '/blade-develop/datasource/select',
|
||||
props: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择数据源',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '物理表名',
|
||||
prop: 'modelTable',
|
||||
type: 'tree',
|
||||
slot: true,
|
||||
dicData: [],
|
||||
props: {
|
||||
label: 'comment',
|
||||
value: 'name',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入数据库表名',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '模型类名',
|
||||
prop: 'modelClass',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入模型类名',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '模型名称',
|
||||
prop: 'modelName',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入模型名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '模型编号',
|
||||
prop: 'modelCode',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入模型编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '模型备注',
|
||||
prop: 'modelRemark',
|
||||
hide: true,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const optionModel = {
|
||||
border: true,
|
||||
index: true,
|
||||
addBtn: false,
|
||||
editBtn: false,
|
||||
addRowBtn: false,
|
||||
cellBtn: false,
|
||||
cancelBtn: false,
|
||||
tip: false,
|
||||
menu: false,
|
||||
selection: true,
|
||||
column: [
|
||||
{
|
||||
label: '物理列名',
|
||||
prop: 'jdbcName',
|
||||
},
|
||||
{
|
||||
label: '物理类型',
|
||||
prop: 'jdbcType',
|
||||
},
|
||||
{
|
||||
label: '实体列名',
|
||||
prop: 'propertyName',
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '实体类型',
|
||||
prop: 'propertyEntity',
|
||||
type: 'select',
|
||||
dicData: entityDic,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '字段说明',
|
||||
prop: 'jdbcComment',
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '列表显示',
|
||||
prop: 'isList',
|
||||
type: 'switch',
|
||||
dicData: switchDic,
|
||||
align: 'center',
|
||||
width: 60,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '表单显示',
|
||||
prop: 'isForm',
|
||||
type: 'switch',
|
||||
dicData: switchDic,
|
||||
align: 'center',
|
||||
width: 60,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '独占一行',
|
||||
prop: 'isRow',
|
||||
type: 'switch',
|
||||
dicData: switchDic,
|
||||
align: 'center',
|
||||
width: 60,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '必填',
|
||||
prop: 'isRequired',
|
||||
type: 'switch',
|
||||
dicData: switchDic,
|
||||
align: 'center',
|
||||
width: 60,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '组件类型',
|
||||
prop: 'componentType',
|
||||
type: 'select',
|
||||
dicData: componentDic,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '字典编码',
|
||||
prop: 'dictCode',
|
||||
type: 'select',
|
||||
dicUrl: '/blade-system/dict/select',
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'code',
|
||||
},
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '查询配置',
|
||||
prop: 'isQuery',
|
||||
type: 'switch',
|
||||
dicData: switchDic,
|
||||
align: 'center',
|
||||
width: 60,
|
||||
cell: true,
|
||||
},
|
||||
{
|
||||
label: '查询类型',
|
||||
prop: 'queryType',
|
||||
type: 'select',
|
||||
dicData: queryDic,
|
||||
cell: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
6
src/docker/Dockerfile
Normal file
6
src/docker/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM nginx
|
||||
VOLUME /tmp
|
||||
ENV LANG en_US.UTF-8
|
||||
ADD ./dist/ /usr/share/nginx/html/
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
25
src/error.js
Normal file
25
src/error.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import store from './store';
|
||||
|
||||
export default {
|
||||
install: app => {
|
||||
app.config.errorHandler = (err, vm, info) => {
|
||||
store.commit('ADD_LOGS', {
|
||||
type: 'error',
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
info,
|
||||
});
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.group('>>>>>> 错误信息 >>>>>>');
|
||||
console.log(info);
|
||||
console.groupEnd();
|
||||
console.group('>>>>>> Vue 实例 >>>>>>');
|
||||
console.log(vm);
|
||||
console.groupEnd();
|
||||
console.group('>>>>>> Error >>>>>>');
|
||||
console.log(err);
|
||||
console.groupEnd();
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
122
src/lang/en.js
Normal file
122
src/lang/en.js
Normal file
@@ -0,0 +1,122 @@
|
||||
export default {
|
||||
title: 'Saber Admin',
|
||||
logoutTip: 'Exit the system, do you want to continue?',
|
||||
submitText: 'submit',
|
||||
cancelText: 'cancel',
|
||||
search: 'Please input search content',
|
||||
menuTip: 'none menu list',
|
||||
common: {
|
||||
condition: 'condition',
|
||||
display: 'display',
|
||||
hide: 'hide',
|
||||
},
|
||||
tip: {
|
||||
select: 'Please select',
|
||||
input: 'Please input',
|
||||
},
|
||||
upload: {
|
||||
upload: 'upload',
|
||||
tip: 'Drag files here,/',
|
||||
},
|
||||
date: {
|
||||
start: 'Start date',
|
||||
end: 'End date',
|
||||
t: 'today',
|
||||
y: 'yesterday',
|
||||
n: 'nearly 7',
|
||||
a: 'whole',
|
||||
},
|
||||
form: {
|
||||
printBtn: 'print',
|
||||
mockBtn: 'mock',
|
||||
submitBtn: 'submit',
|
||||
emptyBtn: 'empty',
|
||||
},
|
||||
crud: {
|
||||
filter: {
|
||||
addBtn: 'add',
|
||||
clearBtn: 'clear',
|
||||
resetBtn: 'reset',
|
||||
cancelBtn: 'cancel',
|
||||
submitBtn: 'submit',
|
||||
},
|
||||
column: {
|
||||
name: 'name',
|
||||
hide: 'hide',
|
||||
fixed: 'fixed',
|
||||
filters: 'filters',
|
||||
sortable: 'sortable',
|
||||
index: 'index',
|
||||
width: 'width',
|
||||
},
|
||||
tipStartTitle: 'Currently selected',
|
||||
tipEndTitle: 'items',
|
||||
editTitle: 'edit',
|
||||
copyTitle: 'copy',
|
||||
addTitle: 'add',
|
||||
viewTitle: 'view',
|
||||
filterTitle: 'filter',
|
||||
showTitle: 'showTitle',
|
||||
menu: 'menu',
|
||||
addBtn: 'add',
|
||||
show: 'show',
|
||||
hide: 'hide',
|
||||
open: 'open',
|
||||
shrink: 'shrink',
|
||||
printBtn: 'print',
|
||||
excelBtn: 'excel',
|
||||
updateBtn: 'update',
|
||||
cancelBtn: 'cancel',
|
||||
searchBtn: 'search',
|
||||
emptyBtn: 'empty',
|
||||
menuBtn: 'menu',
|
||||
saveBtn: 'save',
|
||||
viewBtn: 'view',
|
||||
editBtn: 'edit',
|
||||
copyBtn: 'copy',
|
||||
delBtn: 'delete',
|
||||
},
|
||||
login: {
|
||||
title: 'Login ',
|
||||
info: 'BladeX Development Platform',
|
||||
tenantId: 'Please input tenantId',
|
||||
username: 'Please input username',
|
||||
password: 'Please input a password',
|
||||
wechat: 'Wechat',
|
||||
qq: 'QQ',
|
||||
github: 'github',
|
||||
gitee: 'gitee',
|
||||
phone: 'Please input a phone',
|
||||
code: 'Please input a code',
|
||||
submit: 'Login',
|
||||
userLogin: 'userLogin',
|
||||
phoneLogin: 'phoneLogin',
|
||||
thirdLogin: 'thirdLogin',
|
||||
ssoLogin: 'ssoLogin',
|
||||
msgText: 'send code',
|
||||
msgSuccess: 'reissued code',
|
||||
},
|
||||
navbar: {
|
||||
info: 'info',
|
||||
logOut: 'logout',
|
||||
userinfo: 'userinfo',
|
||||
switchDept: 'switch dept',
|
||||
dashboard: 'dashboard',
|
||||
lock: 'lock',
|
||||
bug: 'none bug',
|
||||
bugs: 'bug',
|
||||
screenfullF: 'exit screenfull',
|
||||
screenfull: 'screenfull',
|
||||
language: 'language',
|
||||
notice: 'notice',
|
||||
theme: 'theme',
|
||||
color: 'color',
|
||||
},
|
||||
tagsView: {
|
||||
search: 'Search',
|
||||
menu: 'menu',
|
||||
clearCache: 'Clear Cache',
|
||||
closeOthers: 'Close Others',
|
||||
closeAll: 'Close All',
|
||||
},
|
||||
};
|
||||
26
src/lang/index.js
Normal file
26
src/lang/index.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import Store from '@/store';
|
||||
import elementEnLocale from 'element-plus/es/locale/lang/en';
|
||||
import elementZhLocale from 'element-plus/es/locale/lang/zh-cn';
|
||||
import enLocale from './en';
|
||||
import zhLocale from './zh';
|
||||
import AvueEnLocale from '@smallwei/avue/lib/locale/lang/en';
|
||||
import AvueZhLocale from '@smallwei/avue/lib/locale/lang/zh';
|
||||
|
||||
export const messages = {
|
||||
en: {
|
||||
...enLocale,
|
||||
...AvueEnLocale,
|
||||
...elementEnLocale,
|
||||
},
|
||||
'zh-cn': {
|
||||
...zhLocale,
|
||||
...AvueZhLocale,
|
||||
...elementZhLocale,
|
||||
},
|
||||
};
|
||||
export const language = Store.getters.language;
|
||||
export default createI18n({
|
||||
locale: language,
|
||||
messages,
|
||||
});
|
||||
122
src/lang/zh.js
Normal file
122
src/lang/zh.js
Normal file
@@ -0,0 +1,122 @@
|
||||
export default {
|
||||
title: 'Saber企业级开发平台',
|
||||
logoutTip: '退出系统, 是否继续?',
|
||||
submitText: '确定',
|
||||
cancelText: '取消',
|
||||
search: '请输入搜索内容',
|
||||
menuTip: '没有发现菜单',
|
||||
common: {
|
||||
condition: '条件',
|
||||
display: '显示',
|
||||
hide: '隐藏',
|
||||
},
|
||||
tip: {
|
||||
select: '请选择',
|
||||
input: '请输入',
|
||||
},
|
||||
upload: {
|
||||
upload: '点击上传',
|
||||
tip: '将文件拖到此处,或',
|
||||
},
|
||||
date: {
|
||||
start: '开始日期',
|
||||
end: '结束日期',
|
||||
t: '今日',
|
||||
y: '昨日',
|
||||
n: '近7天',
|
||||
a: '全部',
|
||||
},
|
||||
form: {
|
||||
printBtn: '打 印',
|
||||
mockBtn: '模 拟',
|
||||
submitBtn: '提 交',
|
||||
emptyBtn: '清 空',
|
||||
},
|
||||
crud: {
|
||||
filter: {
|
||||
addBtn: '新增条件',
|
||||
clearBtn: '清空数据',
|
||||
resetBtn: '清空条件',
|
||||
cancelBtn: '取 消',
|
||||
submitBtn: '确 定',
|
||||
},
|
||||
column: {
|
||||
name: '列名',
|
||||
hide: '隐藏',
|
||||
fixed: '冻结',
|
||||
filters: '过滤',
|
||||
sortable: '排序',
|
||||
index: '顺序',
|
||||
width: '宽度',
|
||||
},
|
||||
tipStartTitle: '当前表格已选择',
|
||||
tipEndTitle: '项',
|
||||
editTitle: '编 辑',
|
||||
copyTitle: '复 制',
|
||||
addTitle: '新 增',
|
||||
viewTitle: '查 看',
|
||||
filterTitle: '过滤条件',
|
||||
showTitle: '列显隐',
|
||||
menu: '操作',
|
||||
addBtn: '新 增',
|
||||
show: '显 示',
|
||||
hide: '隐 藏',
|
||||
open: '展 开',
|
||||
shrink: '收 缩',
|
||||
printBtn: '打 印',
|
||||
excelBtn: '导 出',
|
||||
updateBtn: '修 改',
|
||||
cancelBtn: '取 消',
|
||||
searchBtn: '搜 索',
|
||||
emptyBtn: '清 空',
|
||||
menuBtn: '功 能',
|
||||
saveBtn: '保 存',
|
||||
viewBtn: '查 看',
|
||||
editBtn: '编 辑',
|
||||
copyBtn: '复 制',
|
||||
delBtn: '删 除',
|
||||
},
|
||||
login: {
|
||||
title: '登录 ',
|
||||
info: 'BladeX 企业级开发平台',
|
||||
tenantId: '请输入租户ID',
|
||||
username: '请输入账号',
|
||||
password: '请输入密码',
|
||||
wechat: '微信',
|
||||
qq: 'QQ',
|
||||
github: 'github',
|
||||
gitee: '码云',
|
||||
phone: '请输入手机号',
|
||||
code: '请输入验证码',
|
||||
submit: '登录',
|
||||
register: '注册',
|
||||
userLogin: '账号密码登录',
|
||||
phoneLogin: '手机号登录',
|
||||
thirdLogin: '第三方系统登录',
|
||||
ssoLogin: '单点系统登录',
|
||||
msgText: '发送验证码',
|
||||
msgSuccess: '秒后重发',
|
||||
},
|
||||
navbar: {
|
||||
logOut: '退出登录',
|
||||
userinfo: '个人信息',
|
||||
switchDept: '部门切换',
|
||||
dashboard: '首页',
|
||||
lock: '锁屏',
|
||||
bug: '没有错误日志',
|
||||
bugs: '条错误日志',
|
||||
screenfullF: '退出全屏',
|
||||
screenfull: '全屏',
|
||||
language: '中英文',
|
||||
notice: '消息通知',
|
||||
theme: '主题',
|
||||
color: '换色',
|
||||
},
|
||||
tagsView: {
|
||||
search: '搜索',
|
||||
menu: '更多',
|
||||
clearCache: '清除缓存',
|
||||
closeOthers: '关闭其它',
|
||||
closeAll: '关闭所有',
|
||||
},
|
||||
};
|
||||
391
src/mac/index.vue
Normal file
391
src/mac/index.vue
Normal file
@@ -0,0 +1,391 @@
|
||||
<template>
|
||||
<div class="mac_bg"></div>
|
||||
<div class="desktop">
|
||||
<div class="top">
|
||||
<el-dropdown trigger="click">
|
||||
<div class="logo"><i class="iconfont iconicon_setting"></i></div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<div>{{ userInfo.username }}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<top-lock text="锁定屏幕"></top-lock>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<div @click="switchTheme">退出主题</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout">{{ $t('navbar.logOut') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<div class="space"></div>
|
||||
<div class="status">
|
||||
<div class="audio">
|
||||
<i class="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu-39"></i>
|
||||
</div>
|
||||
<div class="datetime">{{ timeString }}</div>
|
||||
<div class="notification">
|
||||
<i class="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu-25"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="desktop-app">
|
||||
<template v-for="item in deskTopAppList" :key="item.key">
|
||||
<div class="app-item" @click="openApp(item)" v-if="!item.hideInDesktop">
|
||||
<div class="icon" :style="{ backgroundColor: item.iconBgColor, color: item.iconColor }">
|
||||
<i class="iconfont" :class="item[iconKey]"></i>
|
||||
</div>
|
||||
<div class="title">{{ item[labelKey] }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="space"></div>
|
||||
<div class="dock">
|
||||
<template v-for="item in openAppList" :key="item.key">
|
||||
<div class="item" @click="openApp(item)">
|
||||
<i
|
||||
:style="{ backgroundColor: item.iconBgColor, color: item.iconColor }"
|
||||
class="iconfont"
|
||||
:class="item[iconKey]"
|
||||
></i>
|
||||
<small style="margin-top: 5px; font-size: 10px">{{ item[labelKey] }}</small>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="space"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import $Mode from './mode/index';
|
||||
import index from '@/mixins/index';
|
||||
import topLock from '@/page/index/top/top-lock.vue';
|
||||
|
||||
export default {
|
||||
mixins: [index],
|
||||
components: {
|
||||
topLock,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
app: false,
|
||||
timeString: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['menu', 'tagList', 'tagWel', 'tag', 'userInfo', 'isMacOs']),
|
||||
labelKey() {
|
||||
return this.website.menu.label;
|
||||
},
|
||||
pathKey() {
|
||||
return this.website.menu.path;
|
||||
},
|
||||
hrefKey() {
|
||||
return this.website.menu.href;
|
||||
},
|
||||
childrenKey() {
|
||||
return this.website.menu.children;
|
||||
},
|
||||
queryKey() {
|
||||
return this.website.menu.query;
|
||||
},
|
||||
iconKey() {
|
||||
return this.website.menu.icon;
|
||||
},
|
||||
menuList() {
|
||||
let result = [];
|
||||
const findMenu = list => {
|
||||
list.forEach(ele => {
|
||||
if (ele[this.childrenKey] && ele[this.childrenKey].length !== 0) {
|
||||
findMenu(ele[this.childrenKey]);
|
||||
} else {
|
||||
result.push(ele);
|
||||
}
|
||||
});
|
||||
};
|
||||
findMenu(this.menu);
|
||||
return result;
|
||||
},
|
||||
deskTopAppList() {
|
||||
return this.menuList;
|
||||
},
|
||||
openAppList() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.startTimer();
|
||||
this.$store.dispatch('GetMenu');
|
||||
},
|
||||
methods: {
|
||||
switchTheme() {
|
||||
this.$store.commit('SET_THEME_NAME', '');
|
||||
this.$router.push(this.tagWel);
|
||||
setTimeout(() => location.reload());
|
||||
},
|
||||
logout() {
|
||||
this.$store.commit('SET_THEME_NAME', '');
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
this.$router.push({ path: '/login' });
|
||||
setTimeout(() => location.reload());
|
||||
});
|
||||
},
|
||||
startTimer() {
|
||||
setInterval(() => {
|
||||
this.timeString = this.$dayjs().format('YYYY年MM月DD日 HH:mm');
|
||||
}, 1000);
|
||||
},
|
||||
openApp(item) {
|
||||
$Mode({
|
||||
title: item[this.labelKey],
|
||||
path: item[this.hrefKey] ? item[this.hrefKey] : item[this.pathKey],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.top .el-dropdown {
|
||||
color: white !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
.desktop {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
text-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.top {
|
||||
height: 28px;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
backdrop-filter: blur(20px);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 14px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0px 5px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.space {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0px 15px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo .el-select {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.logo .iconfont {
|
||||
font-size: 16px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.menu .item:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.audio .iconfont,
|
||||
.notification .iconfont {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.datetime,
|
||||
.audio,
|
||||
.notification {
|
||||
cursor: pointer;
|
||||
padding: 0px 10px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.datetime:hover,
|
||||
.audio:hover,
|
||||
.notification:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.body {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.footer .dock {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 10px;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.dock .item {
|
||||
padding: 3px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dock .dot {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.dock .item .iconfont {
|
||||
cursor: pointer;
|
||||
border-radius: 20px;
|
||||
padding: 2px;
|
||||
display: inline-block;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform 0.3s, margin 0.3s;
|
||||
}
|
||||
|
||||
.dock .item:hover .iconfont {
|
||||
transform: scale(2) translateY(-10px);
|
||||
margin: 0px 15px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dock .nearby .iconfont {
|
||||
transform: scale(1.6) translateY(-8px);
|
||||
margin: 0px 12px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dock .nearby1 .iconfont {
|
||||
transform: scale(1.2) translateY(-6px);
|
||||
margin: 0px 9px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dock .nearby2 .iconfont {
|
||||
transform: scale(1.1) translateY(-5px);
|
||||
margin: 0px 7px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.desktop-app {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
padding: 20px;
|
||||
flex-wrap: wrap-reverse;
|
||||
}
|
||||
|
||||
.app-item {
|
||||
margin: 5px 10px;
|
||||
padding: 5px;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
text-shadow: 0px 0px 2px rgb(0 0 0 / 50%);
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.app-item .icon {
|
||||
border-radius: 10px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.app-item .iconfont {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.app-item .title {
|
||||
font-size: 12px;
|
||||
width: 50px;
|
||||
margin-top: 5px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-item:hover {
|
||||
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
62
src/mac/lock.vue
Normal file
62
src/mac/lock.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="mac_bg"></div>
|
||||
<div class="login animate__animated" :class="{ animate__bounceOut: pass }">
|
||||
<div class="head">
|
||||
<img
|
||||
src="https://avatar.gitee.com/uploads/61/632261_smallweigit.jpg!avatar100?1518660401"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div class="message">{{ userInfo.username }}</div>
|
||||
<div class="form">
|
||||
<div class="item" style="width: 320px" :class="passwdError ? 'error' : ''">
|
||||
<input class="password" placeholder="password here..." v-model="passwd" type="password" />
|
||||
<i class="iconfont el-icon-unlock" @click="handleLogin"></i>
|
||||
<i class="iconfont icon-tuichu" @click="handleLogout"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
passwdError: false,
|
||||
passwd: '',
|
||||
pass: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'tag', 'lockPasswd']),
|
||||
},
|
||||
methods: {
|
||||
handleLogout() {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
this.$router.push({ path: '/login' });
|
||||
});
|
||||
},
|
||||
handleLogin() {
|
||||
if (this.passwd != this.lockPasswd) {
|
||||
this.passwd = '';
|
||||
this.passwdError = true;
|
||||
setTimeout(() => {
|
||||
this.passwdError = false;
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
this.pass = true;
|
||||
setTimeout(() => {
|
||||
this.$store.commit('CLEAR_LOCK');
|
||||
this.$router.push({
|
||||
path: this.tag.value,
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
@import url('./login.css');
|
||||
</style>
|
||||
134
src/mac/login.css
Normal file
134
src/mac/login.css
Normal file
@@ -0,0 +1,134 @@
|
||||
@keyframes loginErrorAnimation {
|
||||
0% {
|
||||
margin-left: -30px;
|
||||
}
|
||||
50% {
|
||||
margin-left: 30px;
|
||||
}
|
||||
100% {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.login {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: white;
|
||||
margin-top: -100px;
|
||||
z-index: 99999;
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.head {
|
||||
padding: 3px;
|
||||
background-size: 40% auto;
|
||||
background-position: center center;
|
||||
height: 150px;
|
||||
width: 150px;
|
||||
border-radius: 100%;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.1);
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.head img {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-top: 20px;
|
||||
font-size: 20px;
|
||||
text-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.3);
|
||||
color: #eee;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.password {
|
||||
transition: width 0.3s;
|
||||
}
|
||||
|
||||
.password-in {
|
||||
width: 155px;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: -50px;
|
||||
transition: right 0.3s;
|
||||
}
|
||||
|
||||
.click-enable {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
animation: loginErrorAnimation 0.2s ease 3;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::-moz-placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
:-ms-input-placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
width: 280px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item input {
|
||||
color: white;
|
||||
outline: none;
|
||||
border: none;
|
||||
margin: 5px 0;
|
||||
font-size: 16px;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
padding: 8px 24px;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item .iconfont {
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
font-size: 18px;
|
||||
border-radius: 100%;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.item .iconfont:hover {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
73
src/mac/login.vue
Normal file
73
src/mac/login.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="mac_bg"></div>
|
||||
<div class="login animate__animated" :class="{ animate__bounceOut: pass }">
|
||||
<div class="head">
|
||||
<img
|
||||
src="https://avatar.gitee.com/uploads/61/632261_smallweigit.jpg!avatar100?1518660401"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div class="message">Login Please</div>
|
||||
<div class="form">
|
||||
<div class="item" :class="isUserNameError ? 'error' : ''">
|
||||
<input class="account" placeholder="account here..." v-model="form.username" type="email" />
|
||||
</div>
|
||||
<div class="item" :class="isUserPasswordError ? 'error' : ''">
|
||||
<input
|
||||
class="password"
|
||||
placeholder="password here..."
|
||||
v-model="form.password"
|
||||
type="password"
|
||||
/>
|
||||
<i class="iconfont icon-send" @click="handleLogin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pass: false,
|
||||
isUserNameError: false,
|
||||
isUserPasswordError: false,
|
||||
form: {
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['tagWel']),
|
||||
},
|
||||
methods: {
|
||||
handleLogin() {
|
||||
if (this.form.username == '') {
|
||||
this.isUserNameError = true;
|
||||
setTimeout(() => {
|
||||
this.isUserNameError = false;
|
||||
}, 1000);
|
||||
return;
|
||||
return;
|
||||
} else if (this.form.password == '') {
|
||||
this.isUserPasswordError = true;
|
||||
setTimeout(() => {
|
||||
this.isUserPasswordError = false;
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
|
||||
this.pass = true;
|
||||
setTimeout(() => {
|
||||
this.$router.push(this.tagWel);
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
@import url('./login.css');
|
||||
</style>
|
||||
18
src/mac/mode/index.js
Normal file
18
src/mac/mode/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import MessageConstructor from './index.vue';
|
||||
import { createVNode, render } from 'vue';
|
||||
|
||||
export default (function () {
|
||||
return (opts = {}) => {
|
||||
let options = {
|
||||
app: opts,
|
||||
};
|
||||
const parent = document.createElement('div');
|
||||
let instance = createVNode(MessageConstructor, options);
|
||||
instance.props.onDestroy = () => {
|
||||
render(null, parent);
|
||||
};
|
||||
render(instance, parent);
|
||||
document.body.appendChild(parent.firstElementChild);
|
||||
return instance;
|
||||
};
|
||||
})();
|
||||
483
src/mac/mode/index.vue
Normal file
483
src/mac/mode/index.vue
Normal file
@@ -0,0 +1,483 @@
|
||||
<template>
|
||||
<div
|
||||
class="moveBg"
|
||||
v-show="isShow"
|
||||
@click="handleFocus"
|
||||
@mousemove="mouseMove"
|
||||
@mouseup="mouseUp"
|
||||
@mouseleave.stop="mouseLeave"
|
||||
:style="{ pointerEvents: isBoxResizing || isBoxMoving ? 'auto' : 'none' }"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
:style="{
|
||||
left: nowRect.left + 'px',
|
||||
top: nowRect.top + 'px',
|
||||
bottom: nowRect.bottom + 'px',
|
||||
right: nowRect.right + 'px',
|
||||
}"
|
||||
:class="getExtBoxClasses()"
|
||||
>
|
||||
<div class="box-top">
|
||||
<div class="box-top-left" @mousedown="resizeMouseDown"></div>
|
||||
<div class="box-top-center" @mousedown="resizeMouseDown"></div>
|
||||
<div class="box-top-right" @mousedown="resizeMouseDown"></div>
|
||||
</div>
|
||||
<div class="box-center">
|
||||
<div class="box-center-left" @mousedown="resizeMouseDown"></div>
|
||||
<div class="box-center-center loader">
|
||||
<div
|
||||
class="app-bar"
|
||||
:style="{ backgroundColor: app.tabbarBgColor }"
|
||||
@mousedown.stop="positionMouseDown"
|
||||
v-on:dblclick="appBarDoubleClicked"
|
||||
>
|
||||
<div class="controll">
|
||||
<div class="close" @click.stop="close"></div>
|
||||
<div
|
||||
class="full"
|
||||
:class="app.disableResize ? 'full-disabled' : ''"
|
||||
@click.stop="switchFullScreen"
|
||||
></div>
|
||||
</div>
|
||||
<div class="title" :style="{ color: app.tabbarTextColor }">{{ app.title }}</div>
|
||||
</div>
|
||||
<iframe :src="location + app.path" frameborder="0" class="iframe"></iframe>
|
||||
</div>
|
||||
<div class="box-center-right" @mousedown="resizeMouseDown"></div>
|
||||
</div>
|
||||
<div class="box-bottom">
|
||||
<div class="box-bottom-left" @mousedown="resizeMouseDown"></div>
|
||||
<div class="box-bottom-center" @mousedown="resizeMouseDown"></div>
|
||||
<div class="box-bottom-right" @mousedown="resizeMouseDown"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isURL } from 'utils/validate';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
app: Object,
|
||||
onDestroy: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: true,
|
||||
defaultIndex: 10,
|
||||
activeIndex: 20,
|
||||
isBoxMoving: false,
|
||||
startPosition: { x: 0, y: 0 },
|
||||
nowRect: {
|
||||
left: 100,
|
||||
right: 100,
|
||||
top: 100,
|
||||
bottom: 100,
|
||||
},
|
||||
startRect: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
isBoxResizing: false,
|
||||
moveDirection: false,
|
||||
isMaxShowing: false,
|
||||
isFullScreen: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
location() {
|
||||
return isURL(this.app.path) ? '' : window.location.origin;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.app.width) {
|
||||
this.nowRect.left = this.nowRect.right = (document.body.clientWidth - this.app.width) / 2;
|
||||
}
|
||||
if (this.app.height) {
|
||||
this.nowRect.bottom = (document.body.clientHeight - this.app.height) / 2 + 50;
|
||||
this.nowRect.top = (document.body.clientHeight - this.app.height) / 2 - 50;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFocus() {
|
||||
let list = document.getElementsByClassName('moveBg');
|
||||
if (list.length == 1) return;
|
||||
let max = 0;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let ele = list[i];
|
||||
let box = ele.getElementsByClassName('box')[0].style;
|
||||
let zIndex = Number(box.zIndex);
|
||||
if (max < zIndex) {
|
||||
max = zIndex;
|
||||
}
|
||||
}
|
||||
max = max + 1;
|
||||
this.$el.getElementsByClassName('box')[0].style.zIndex = max;
|
||||
},
|
||||
close() {
|
||||
this.isShow = false;
|
||||
this.onDestroy();
|
||||
},
|
||||
switchFullScreen() {
|
||||
if (this.app.disableResize) {
|
||||
return;
|
||||
}
|
||||
this.isFullScreen = !this.isFullScreen;
|
||||
if (this.isFullScreen) {
|
||||
this.isMaxShowing = true;
|
||||
} else {
|
||||
this.isMaxShowing = false;
|
||||
}
|
||||
},
|
||||
getExtBoxClasses() {
|
||||
let str = '';
|
||||
if (!this.isBoxResizing && !this.isBoxMoving) {
|
||||
str += 'box-animation ';
|
||||
}
|
||||
if (this.isMaxShowing) {
|
||||
str += 'isMaxShowing ';
|
||||
}
|
||||
if (this.isFullScreen) {
|
||||
str += 'isFullScreen ';
|
||||
}
|
||||
if (this.app.disableResize) {
|
||||
str += 'resize-disabled ';
|
||||
}
|
||||
if (this.app.isTop) {
|
||||
str += 'isTop ';
|
||||
}
|
||||
return str;
|
||||
},
|
||||
appBarDoubleClicked() {
|
||||
if (this.app.disableResize) {
|
||||
return;
|
||||
}
|
||||
this.isMaxShowing = !this.isMaxShowing;
|
||||
if (!this.isMaxShowing) {
|
||||
this.isFullScreen = false;
|
||||
}
|
||||
},
|
||||
positionMouseDown(e) {
|
||||
if (this.isFullScreen || this.isMaxShowing) {
|
||||
return;
|
||||
}
|
||||
this.startRect = {
|
||||
left: this.nowRect.left,
|
||||
right: this.nowRect.right,
|
||||
top: this.nowRect.top,
|
||||
bottom: this.nowRect.bottom,
|
||||
};
|
||||
this.startPosition.x = e.clientX;
|
||||
this.startPosition.y = e.clientY;
|
||||
this.isBoxMoving = true;
|
||||
},
|
||||
mouseUp() {
|
||||
this.isBoxMoving = false;
|
||||
this.isBoxResizing = false;
|
||||
this.moveDirection = false;
|
||||
},
|
||||
mouseLeave() {
|
||||
this.isBoxMoving = false;
|
||||
this.isBoxResizing = false;
|
||||
this.moveDirection = false;
|
||||
},
|
||||
mouseMove(e) {
|
||||
if (this.isBoxResizing) {
|
||||
this.isFullScreen = false;
|
||||
this.isMaxShowing = false;
|
||||
switch (this.moveDirection) {
|
||||
case 'box-top-left':
|
||||
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
|
||||
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
|
||||
break;
|
||||
case 'box-top-center':
|
||||
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
|
||||
break;
|
||||
case 'box-top-right':
|
||||
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
|
||||
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
|
||||
break;
|
||||
case 'box-center-left':
|
||||
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
|
||||
break;
|
||||
case 'box-bottom-left':
|
||||
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
|
||||
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
|
||||
break;
|
||||
case 'box-bottom-center':
|
||||
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
|
||||
break;
|
||||
case 'box-center-right':
|
||||
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
|
||||
break;
|
||||
case 'box-bottom-right':
|
||||
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
|
||||
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.isBoxMoving) {
|
||||
this.isFullScreen = false;
|
||||
this.isMaxShowing = false;
|
||||
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
|
||||
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
|
||||
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
|
||||
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
|
||||
return;
|
||||
}
|
||||
},
|
||||
resizeMouseDown(e) {
|
||||
if (this.app.disableResize) {
|
||||
return;
|
||||
}
|
||||
if (this.isFullScreen || this.isMaxShowing) {
|
||||
return;
|
||||
}
|
||||
this.startRect = {
|
||||
left: this.nowRect.left,
|
||||
top: this.nowRect.top,
|
||||
right: this.nowRect.right,
|
||||
bottom: this.nowRect.bottom,
|
||||
};
|
||||
this.startPosition.x = e.clientX;
|
||||
this.startPosition.y = e.clientY;
|
||||
this.isBoxResizing = true;
|
||||
this.moveDirection = e.target.className;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.iframe {
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
margin-top: 5px;
|
||||
border-right: 5px;
|
||||
}
|
||||
|
||||
.moveBg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.box {
|
||||
--resize: 5px;
|
||||
--resize-bg: transparent;
|
||||
--resize-main: transparent;
|
||||
--resize-bg-main: transparent;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
pointer-events: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.box-top {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.box-top-left {
|
||||
width: var(--resize);
|
||||
height: var(--resize);
|
||||
background: var(--resize-bg);
|
||||
cursor: nw-resize;
|
||||
}
|
||||
|
||||
.box-top-center {
|
||||
height: var(--resize);
|
||||
background: var(--resize-bg-main);
|
||||
cursor: n-resize;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.box-top-right {
|
||||
width: var(--resize);
|
||||
height: var(--resize);
|
||||
background: var(--resize-bg);
|
||||
cursor: ne-resize;
|
||||
}
|
||||
|
||||
.box-center {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.box-center-left {
|
||||
width: var(--resize);
|
||||
height: 100%;
|
||||
background: var(--resize-bg-main);
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.box-center-center {
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 3px #999;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(20px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.isTop .box-center-center {
|
||||
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.5);
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.box-animation {
|
||||
transition: width 0.1s, height 0.1s, left 0.1s, right 0.1s, top 0.1s, bottom 0.1s;
|
||||
}
|
||||
|
||||
.isMaxShowing {
|
||||
left: -5px !important;
|
||||
right: -5px !important;
|
||||
top: 24px !important;
|
||||
bottom: 47px !important;
|
||||
height: calc(100% - 24px);
|
||||
}
|
||||
|
||||
.isFullScreen {
|
||||
position: fixed !important;
|
||||
z-index: 999 !important;
|
||||
bottom: -5px !important;
|
||||
}
|
||||
|
||||
.isMaxShowing .box-center-center,
|
||||
.isFullScreen .box-center-center {
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
|
||||
.box-center-right {
|
||||
width: var(--resize);
|
||||
height: 100%;
|
||||
background: var(--resize-bg-main);
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.box-bottom {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.box-bottom-left {
|
||||
width: var(--resize);
|
||||
height: var(--resize);
|
||||
background: var(--resize-bg);
|
||||
cursor: sw-resize;
|
||||
}
|
||||
|
||||
.box-bottom-center {
|
||||
height: var(--resize);
|
||||
background: var(--resize-bg-main);
|
||||
cursor: s-resize;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.box-bottom-right {
|
||||
width: var(--resize);
|
||||
height: var(--resize);
|
||||
background: var(--resize-bg);
|
||||
cursor: se-resize;
|
||||
}
|
||||
|
||||
.loader {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app-bar {
|
||||
height: 40px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(20px);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-bar .controll {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.app-bar .controll div {
|
||||
border-radius: 100%;
|
||||
height: 11px;
|
||||
width: 11px;
|
||||
margin-right: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.app-bar .title {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
margin-right: 80px;
|
||||
font-weight: 500;
|
||||
text-shadow: none;
|
||||
font-size: 13px;
|
||||
cursor: move;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.controll .close {
|
||||
background: #fc605c;
|
||||
border: 1px solid #fc635d;
|
||||
}
|
||||
|
||||
.controll .min {
|
||||
background: #fcbb40;
|
||||
border: 1px solid #f8b438;
|
||||
}
|
||||
|
||||
.controll .full {
|
||||
background: #34c648;
|
||||
border: 1px solid #2bc03f;
|
||||
}
|
||||
|
||||
.full-disabled {
|
||||
background: #ccc !important;
|
||||
border: 1px solid #ccc !important;
|
||||
}
|
||||
|
||||
.resize-disabled .box-top-left,
|
||||
.resize-disabled .box-top-center,
|
||||
.resize-disabled .box-top-right,
|
||||
.resize-disabled .box-center-left,
|
||||
.resize-disabled .box-center-right,
|
||||
.resize-disabled .box-bottom-left,
|
||||
.resize-disabled .box-bottom-center,
|
||||
.resize-disabled .box-bottom-right {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.app-body {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
56
src/main.js
Normal file
56
src/main.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { createApp } from 'vue';
|
||||
import website from './config/website';
|
||||
import axios from './axios';
|
||||
import router from './router/';
|
||||
import store from './store';
|
||||
import i18n from './lang/';
|
||||
import { language, messages } from './lang/';
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
|
||||
import ElementPlus from 'element-plus';
|
||||
import 'element-plus/dist/index.css';
|
||||
import Avue from '@smallwei/avue';
|
||||
import '@smallwei/avue/lib/index.css';
|
||||
import crudCommon from '@/mixins/crud.js';
|
||||
import { getScreen } from './utils/util';
|
||||
import './permission';
|
||||
import error from './error';
|
||||
import avueUeditor from 'avue-plugin-ueditor';
|
||||
import basicBlock from 'components/basic-block/main.vue';
|
||||
import basicContainer from 'components/basic-container/main.vue';
|
||||
import thirdRegister from './components/third-register/main.vue';
|
||||
import NfDesignBase from '@saber/nf-design-base-elp';
|
||||
import App from './App.vue';
|
||||
import 'animate.css';
|
||||
import dayjs from 'dayjs';
|
||||
import 'styles/common.scss';
|
||||
// 业务组件
|
||||
import tenantPackage from './views/system/tenantpackage.vue';
|
||||
|
||||
window.$crudCommon = crudCommon;
|
||||
window.axios = axios;
|
||||
const app = createApp(App);
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
app.component('basicContainer', basicContainer);
|
||||
app.component('basicBlock', basicBlock);
|
||||
app.component('thirdRegister', thirdRegister);
|
||||
app.component('tenantPackage', tenantPackage);
|
||||
app.config.globalProperties.$dayjs = dayjs;
|
||||
app.config.globalProperties.website = website;
|
||||
app.config.globalProperties.getScreen = getScreen;
|
||||
app.use(error);
|
||||
app.use(i18n);
|
||||
app.use(store);
|
||||
app.use(router);
|
||||
app.use(ElementPlus, {
|
||||
locale: messages[language],
|
||||
});
|
||||
app.use(Avue, {
|
||||
axios,
|
||||
calcHeight: 10,
|
||||
locale: messages[language],
|
||||
});
|
||||
app.use(avueUeditor, { axios })
|
||||
app.use(NfDesignBase);
|
||||
app.mount('#app');
|
||||
217
src/mixins/crud.js
Normal file
217
src/mixins/crud.js
Normal file
@@ -0,0 +1,217 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default (app, option = {}) => {
|
||||
let optionObj = import.meta.glob(`../option/**/**`)[`../option/${option.name}.js`];
|
||||
let apiObj = import.meta.glob(`../api/**/**`)[`../api/${option.name}.js`];
|
||||
let mixins = {
|
||||
data() {
|
||||
return {
|
||||
data: [],
|
||||
form: {},
|
||||
params: {},
|
||||
option: {},
|
||||
api: {},
|
||||
loading: false,
|
||||
page: {},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
optionObj().then(mode => (this.option = mode.default));
|
||||
apiObj().then(mode => {
|
||||
this.api = mode;
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission', 'roles']),
|
||||
ids() {
|
||||
const ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele[this.rowKey]);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
bindVal() {
|
||||
return {
|
||||
ref: 'crud',
|
||||
option: this.option,
|
||||
data: this.data,
|
||||
tableLoading: this.loading,
|
||||
};
|
||||
},
|
||||
onEvent() {
|
||||
return {
|
||||
'size-change': this.sizeChange,
|
||||
'current-change': this.currentChange,
|
||||
'row-save': this.rowSave,
|
||||
'row-update': this.rowUpdate,
|
||||
'row-del': this.rowDel,
|
||||
'refresh-change': this.refreshChange,
|
||||
'search-reset': this.searchChange,
|
||||
'search-change': this.searchChange,
|
||||
};
|
||||
},
|
||||
rowKey() {
|
||||
return option.rowKey || 'id';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
const callback = () => {
|
||||
this.loading = true;
|
||||
this.data = [];
|
||||
this.api[option.list || 'getList'](
|
||||
this.page.currentPage,
|
||||
this.page.pageSize,
|
||||
this.params
|
||||
).then(res => {
|
||||
this.loading = false;
|
||||
let data;
|
||||
if (option.res) {
|
||||
data = option.res(res.data);
|
||||
} else {
|
||||
data = res.data.data;
|
||||
}
|
||||
this.page.total = data[option.total || 'total'];
|
||||
const result = data[option.data || 'records'];
|
||||
this.data = result;
|
||||
if (this.listAfter) {
|
||||
this.listAfter(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
if (this.listBefore) {
|
||||
this.listBefore();
|
||||
}
|
||||
callback();
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
const callback = () => {
|
||||
delete this.form.params;
|
||||
this.api[option.add || 'add'](this.form)
|
||||
.then(data => {
|
||||
this.getList();
|
||||
if (this.addAfter) {
|
||||
this.addAfter(data);
|
||||
} else {
|
||||
this.$message.success('新增成功');
|
||||
}
|
||||
done();
|
||||
})
|
||||
.catch(() => {
|
||||
loading();
|
||||
});
|
||||
};
|
||||
if (this.addBefore) {
|
||||
this.addBefore();
|
||||
}
|
||||
callback();
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
const callback = () => {
|
||||
delete this.form.params;
|
||||
this.api[option.update || 'update'](this.form)
|
||||
.then(data => {
|
||||
this.getList();
|
||||
if (this.updateAfter) {
|
||||
this.updateAfter(data);
|
||||
} else {
|
||||
this.$message.success('更新成功');
|
||||
}
|
||||
done();
|
||||
})
|
||||
.catch(() => {
|
||||
loading();
|
||||
});
|
||||
};
|
||||
if (this.updateBefore) {
|
||||
this.updateBefore();
|
||||
}
|
||||
callback();
|
||||
},
|
||||
rowDel(row, index) {
|
||||
const callback = () => {
|
||||
this.api[option.del || 'del'](row[this.rowKey], row).then(data => {
|
||||
this.getList();
|
||||
if (this.delAfter) {
|
||||
this.delAfter(data, row, index);
|
||||
} else {
|
||||
this.$message.success('删除成功');
|
||||
}
|
||||
});
|
||||
};
|
||||
if (this.delBefore) {
|
||||
this.delBefore();
|
||||
callback();
|
||||
} else {
|
||||
this.$confirm('确定将选择数据删除?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
this.api[option.del || 'remove'](this.ids).then(data => {
|
||||
this.getList();
|
||||
if (this.delMultiAfter) {
|
||||
this.delMultiAfter(data, this.ids);
|
||||
} else {
|
||||
this.$message.success('删除成功');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
searchChange(params, done) {
|
||||
if (done) done();
|
||||
this.params = params;
|
||||
this.page.currentPage = 1;
|
||||
this.getList();
|
||||
},
|
||||
dateChange(date) {
|
||||
if (date) {
|
||||
this.params.createTime_dategt = date[0];
|
||||
this.params.createTime_datelt = date[1];
|
||||
} else {
|
||||
delete this.params.createTime_dategt;
|
||||
delete this.params.createTime_datelt;
|
||||
}
|
||||
this.page.currentPage = 1;
|
||||
this.getList();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
refreshChange() {
|
||||
this.getList();
|
||||
},
|
||||
sizeChange(val) {
|
||||
this.page.currentPage = 1;
|
||||
this.page.pageSize = val;
|
||||
this.getList();
|
||||
},
|
||||
currentChange(val) {
|
||||
this.page.currentPage = val;
|
||||
this.getList();
|
||||
},
|
||||
},
|
||||
};
|
||||
app.mixins = app.mixins || [];
|
||||
app.mixins.push(mixins);
|
||||
return app;
|
||||
};
|
||||
46
src/mixins/index.js
Normal file
46
src/mixins/index.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import { validatenull } from '@/utils/validate';
|
||||
import { getStore } from '@/utils/store.js';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//刷新token锁
|
||||
refreshLock: false,
|
||||
//刷新token的时间
|
||||
refreshTime: '',
|
||||
};
|
||||
},
|
||||
created() {
|
||||
//实时检测刷新token
|
||||
this.refreshToken();
|
||||
},
|
||||
methods: {
|
||||
//实时检测刷新token
|
||||
refreshToken() {
|
||||
this.refreshTime = setInterval(() => {
|
||||
const token =
|
||||
getStore({
|
||||
name: 'token',
|
||||
debug: true,
|
||||
}) || {};
|
||||
let date1 = this.$dayjs(token.datetime);
|
||||
let date2 = this.$dayjs();
|
||||
const date = date2.diff(date1, 'seconds');
|
||||
if (validatenull(date)) return;
|
||||
if (date >= this.website.tokenTime && !this.refreshLock) {
|
||||
this.refreshLock = true;
|
||||
this.$store
|
||||
.dispatch('RefreshToken')
|
||||
.then(() => {
|
||||
this.refreshLock = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
this.refreshLock = false;
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
145
src/option/equip/approvalProcessNode.js
Normal file
145
src/option/equip/approvalProcessNode.js
Normal file
@@ -0,0 +1,145 @@
|
||||
export default {
|
||||
height:'auto',
|
||||
calcHeight: 30,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: "",
|
||||
prop: "id",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "项目编码",
|
||||
prop: "itemCode",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "项目名称",
|
||||
prop: "itemName",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "设备类型",
|
||||
prop: "deviceType",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "检查方法",
|
||||
prop: "checkMethod",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "检查标准",
|
||||
prop: "checkStandard",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "结果类型(数值/状态/文本)",
|
||||
prop: "checkResultType",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "检查单位",
|
||||
prop: "checkUnit",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "正常范围",
|
||||
prop: "normalRange",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "备注",
|
||||
prop: "remark",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "status",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "isDeleted",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "createDept",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "createUser",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "createTime",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "updateUser",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "updateTime",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
prop: "tenantId",
|
||||
type: "input",
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: false,
|
||||
hide: true,
|
||||
},
|
||||
]
|
||||
}
|
||||
515
src/option/job/jobinfo.js
Normal file
515
src/option/job/jobinfo.js
Normal file
@@ -0,0 +1,515 @@
|
||||
export const timeExpressionTypeDic = [
|
||||
{
|
||||
label: 'API',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'CRON',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '固定频率(毫秒)',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: '固定延迟(毫秒)',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
label: '工作流',
|
||||
value: 5,
|
||||
},
|
||||
];
|
||||
|
||||
export const executeTypeDic = [
|
||||
{
|
||||
label: '单机执行',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '广播执行',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: 'MapReduce',
|
||||
value: 3,
|
||||
},
|
||||
];
|
||||
|
||||
export const processorTypeDic = [
|
||||
{
|
||||
label: '内建处理器',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '外部处理器(动态加载)',
|
||||
value: 4,
|
||||
},
|
||||
];
|
||||
|
||||
export const dispatchStrategyDic = [
|
||||
{
|
||||
label: 'HEALTH_FIRST',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'RANDOM',
|
||||
value: 2,
|
||||
},
|
||||
];
|
||||
|
||||
export const enableDic = [
|
||||
{
|
||||
label: '暂停',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '启用',
|
||||
value: 1,
|
||||
},
|
||||
];
|
||||
|
||||
export const logTypeDic = [
|
||||
{
|
||||
label: 'ONLINE',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'LOCAL',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: 'STDOUT',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: 'LOCAL_AND_ONLINE',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
label: 'NULL',
|
||||
value: 999,
|
||||
},
|
||||
];
|
||||
|
||||
export const logLevelDic = [
|
||||
{
|
||||
label: 'DEBUG',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'INFO',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: 'WARN',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: 'ERROR',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
label: 'OFF',
|
||||
value: 99,
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
height: 'auto',
|
||||
calcHeight: 30,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
grid: true,
|
||||
labelWidth: 180,
|
||||
menuWidth: 350,
|
||||
dialogWidth: 1200,
|
||||
dialogClickModal: false,
|
||||
tabs: true,
|
||||
column: [
|
||||
{
|
||||
label: '任务应用',
|
||||
prop: 'jobServerId',
|
||||
type: 'select',
|
||||
dicUrl: '/blade-job/job-server/select',
|
||||
props: {
|
||||
label: 'jobAppName',
|
||||
value: 'id',
|
||||
},
|
||||
search: true,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '任务ID',
|
||||
prop: 'jobId',
|
||||
type: 'input',
|
||||
search: true,
|
||||
width: 80,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '任务名称',
|
||||
prop: 'jobName',
|
||||
type: 'input',
|
||||
search: true,
|
||||
width: 200,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '定时信息',
|
||||
labelTip: '时间表达式类型',
|
||||
prop: 'timeExpressionType',
|
||||
type: 'select',
|
||||
dicData: timeExpressionTypeDic,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择定时信息',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
width: 120,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '执行类型',
|
||||
labelTip: '枚举值',
|
||||
prop: 'executeType',
|
||||
type: 'select',
|
||||
dicData: executeTypeDic,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择执行器类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
width: 110,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '处理器类型',
|
||||
labelTip: '枚举值',
|
||||
prop: 'processorType',
|
||||
type: 'select',
|
||||
dicData: processorTypeDic,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择处理器类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
width: 180,
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
label: '任务状态',
|
||||
labelTip: '未启用的任务不会被调度',
|
||||
prop: 'enable',
|
||||
type: 'switch',
|
||||
dicData: enableDic,
|
||||
slot: true,
|
||||
width: 100,
|
||||
display: false,
|
||||
},
|
||||
],
|
||||
group: [
|
||||
{
|
||||
label: '基础配置',
|
||||
prop: 'modelSetting',
|
||||
icon: 'el-icon-tickets',
|
||||
column: [
|
||||
{
|
||||
label: '任务应用',
|
||||
prop: 'jobServerId',
|
||||
type: 'select',
|
||||
dicUrl: '/blade-job/job-server/select',
|
||||
props: {
|
||||
label: 'jobAppName',
|
||||
value: 'id',
|
||||
},
|
||||
editDisabled: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择任务应用',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '任务状态',
|
||||
labelTip: '未启用的任务不会被调度',
|
||||
prop: 'enable',
|
||||
type: 'switch',
|
||||
value: 1,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择是否开启',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '任务名称',
|
||||
prop: 'jobName',
|
||||
type: 'input',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入任务名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '生命周期',
|
||||
labelTip: '预留,用于指定定时调度任务的生效时间范围)',
|
||||
prop: 'lifecycle',
|
||||
type: 'datetimerange',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
startPlaceholder: '任务开始时间',
|
||||
endPlaceholder: '任务结束时间',
|
||||
},
|
||||
{
|
||||
label: '定时类型',
|
||||
labelTip: '时间表达式类型',
|
||||
prop: 'timeExpressionType',
|
||||
type: 'select',
|
||||
dicData: timeExpressionTypeDic,
|
||||
value: 2,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择定时信息',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '时间表达式',
|
||||
labelTip: '填写类型由 定时类型 决定,比如 CRON 需要填写 CRON 表达式',
|
||||
prop: 'timeExpression',
|
||||
type: 'input',
|
||||
},
|
||||
{
|
||||
label: '执行类型',
|
||||
labelTip: '枚举值',
|
||||
prop: 'executeType',
|
||||
type: 'select',
|
||||
dicData: executeTypeDic,
|
||||
value: 1,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择执行器类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '运行时配置',
|
||||
labelTip: '目前支持随机(RANDOM)和健康度优先(HEALTH_FIRST)',
|
||||
prop: 'dispatchStrategy',
|
||||
type: 'select',
|
||||
dicData: dispatchStrategyDic,
|
||||
value: 1,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择运行时配置',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '处理器类型',
|
||||
labelTip: '枚举值',
|
||||
prop: 'processorType',
|
||||
type: 'select',
|
||||
dicData: processorTypeDic,
|
||||
value: 1,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择处理器类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '处理器参数',
|
||||
labelTip:
|
||||
'如Java处理器需要填写全限定类名,如:org.springblade.demo.MapReduceProcessorDemo',
|
||||
prop: 'processorInfo',
|
||||
type: 'input',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入处理器参数',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '任务参数',
|
||||
labelTip: '方法入参 TaskContext 对象的 json 字段',
|
||||
prop: 'jobParams',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
},
|
||||
{
|
||||
label: '任务描述',
|
||||
prop: 'jobDescription',
|
||||
type: 'textarea',
|
||||
minRows: 3,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '高级配置',
|
||||
prop: 'templateSetting',
|
||||
icon: 'el-icon-copy-document',
|
||||
column: [
|
||||
{
|
||||
label: '最大实例数',
|
||||
labelTip:
|
||||
'该任务同时执行的数量(任务和实例就像是类和对象的关系,任务被调度执行后被称为实例)',
|
||||
prop: 'maxInstanceNum',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '单机线程并发数',
|
||||
labelTip: '该实例执行过程中每个 Worker 使用的线程数量',
|
||||
prop: 'concurrency',
|
||||
type: 'number',
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
label: '任务实例运行时间限制',
|
||||
labelTip: '0 代表无任何限制,超时会被打断并判定为执行失败',
|
||||
prop: 'instanceTimeLimit',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '任务实例重试次数',
|
||||
labelTip: '任务实例重试次数,整个任务失败时重试,代价大,不推荐使用',
|
||||
prop: 'instanceRetryNum',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '任务作业重试次数',
|
||||
labelTip: 'Task 重试次数,每个子 Task 失败后单独重试,代价小,推荐使用',
|
||||
prop: 'taskRetryNum',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '最低CPU核心',
|
||||
labelTip:
|
||||
'最小可用 CPU 核心数,CPU 可用核心数小于该值的 Worker 将不会执行该任务,0 代表无任何限制',
|
||||
prop: 'minCpuCores',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '最低内存(GB)',
|
||||
labelTip: '可用内存小于该值的Worker 将不会执行该任务,0 代表无任何限制',
|
||||
prop: 'minMemorySpace',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '最低磁盘空间(GB)',
|
||||
labelTip: '可用磁盘空间小于该值的Worker 将不会执行该任务,0 代表无任何限制',
|
||||
prop: 'minDiskSpace',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '执行机器地址',
|
||||
labelTip: '设置该参数后只有列表中的机器允许执行该任务,空代表不指定机器',
|
||||
prop: 'designatedWorkers',
|
||||
type: 'input',
|
||||
},
|
||||
{
|
||||
label: '最大执行机器数量',
|
||||
labelTip: '限定调动执行的机器数量,0代表无限制',
|
||||
prop: 'maxWorkerCount',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '其他配置',
|
||||
prop: 'codingSetting',
|
||||
icon: 'el-icon-printer',
|
||||
column: [
|
||||
{
|
||||
label: '报警人员ID列表',
|
||||
labelTip: '接收报警的用户ID列表',
|
||||
prop: 'notifyUserIds',
|
||||
type: 'input',
|
||||
},
|
||||
{
|
||||
label: '错误阈值',
|
||||
labelTip: '错误阈值,0代表不限制',
|
||||
prop: 'alertThreshold',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '统计窗口(s)',
|
||||
labelTip: '统计的窗口长度(s),0代表不限制',
|
||||
prop: 'statisticWindowLen',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '沉默窗口(s)',
|
||||
labelTip: '沉默时间窗口(s),0代表不限制',
|
||||
prop: 'silenceWindowLen',
|
||||
type: 'number',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '日志配置',
|
||||
labelTip: '日志配置',
|
||||
prop: 'logType',
|
||||
type: 'select',
|
||||
value: 1,
|
||||
dicData: logTypeDic,
|
||||
},
|
||||
{
|
||||
label: '日志级别',
|
||||
labelTip: '日志级别',
|
||||
prop: 'logLevel',
|
||||
type: 'select',
|
||||
value: 2,
|
||||
dicData: logLevelDic,
|
||||
},
|
||||
{
|
||||
label: '扩展字段',
|
||||
labelTip: '供开发者使用,用于功能扩展,powerjob 自身不会使用该字段',
|
||||
prop: 'extra',
|
||||
type: 'textarea',
|
||||
minRows: 3,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
78
src/option/job/jobserver.js
Normal file
78
src/option/job/jobserver.js
Normal file
@@ -0,0 +1,78 @@
|
||||
export default {
|
||||
height: 'auto',
|
||||
calcHeight: 30,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
grid: true,
|
||||
labelWidth: 100,
|
||||
menuWidth: 350,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '服务名称',
|
||||
prop: 'jobServerName',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入服务名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '服务器地址',
|
||||
prop: 'jobServerUrl',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入服务器地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '应用名称',
|
||||
prop: 'jobAppName',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入应用名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '应用密码',
|
||||
prop: 'jobAppPassword',
|
||||
type: 'input',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入应用密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '任务备注',
|
||||
prop: 'jobRemark',
|
||||
type: 'textarea',
|
||||
minRows: 3,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
};
|
||||
210
src/option/system/dict.js
Normal file
210
src/option/system/dict.js
Normal file
@@ -0,0 +1,210 @@
|
||||
export const optionParent = {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 10,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
viewBtn: true,
|
||||
menuWidth: 250,
|
||||
dialogWidth: 880,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '字典编号',
|
||||
prop: 'code',
|
||||
search: true,
|
||||
slot: true,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典名称',
|
||||
prop: 'dictValue',
|
||||
search: true,
|
||||
align: 'center',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
align: 'right',
|
||||
width: 100,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '封存',
|
||||
prop: 'isSealed',
|
||||
type: 'switch',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
dicData: [
|
||||
{
|
||||
label: '否',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '是',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
value: 0,
|
||||
slot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择封存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典备注',
|
||||
prop: 'remark',
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const optionChild = {
|
||||
height: 'auto',
|
||||
calcHeight: 95,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 10,
|
||||
tree: true,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
viewBtn: true,
|
||||
menuWidth: 300,
|
||||
dialogWidth: 880,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '字典编号',
|
||||
prop: 'code',
|
||||
addDisabled: true,
|
||||
editDisabled: true,
|
||||
search: true,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典名称',
|
||||
prop: 'dictValue',
|
||||
search: true,
|
||||
align: 'center',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '上级字典',
|
||||
prop: 'parentId',
|
||||
type: 'tree',
|
||||
dicData: [],
|
||||
hide: true,
|
||||
props: {
|
||||
label: 'title',
|
||||
},
|
||||
addDisabled: true,
|
||||
editDisabled: true,
|
||||
rules: [
|
||||
{
|
||||
required: false,
|
||||
message: '请选择上级字典',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典键值',
|
||||
prop: 'dictKey',
|
||||
width: 85,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典键值',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
align: 'right',
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '封存',
|
||||
prop: 'isSealed',
|
||||
type: 'switch',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
dicData: [
|
||||
{
|
||||
label: '否',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '是',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
value: 0,
|
||||
slot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择封存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典备注',
|
||||
prop: 'remark',
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
211
src/option/system/dictbiz.js
Normal file
211
src/option/system/dictbiz.js
Normal file
@@ -0,0 +1,211 @@
|
||||
export const optionParent = {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 10,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
viewBtn: true,
|
||||
menuWidth: 250,
|
||||
dialogWidth: 880,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '字典编号',
|
||||
prop: 'code',
|
||||
search: true,
|
||||
slot: true,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典名称',
|
||||
prop: 'dictValue',
|
||||
search: true,
|
||||
align: 'center',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
align: 'right',
|
||||
width: 100,
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '封存',
|
||||
prop: 'isSealed',
|
||||
type: 'switch',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
dicData: [
|
||||
{
|
||||
label: '否',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '是',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
value: 0,
|
||||
slot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择封存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典备注',
|
||||
prop: 'remark',
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const optionChild = {
|
||||
height: 'auto',
|
||||
calcHeight: 95,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 10,
|
||||
tree: true,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
viewBtn: true,
|
||||
menuWidth: 300,
|
||||
dialogWidth: 880,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '字典编号',
|
||||
prop: 'code',
|
||||
addDisabled: true,
|
||||
editDisabled: true,
|
||||
search: true,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典名称',
|
||||
prop: 'dictValue',
|
||||
search: true,
|
||||
align: 'center',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '上级字典',
|
||||
prop: 'parentId',
|
||||
type: 'tree',
|
||||
dicData: [],
|
||||
hide: true,
|
||||
props: {
|
||||
label: 'title',
|
||||
},
|
||||
addDisabled: true,
|
||||
editDisabled: true,
|
||||
rules: [
|
||||
{
|
||||
required: false,
|
||||
message: '请选择上级字典',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典键值',
|
||||
prop: 'dictKey',
|
||||
width: 85,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典键值',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
align: 'right',
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入字典排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '封存',
|
||||
prop: 'isSealed',
|
||||
type: 'switch',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
dicData: [
|
||||
{
|
||||
label: '否',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '是',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
value: 0,
|
||||
slot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择封存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '字典备注',
|
||||
prop: 'remark',
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
77
src/option/user/info.js
Normal file
77
src/option/user/info.js
Normal file
@@ -0,0 +1,77 @@
|
||||
export default {
|
||||
tabs: true,
|
||||
tabsActive: 1,
|
||||
group: [
|
||||
{
|
||||
label: '个人信息',
|
||||
prop: 'info',
|
||||
column: [
|
||||
{
|
||||
label: '头像',
|
||||
type: 'upload',
|
||||
listType: 'picture-img',
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
url: 'link',
|
||||
},
|
||||
action: '/blade-resource/oss/endpoint/put-file',
|
||||
tip: '只能上传jpg/png用户头像,且不超过500kb',
|
||||
span: 12,
|
||||
row: true,
|
||||
prop: 'avatar',
|
||||
},
|
||||
{
|
||||
label: '姓名',
|
||||
span: 12,
|
||||
row: true,
|
||||
prop: 'realName',
|
||||
},
|
||||
{
|
||||
label: '用户名',
|
||||
span: 12,
|
||||
row: true,
|
||||
prop: 'name',
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
span: 12,
|
||||
row: true,
|
||||
prop: 'phone',
|
||||
},
|
||||
{
|
||||
label: '邮箱',
|
||||
prop: 'email',
|
||||
span: 12,
|
||||
row: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '修改密码',
|
||||
prop: 'password',
|
||||
column: [
|
||||
{
|
||||
label: '原密码',
|
||||
span: 12,
|
||||
row: true,
|
||||
type: 'password',
|
||||
prop: 'oldPassword',
|
||||
},
|
||||
{
|
||||
label: '新密码',
|
||||
span: 12,
|
||||
row: true,
|
||||
type: 'password',
|
||||
prop: 'newPassword',
|
||||
},
|
||||
{
|
||||
label: '确认密码',
|
||||
span: 12,
|
||||
row: true,
|
||||
type: 'password',
|
||||
prop: 'newPassword1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
105
src/page/index/index.vue
Normal file
105
src/page/index/index.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="avue-contail" :class="{ 'avue--collapse': isCollapse }">
|
||||
<div class="avue-layout" :class="{ 'avue-layout--horizontal': isHorizontal }">
|
||||
<div class="avue-sidebar" v-show="validSidebar">
|
||||
<!-- 左侧导航栏 -->
|
||||
<logo />
|
||||
<sidebar />
|
||||
</div>
|
||||
<div class="avue-main">
|
||||
<!-- 顶部导航栏 -->
|
||||
<top ref="top" />
|
||||
<!-- 顶部标签卡 -->
|
||||
<tags />
|
||||
<search class="avue-view" v-show="isSearch"></search>
|
||||
<!-- 主体视图层 -->
|
||||
<div id="avue-view" v-show="!isSearch" v-if="isRefresh">
|
||||
<router-view #="{ Component }">
|
||||
<keep-alive :include="$store.getters.tagsKeep">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <wechat></wechat> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import index from '@/mixins/index';
|
||||
import wechat from './wechat.vue';
|
||||
//import { validatenull } from 'utils/validate';
|
||||
import { mapGetters } from 'vuex';
|
||||
import tags from './tags.vue';
|
||||
import search from './search.vue';
|
||||
import logo from './logo.vue';
|
||||
import top from './top/index.vue';
|
||||
import sidebar from './sidebar/index.vue';
|
||||
|
||||
export default {
|
||||
mixins: [index],
|
||||
components: {
|
||||
top,
|
||||
logo,
|
||||
tags,
|
||||
search,
|
||||
sidebar,
|
||||
wechat,
|
||||
},
|
||||
name: 'index',
|
||||
provide() {
|
||||
return {
|
||||
index: this,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isHorizontal',
|
||||
'isRefresh',
|
||||
'isLock',
|
||||
'isCollapse',
|
||||
'isSearch',
|
||||
'menu',
|
||||
'setting',
|
||||
]),
|
||||
validSidebar() {
|
||||
return !(
|
||||
(this.$route.meta || {}).menu === false || (this.$route.query || {}).menu === 'false'
|
||||
);
|
||||
},
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
//打开菜单
|
||||
openMenu(item = {}) {
|
||||
this.$store.dispatch('GetMenu', item.id).then(data => {
|
||||
if (data.length !== 0) {
|
||||
this.$router.$avueRouter.formatRoutes(data, true);
|
||||
}
|
||||
//当点击顶部菜单后默认打开第一个菜单
|
||||
/*if (!this.validatenull(item)) {
|
||||
let itemActive = {},
|
||||
childItemActive = 0;
|
||||
if (item.path) {
|
||||
itemActive = item;
|
||||
} else {
|
||||
if (this.menu[childItemActive].length === 0) {
|
||||
itemActive = this.menu[childItemActive];
|
||||
} else {
|
||||
itemActive = this.menu[childItemActive].children[childItemActive];
|
||||
}
|
||||
}
|
||||
this.$store.commit('SET_MENU_ID', item);
|
||||
this.$router.push({
|
||||
path: this.$router.$avueRouter.getPath({
|
||||
name: (itemActive.label || itemActive.name),
|
||||
src: itemActive.path
|
||||
}, itemActive.meta)
|
||||
});
|
||||
}*/
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
7
src/page/index/layout.vue
Normal file
7
src/page/index/layout.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<router-view #="{ Component }">
|
||||
<keep-alive :include="$store.getters.tagsKeep">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</template>
|
||||
30
src/page/index/logo.vue
Normal file
30
src/page/index/logo.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="avue-logo">
|
||||
<transition name="fade">
|
||||
<span v-if="getScreen(isCollapse)" class="avue-logo_subtitle" key="0">
|
||||
{{ website.logo }}
|
||||
</span>
|
||||
</transition>
|
||||
<transition-group name="fade">
|
||||
<template v-if="getScreen(!isCollapse)">
|
||||
<span class="avue-logo_title" key="1">{{ website.indexTitle }} </span>
|
||||
</template>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'logo',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
created() {},
|
||||
computed: {
|
||||
...mapGetters(['isCollapse']),
|
||||
},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
178
src/page/index/search.vue
Normal file
178
src/page/index/search.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<div class="avue-searchs" @click.self="handleEsc">
|
||||
<div class="avue-searchs__title">Avue菜单搜索</div>
|
||||
<div class="avue-searchs__content">
|
||||
<div class="avue-searchs__form">
|
||||
<el-input :placeholder="$t('search')" v-model="value" @keydown.esc="handleEsc">
|
||||
<template #append>
|
||||
<el-button icon="el-icon-search"></el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<p>
|
||||
<el-tag>你可以使用快捷键esc 关闭</el-tag>
|
||||
</p>
|
||||
</div>
|
||||
<div class="avue-searchs__list">
|
||||
<el-scrollbar class="avue-searchs__scrollbar">
|
||||
<div
|
||||
class="avue-searchs__item"
|
||||
v-for="(item, index) in menus"
|
||||
:key="index"
|
||||
@click="handleSelect(item)"
|
||||
>
|
||||
<i :class="[item[iconKey], 'avue-searchs__item-icon']"></i>
|
||||
<span class="avue-searchs__item-title">{{ item[labelKey] }}</span>
|
||||
<div class="avue-searchs__item-path">
|
||||
{{ item[pathKey] }}
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
menus: [],
|
||||
menuList: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getMenuList();
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.querySearch();
|
||||
},
|
||||
menu() {
|
||||
this.getMenuList();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
labelKey() {
|
||||
return this.website.menu.label;
|
||||
},
|
||||
pathKey() {
|
||||
return this.website.menu.path;
|
||||
},
|
||||
iconKey() {
|
||||
return this.website.menu.icon;
|
||||
},
|
||||
childrenKey() {
|
||||
return this.website.menu.children;
|
||||
},
|
||||
...mapGetters(['menu']),
|
||||
},
|
||||
methods: {
|
||||
handleEsc() {
|
||||
this.$store.commit('SET_IS_SEARCH', false);
|
||||
},
|
||||
getMenuList() {
|
||||
const findMenu = list => {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const ele = Object.assign({}, list[i]);
|
||||
if (this.validatenull(ele[this.childrenKey])) {
|
||||
this.menuList.push(ele);
|
||||
} else {
|
||||
findMenu(ele[this.childrenKey]);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.menuList = [];
|
||||
findMenu(this.menu);
|
||||
this.menus = this.menuList;
|
||||
},
|
||||
querySearch() {
|
||||
var restaurants = this.menuList;
|
||||
var queryString = this.value;
|
||||
this.menus = queryString ? this.menuList.filter(this.createFilter(queryString)) : restaurants;
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return restaurant => {
|
||||
return restaurant[this.labelKey].toLowerCase().indexOf(queryString.toLowerCase()) === 0;
|
||||
};
|
||||
},
|
||||
handleSelect(item) {
|
||||
this.value = '';
|
||||
this.$router.push({
|
||||
path: item[this.pathKey],
|
||||
query: item.query,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avue-searchs {
|
||||
padding-top: 50px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
z-index: 1024;
|
||||
|
||||
&__title {
|
||||
margin-bottom: 60px;
|
||||
text-align: center;
|
||||
font-size: 42px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
text-indent: 2px;
|
||||
}
|
||||
|
||||
&__form {
|
||||
margin: 0 auto 50px auto;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&__scrollbar {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
&__list {
|
||||
box-sizing: border-box;
|
||||
padding: 20px 30px;
|
||||
margin: 0 auto;
|
||||
width: 70%;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ebeef5;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
color: #303133;
|
||||
transition: 0.3s;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&__item {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px dashed #eee;
|
||||
|
||||
&-icon {
|
||||
margin-right: 5px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&-path {
|
||||
line-height: 30px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
173
src/page/index/setting.vue
Normal file
173
src/page/index/setting.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<el-button
|
||||
@click="show = true"
|
||||
class="setting-icon"
|
||||
type="primary"
|
||||
icon="el-icon-setting"
|
||||
circle
|
||||
></el-button>
|
||||
<el-drawer append-to-body :with-header="false" v-model="show" size="30%">
|
||||
<div class="setting">
|
||||
<h5>导航模式</h5>
|
||||
<div class="setting-checkbox">
|
||||
<el-tooltip class="item" effect="dark" content="侧边菜单布局" placement="top">
|
||||
<div
|
||||
@click="setting.sidebar = 'vertical'"
|
||||
class="setting-checkbox-item setting-checkbox-item--side"
|
||||
></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="顶部菜单布局" placement="top">
|
||||
<div
|
||||
@click="setting.sidebar = 'horizontal'"
|
||||
class="setting-checkbox-item setting-checkbox-item--top"
|
||||
></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<h5>页面布局</h5>
|
||||
<div class="setting-checkbox">
|
||||
<div class="setting-item" v-for="(item, index) in list1" :key="index">
|
||||
{{ item.label }}:
|
||||
<el-switch v-model="setting[item.value]"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<h5>功能调试</h5>
|
||||
<div class="setting-checkbox">
|
||||
<div class="setting-item" v-for="(item, index) in list2" :key="index">
|
||||
{{ item.label }}:
|
||||
<el-switch v-model="setting[item.value]"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
list1: [
|
||||
{
|
||||
label: '导航标签',
|
||||
value: 'tag',
|
||||
},
|
||||
{
|
||||
label: '菜单折叠',
|
||||
value: 'collapse',
|
||||
},
|
||||
{
|
||||
label: '菜单搜索',
|
||||
value: 'search',
|
||||
},
|
||||
{
|
||||
label: '屏幕全屏',
|
||||
value: 'fullscren',
|
||||
},
|
||||
{
|
||||
label: '主题选择',
|
||||
value: 'theme',
|
||||
},
|
||||
{
|
||||
label: '顶部菜单',
|
||||
value: 'menu',
|
||||
},
|
||||
],
|
||||
list2: [
|
||||
{
|
||||
label: '日志调试',
|
||||
value: 'debug',
|
||||
},
|
||||
{
|
||||
label: '屏幕锁定',
|
||||
value: 'lock',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isHorizontal', 'setting']),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.setting {
|
||||
&-icon {
|
||||
color: #666;
|
||||
position: fixed;
|
||||
bottom: 200px;
|
||||
right: 20px;
|
||||
z-index: 2048;
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&-checkbox {
|
||||
&--check {
|
||||
position: absolute;
|
||||
color: #409eff;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 44px;
|
||||
height: 36px;
|
||||
margin-right: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #f0f2f5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2.5px 0 rgba(0, 0, 0, 0.18);
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #fff;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&--side {
|
||||
&:before {
|
||||
z-index: 1;
|
||||
background-color: #001529;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&:after {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&--top {
|
||||
&:after {
|
||||
background-color: #001529;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
41
src/page/index/sidebar/index.vue
Normal file
41
src/page/index/sidebar/index.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<el-scrollbar class="avue-menu">
|
||||
<div v-if="menu && menu.length == 0 && !isHorizontal" class="avue-sidebar--tip">
|
||||
{{ $t('menuTip') }}
|
||||
</div>
|
||||
<el-menu
|
||||
unique-opened
|
||||
:default-active="activeMenu"
|
||||
:mode="setting.sidebar"
|
||||
:collapse="getScreen(isCollapse)"
|
||||
>
|
||||
<sidebar-item :menu="menu"></sidebar-item>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import sidebarItem from './sidebarItem.vue';
|
||||
|
||||
export default {
|
||||
name: 'sidebar',
|
||||
components: { sidebarItem },
|
||||
inject: ['index'],
|
||||
created() {
|
||||
this.index.openMenu();
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isHorizontal', 'setting', 'menu', 'tag', 'isCollapse', 'menuId']),
|
||||
activeMenu() {
|
||||
const route = this.$route;
|
||||
const { meta, path } = route;
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu;
|
||||
}
|
||||
return path;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
92
src/page/index/sidebar/sidebarItem.vue
Normal file
92
src/page/index/sidebar/sidebarItem.vue
Normal file
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<template v-for="item in menu">
|
||||
<el-menu-item
|
||||
v-if="validatenull(item[childrenKey]) && validRoles(item)"
|
||||
:index="getPath(item)"
|
||||
@click="open(item)"
|
||||
:key="item[labelKey]"
|
||||
>
|
||||
<i :class="item[iconKey]"></i>
|
||||
<template #title>
|
||||
<span :alt="item[pathKey]">{{ getTitle(item) }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<el-sub-menu
|
||||
v-else-if="!validatenull(item[childrenKey]) && validRoles(item)"
|
||||
:index="getPath(item)"
|
||||
:key="item[labelKey]"
|
||||
>
|
||||
<template #title>
|
||||
<i :class="item[iconKey]"></i>
|
||||
<span>{{ getTitle(item) }}</span>
|
||||
</template>
|
||||
<template v-for="(child, cindex) in item[childrenKey]" :key="child[labelKey]">
|
||||
<el-menu-item
|
||||
:index="getPath(child)"
|
||||
@click="open(child)"
|
||||
v-if="validatenull(child[childrenKey])"
|
||||
>
|
||||
<i :class="child[iconKey]"></i>
|
||||
<template #title>
|
||||
<span>{{ getTitle(child) }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<sidebar-item v-else :menu="[child]" :key="cindex"></sidebar-item>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { validatenull } from 'utils/validate';
|
||||
import website from '@/config/website';
|
||||
|
||||
export default {
|
||||
name: 'sidebarItem',
|
||||
data() {
|
||||
return {
|
||||
props: website.menu,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
menu: Array,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles']),
|
||||
labelKey() {
|
||||
return this.props.label;
|
||||
},
|
||||
pathKey() {
|
||||
return this.props.path;
|
||||
},
|
||||
queryKey() {
|
||||
return this.props.query;
|
||||
},
|
||||
iconKey() {
|
||||
return this.props.icon;
|
||||
},
|
||||
childrenKey() {
|
||||
return this.props.children;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
validatenull,
|
||||
getPath(item) {
|
||||
return item[this.pathKey];
|
||||
},
|
||||
getTitle(item) {
|
||||
return this.$router.$avueRouter.generateTitle(item, this.props);
|
||||
},
|
||||
validRoles(item) {
|
||||
item.meta = item.meta || {};
|
||||
return item.meta.roles ? item.meta.roles.includes(this.roles) : true;
|
||||
},
|
||||
open(item) {
|
||||
this.$router.push({
|
||||
path: item[this.pathKey],
|
||||
query: item[this.queryKey],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
188
src/page/index/tags.vue
Normal file
188
src/page/index/tags.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<div class="avue-tags" v-if="setting.tag" @click="contextmenuFlag = false">
|
||||
<!-- tag盒子 -->
|
||||
<div
|
||||
v-if="contextmenuFlag"
|
||||
class="avue-tags__contentmenu"
|
||||
:style="{ left: contentmenuX + 'px', top: contentmenuY + 'px' }"
|
||||
>
|
||||
<div class="item" @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</div>
|
||||
<div class="item" @click="closeAllTags">{{ $t('tagsView.closeAll') }}</div>
|
||||
<div class="item" @click="clearCacheTags">{{ $t('tagsView.clearCache') }}</div>
|
||||
</div>
|
||||
<div class="avue-tags__box">
|
||||
<el-tabs
|
||||
v-model="active"
|
||||
type="card"
|
||||
@contextmenu="handleContextmenu"
|
||||
:closable="tagLen !== 1"
|
||||
@tab-click="openTag"
|
||||
@edit="menuTag"
|
||||
>
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in tagList"
|
||||
:key="index"
|
||||
:label="generateTitle(item)"
|
||||
:name="item.fullPath"
|
||||
>
|
||||
<template #label>
|
||||
<span>
|
||||
{{ generateTitle(item) }}
|
||||
<i
|
||||
class="el-icon-refresh"
|
||||
:class="{ turn: refresh }"
|
||||
@click="handleRefresh"
|
||||
v-if="active === item.fullPath"
|
||||
></i>
|
||||
</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-dropdown class="avue-tags__menu">
|
||||
<el-button type="primary">
|
||||
{{ $t('tagsView.menu') }}
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openSearch">{{ $t('tagsView.search') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="closeOthersTags"
|
||||
>{{ $t('tagsView.closeOthers') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="closeAllTags">{{ $t('tagsView.closeAll') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="clearCacheTags"
|
||||
>{{ $t('tagsView.clearCache') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { clearCache } from '@/api/user';
|
||||
|
||||
export default {
|
||||
name: 'tags',
|
||||
data() {
|
||||
return {
|
||||
refresh: false,
|
||||
active: '',
|
||||
contentmenuX: '',
|
||||
contentmenuY: '',
|
||||
contextmenuFlag: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
tag: {
|
||||
handler(val) {
|
||||
this.active = val.fullPath;
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
contextmenuFlag() {
|
||||
window.addEventListener('mousedown', this.watchContextmenu);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['tagWel', 'tagList', 'tag', 'setting']),
|
||||
tagLen() {
|
||||
return this.tagList.length || 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openSearch() {
|
||||
this.$store.commit('SET_IS_SEARCH', true);
|
||||
},
|
||||
handleRefresh() {
|
||||
this.refresh = true;
|
||||
this.$store.commit('SET_IS_REFRESH', false);
|
||||
setTimeout(() => {
|
||||
this.$store.commit('SET_IS_REFRESH', true);
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
this.refresh = false;
|
||||
}, 500);
|
||||
},
|
||||
generateTitle(item) {
|
||||
return this.$router.$avueRouter.generateTitle({
|
||||
...item,
|
||||
...{
|
||||
label: item.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
watchContextmenu(event) {
|
||||
if (!this.$el.contains(event.target) || event.button !== 0) {
|
||||
this.contextmenuFlag = false;
|
||||
}
|
||||
window.removeEventListener('mousedown', this.watchContextmenu);
|
||||
},
|
||||
handleContextmenu(event) {
|
||||
let target = event.target;
|
||||
let flag = false;
|
||||
if (target.className.indexOf('el-tabs__item') > -1) flag = true;
|
||||
else if (target.parentNode.className.indexOf('el-tabs__item') > -1) {
|
||||
target = target.parentNode;
|
||||
flag = true;
|
||||
}
|
||||
if (flag) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.contentmenuX = event.clientX;
|
||||
this.contentmenuY = event.clientY;
|
||||
this.tagName = target.getAttribute('aria-controls').slice(5);
|
||||
this.contextmenuFlag = true;
|
||||
}
|
||||
},
|
||||
menuTag(value, action) {
|
||||
if (action === 'remove') {
|
||||
let { tag, key } = this.findTag(value);
|
||||
this.$store.commit('DEL_TAG', tag);
|
||||
if (tag.fullPath === this.tag.fullPath) {
|
||||
tag = this.tagList[key - 1];
|
||||
this.$router.push({
|
||||
path: tag.path,
|
||||
query: tag.query,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
openTag(item) {
|
||||
let value = item.props.name;
|
||||
let { tag } = this.findTag(value);
|
||||
this.$router.push({
|
||||
path: tag.path,
|
||||
query: tag.query,
|
||||
});
|
||||
},
|
||||
findTag(fullPath) {
|
||||
let tag = this.tagList.find(item => item.fullPath === fullPath);
|
||||
let key = this.tagList.findIndex(item => item.fullPath === fullPath);
|
||||
return { tag, key };
|
||||
},
|
||||
closeOthersTags() {
|
||||
this.contextmenuFlag = false;
|
||||
this.$store.commit('DEL_TAG_OTHER');
|
||||
},
|
||||
closeAllTags() {
|
||||
this.contextmenuFlag = false;
|
||||
this.$store.commit('DEL_ALL_TAG');
|
||||
this.$router.push(this.tagWel);
|
||||
},
|
||||
clearCacheTags() {
|
||||
this.$confirm('是否需要清除缓存?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
clearCache().then(() => {
|
||||
this.contextmenuFlag = false;
|
||||
this.$message.success('清除完毕');
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
120
src/page/index/top/index.vue
Normal file
120
src/page/index/top/index.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="avue-top">
|
||||
<div class="top-bar__left">
|
||||
<div
|
||||
class="avue-breadcrumb"
|
||||
:class="[{ 'avue-breadcrumb--active': isCollapse }]"
|
||||
v-if="setting.collapse && !isHorizontal"
|
||||
>
|
||||
<i class="icon-navicon" @click="setCollapse"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="top-bar__title">
|
||||
<top-menu ref="topMenu" v-if="setting.menu"></top-menu>
|
||||
<top-search class="top-bar__item" v-if="setting.search"></top-search>
|
||||
</div> -->
|
||||
<div class="top-bar__right">
|
||||
<!-- <div v-if="setting.lock" class="top-bar__item">
|
||||
<top-lock></top-lock>
|
||||
</div> -->
|
||||
<!-- <div v-if="setting.theme" class="top-bar__item">
|
||||
<top-theme></top-theme>
|
||||
</div> -->
|
||||
<!-- <div class="top-bar__item">
|
||||
<top-lang></top-lang>
|
||||
</div> -->
|
||||
<div class="top-bar__item" v-if="setting.fullscren">
|
||||
<top-full></top-full>
|
||||
</div>
|
||||
<!-- <div class="top-bar__item" v-if="setting.debug">
|
||||
<top-logs></top-logs>
|
||||
</div> -->
|
||||
<div class="top-user">
|
||||
<img class="top-bar__img" :src="userInfo.avatar" />
|
||||
<el-dropdown>
|
||||
<span class="el-dropdown-link">
|
||||
{{ userInfo.real_name }}
|
||||
<el-icon class="el-icon--right">
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<router-link to="/">{{ $t('navbar.dashboard') }}</router-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<router-link to="/info/index">{{ $t('navbar.userinfo') }}</router-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout" divided
|
||||
>{{ $t('navbar.logOut') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<top-setting></top-setting>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import topLock from './top-lock.vue';
|
||||
import topMenu from './top-menu.vue';
|
||||
import topSearch from './top-search.vue';
|
||||
import topTheme from './top-theme.vue';
|
||||
import topLogs from './top-logs.vue';
|
||||
import topLang from './top-lang.vue';
|
||||
import topFull from './top-full.vue';
|
||||
import topSetting from '../setting.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
topLock,
|
||||
topMenu,
|
||||
topSearch,
|
||||
topTheme,
|
||||
topLogs,
|
||||
topLang,
|
||||
topFull,
|
||||
topSetting,
|
||||
},
|
||||
name: 'top',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
filters: {},
|
||||
created() {},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'setting',
|
||||
'userInfo',
|
||||
'tagWel',
|
||||
'tagList',
|
||||
'isCollapse',
|
||||
'tag',
|
||||
'logsLen',
|
||||
'logsFlag',
|
||||
'isHorizontal',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
setCollapse() {
|
||||
this.$store.commit('SET_COLLAPSE');
|
||||
},
|
||||
logout() {
|
||||
this.$confirm(this.$t('logoutTip'), this.$t('tip'), {
|
||||
confirmButtonText: this.$t('submitText'),
|
||||
cancelButtonText: this.$t('cancelText'),
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
this.$router.push({ path: '/login' });
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
24
src/page/index/top/top-full.vue
Normal file
24
src/page/index/top/top-full.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<i :class="isFullScren ? 'icon-tuichuquanping' : 'icon-quanping'" @click="handleScreen"></i>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { fullscreenToggel, listenfullscreen } from 'utils/util';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
...mapGetters(['isFullScren']),
|
||||
},
|
||||
mounted() {
|
||||
listenfullscreen(this.setScreen);
|
||||
},
|
||||
methods: {
|
||||
setScreen() {
|
||||
this.$store.commit('SET_FULLSCREN');
|
||||
},
|
||||
handleScreen() {
|
||||
fullscreenToggel();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
40
src/page/index/top/top-lang.vue
Normal file
40
src/page/index/top/top-lang.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<el-dropdown trigger="click" @command="handleSetLanguage">
|
||||
<i class="icon-zhongyingwen"></i>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :disabled="language === 'zh-cn'" command="zh-cn">中文</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="language === 'en'" command="en">English</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'top-lang',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
created() {},
|
||||
mounted() {},
|
||||
computed: {
|
||||
...mapGetters(['language', 'tag']),
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
handleSetLanguage(lang) {
|
||||
this.$i18n.locale = lang;
|
||||
this.$store.commit('SET_LANGUAGE', lang);
|
||||
let tag = this.tag;
|
||||
let title = this.$router.$avueRouter.generateTitle(tag);
|
||||
//根据当前的标签也获取label的值动态设置浏览器标题
|
||||
this.$router.$avueRouter.setTitle(title);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
67
src/page/index/top/top-lock.vue
Normal file
67
src/page/index/top/top-lock.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<span v-if="text" @click="handleLock">{{ text }}</span>
|
||||
<i v-else class="icon-suoping" @click="handleLock"></i>
|
||||
<el-dialog title="设置锁屏密码" v-model="box" width="30%" append-to-body>
|
||||
<el-form :model="form" ref="form" label-width="80px">
|
||||
<el-form-item
|
||||
label="锁屏密码"
|
||||
prop="passwd"
|
||||
:rules="[{ required: true, message: '锁屏密码不能为空' }]"
|
||||
>
|
||||
<el-input v-model="form.passwd" placeholder="请输入锁屏密码">
|
||||
<template #append>
|
||||
<el-button @click="handleSetLock" icon="el-icon-lock"></el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validatenull } from 'utils/validate';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'top-lock',
|
||||
data() {
|
||||
return {
|
||||
box: false,
|
||||
form: {
|
||||
passwd: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
mounted() {},
|
||||
computed: {
|
||||
...mapGetters(['lockPasswd']),
|
||||
},
|
||||
props: {
|
||||
text: String,
|
||||
},
|
||||
methods: {
|
||||
handleSetLock() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (valid) {
|
||||
this.$store.commit('SET_LOCK_PASSWD', this.form.passwd);
|
||||
this.handleLock();
|
||||
}
|
||||
});
|
||||
},
|
||||
handleLock() {
|
||||
if (validatenull(this.lockPasswd)) {
|
||||
this.box = true;
|
||||
return;
|
||||
}
|
||||
this.$store.commit('SET_LOCK');
|
||||
setTimeout(() => {
|
||||
this.$router.push({ path: '/lock' });
|
||||
}, 100);
|
||||
},
|
||||
},
|
||||
components: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
86
src/page/index/top/top-logs.vue
Normal file
86
src/page/index/top/top-logs.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<span @click="logsFlag ? '' : handleOpen()">
|
||||
<el-badge :value="logsFlag ? '' : logsLen" :max="99">
|
||||
<i class="icon-rizhi1"></i>
|
||||
</el-badge>
|
||||
<el-dialog title="日志" v-model="box" width="60%" append-to-body>
|
||||
<el-button type="primary" icon="el-icon-upload" @click="send">上传服务器</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" @click="clear">清空本地日志</el-button>
|
||||
<el-table :data="logsList">
|
||||
<el-table-column prop="type" label="类型" width="50px"> </el-table-column>
|
||||
<el-table-column prop="url" label="地址" show-overflow-tooltip width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="message" show-overflow-tooltip label="内容"> </el-table-column>
|
||||
<el-table-column prop="stack" show-overflow-tooltip label="错误堆栈"> </el-table-column>
|
||||
<el-table-column prop="time" label="时间"> </el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'top-logs',
|
||||
data() {
|
||||
return {
|
||||
box: false,
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
mounted() {},
|
||||
computed: {
|
||||
...mapGetters(['logsList', 'logsFlag', 'logsLen']),
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
handleOpen() {
|
||||
this.box = true;
|
||||
},
|
||||
send() {
|
||||
this.$confirm('确定上传本地日志到服务器?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
this.$store.dispatch('SendLogs').then(() => {
|
||||
this.box = false;
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '发送成功!',
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
clear() {
|
||||
this.$confirm('确定清空本地日志记录?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
this.$store.commit('CLEAR_LOGS');
|
||||
this.box = false;
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '清空成功!',
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.code {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
margin: 1em 0px;
|
||||
}
|
||||
</style>
|
||||
58
src/page/index/top/top-menu.vue
Normal file
58
src/page/index/top/top-menu.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<el-menu class="top-menu" :default-active="activeIndex" mode="horizontal" text-color="#333">
|
||||
<el-menu-item index="0" @click="openHome(itemHome)">
|
||||
<template #title>
|
||||
<i :class="itemHome.source" style="padding-right: 5px"></i>
|
||||
<span>{{ itemHome.name }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<template v-for="(item, index) in items" :key="index">
|
||||
<el-menu-item :index="item.id + ''" @click="openMenu(item)">
|
||||
<template #title>
|
||||
<i :class="item.source" style="padding-right: 5px"></i>
|
||||
<span>{{ item.name }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'top-menu',
|
||||
data() {
|
||||
return {
|
||||
itemHome: {
|
||||
name: '首页',
|
||||
source: 'iconfont iconicon_work',
|
||||
},
|
||||
activeIndex: '0',
|
||||
items: [],
|
||||
};
|
||||
},
|
||||
inject: ['index'],
|
||||
created() {
|
||||
this.getMenu();
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['tagCurrent', 'menu', 'tagWel']),
|
||||
},
|
||||
methods: {
|
||||
openMenu(item) {
|
||||
this.index.openMenu(item);
|
||||
},
|
||||
openHome(itemHome) {
|
||||
this.index.openMenu(itemHome);
|
||||
this.$router.push(this.tagWel);
|
||||
},
|
||||
getMenu() {
|
||||
this.$store.dispatch('GetTopMenu').then(res => {
|
||||
this.items = res;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
120
src/page/index/top/top-search.vue
Normal file
120
src/page/index/top/top-search.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<el-autocomplete
|
||||
class="top-search"
|
||||
popper-class="my-autocomplete"
|
||||
v-model="value"
|
||||
:fetch-suggestions="querySearch"
|
||||
:placeholder="$t('search')"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<template #="{ item }">
|
||||
<i :class="[item[iconKey], 'icon']"></i>
|
||||
<div class="name">{{ item[labelKey] }}</div>
|
||||
<div class="addr">{{ item[pathKey] }}</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
menuList: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getMenuList();
|
||||
},
|
||||
|
||||
watch: {
|
||||
menu() {
|
||||
this.getMenuList();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
labelKey() {
|
||||
return this.website.menu.label;
|
||||
},
|
||||
pathKey() {
|
||||
return this.website.menu.path;
|
||||
},
|
||||
iconKey() {
|
||||
return this.website.menu.icon;
|
||||
},
|
||||
childrenKey() {
|
||||
return this.website.menu.children;
|
||||
},
|
||||
...mapGetters(['menu']),
|
||||
},
|
||||
methods: {
|
||||
getMenuList() {
|
||||
const findMenu = list => {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const ele = Object.assign({}, list[i]);
|
||||
if (this.validatenull(ele[this.childrenKey])) {
|
||||
this.menuList.push(ele);
|
||||
} else {
|
||||
findMenu(ele[this.childrenKey]);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.menuList = [];
|
||||
findMenu(this.menu);
|
||||
},
|
||||
querySearch(queryString, cb) {
|
||||
var restaurants = this.menuList;
|
||||
var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
|
||||
// 调用 callback 返回建议列表的数据
|
||||
cb(results);
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return restaurant => {
|
||||
return restaurant[this.labelKey].toLowerCase().indexOf(queryString.toLowerCase()) === 0;
|
||||
};
|
||||
},
|
||||
handleSelect(item) {
|
||||
this.value = '';
|
||||
this.$router.push({
|
||||
path: item[this.pathKey],
|
||||
query: item.query,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.my-autocomplete {
|
||||
li {
|
||||
line-height: normal !important;
|
||||
padding: 7px !important;
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.name {
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.addr {
|
||||
padding-top: 5px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
color: #b4b4b4;
|
||||
}
|
||||
|
||||
.highlighted .addr {
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
115
src/page/index/top/top-theme.vue
Normal file
115
src/page/index/top/top-theme.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog title="选择" v-model="box" width="50%">
|
||||
<el-radio-group v-model="text" class="list">
|
||||
<el-row :span="24">
|
||||
<el-col v-for="(item, index) in list" :key="index" :md="4" :xs="12" :sm="4">
|
||||
<el-radio :label="item.value">{{ item.name }}</el-radio>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-radio-group>
|
||||
</el-dialog>
|
||||
|
||||
<span>
|
||||
<i class="icon-zhuti" @click="open"></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { setTheme } from 'utils/util';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
box: false,
|
||||
text: '',
|
||||
list: [
|
||||
{
|
||||
name: '默认主题',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: '白色主题',
|
||||
value: 'theme-white',
|
||||
},
|
||||
{
|
||||
name: '黑色主题',
|
||||
value: 'theme-dark',
|
||||
},
|
||||
{
|
||||
name: 'hey主题',
|
||||
value: 'theme-hey',
|
||||
},
|
||||
{
|
||||
name: '炫彩主题',
|
||||
value: 'theme-star',
|
||||
},
|
||||
{
|
||||
name: 'vip主题',
|
||||
value: 'theme-vip',
|
||||
},
|
||||
{
|
||||
name: '智能工厂主题',
|
||||
value: 'theme-bule',
|
||||
},
|
||||
{
|
||||
name: 'iview主题',
|
||||
value: 'theme-iview',
|
||||
},
|
||||
{
|
||||
name: 'cool主题',
|
||||
value: 'theme-cool',
|
||||
},
|
||||
{
|
||||
name: 'd2主题',
|
||||
value: 'theme-d2',
|
||||
},
|
||||
{
|
||||
name: 'lte主题',
|
||||
value: 'theme-lte',
|
||||
},
|
||||
{
|
||||
name: 'beautiful主题',
|
||||
value: 'theme-beautiful',
|
||||
},
|
||||
{
|
||||
name: 'Mac OS主题',
|
||||
value: 'mac-os',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
text: function (val) {
|
||||
this.$store.commit('SET_THEME_NAME', val);
|
||||
setTheme(val);
|
||||
if (this.$store.getters.isMacOs) {
|
||||
this.$router.push(this.tagWel);
|
||||
setTimeout(() => location.reload());
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['themeName', 'tagWel']),
|
||||
},
|
||||
mounted() {
|
||||
this.text = this.themeName;
|
||||
if (!this.text) {
|
||||
this.text = '';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.box = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
59
src/page/index/wechat.vue
Normal file
59
src/page/index/wechat.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
center
|
||||
:show-close="false"
|
||||
:close-on-press-escape="false"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
v-model="dialogVisible"
|
||||
title="人机识别"
|
||||
width="400px"
|
||||
>
|
||||
<center>
|
||||
<span>
|
||||
扫码下方二维码,回复<b>【验证码】</b><br />
|
||||
<span style="color: red">获得「验证码 + 交流群(一起摸🐟)」</span>
|
||||
</span>
|
||||
<br />
|
||||
<br />
|
||||
<img width="200" src="https://avuejs.com/images/icon/wechat.png" />
|
||||
<br />
|
||||
<br />
|
||||
<el-input v-model="value" placeholder="请输入验证码"></el-input>
|
||||
</center>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="submit">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
dialogVisible: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
if (window.localStorage.getItem('avue_lock')) {
|
||||
return;
|
||||
}
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if (this.value == '') {
|
||||
this.$message.error('验证码不能为空');
|
||||
return;
|
||||
} else if (this.value != 'avue') {
|
||||
this.$message.error('验证码不正确');
|
||||
return;
|
||||
}
|
||||
this.dialogVisible = false;
|
||||
window.localStorage.setItem('avue_lock', true);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
104
src/page/lock/index.vue
Normal file
104
src/page/lock/index.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="login-container" @keyup.enter="handleLogin">
|
||||
<div class="login-time">
|
||||
{{ time }}
|
||||
</div>
|
||||
<div class="login-weaper">
|
||||
<div class="login-left animate__animated animate__fadeInLeft">
|
||||
<img class="img" src="/img/logo.png" alt="" />
|
||||
<p class="title">{{ $t('login.info') }}</p>
|
||||
</div>
|
||||
<div class="login-border animate__animated animate__fadeInRight">
|
||||
<div class="login-main">
|
||||
<div class="lock-form animate__animated animate__bounceInDown">
|
||||
<div
|
||||
class="animate__animated"
|
||||
:class="{ shake: passwdError, animate__bounceOut: pass }"
|
||||
>
|
||||
<h3 style="color: #333">{{ userInfo.username }}</h3>
|
||||
<el-input
|
||||
placeholder="请输入登录密码"
|
||||
type="password"
|
||||
class="input-with-select animated"
|
||||
v-model="passwd"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #append>
|
||||
<i class="icon-bofangqi-suoping" @click="handleLogin"></i>
|
||||
|
||||
<i class="icon-tuichu" @click="handleLogout"></i>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'lock',
|
||||
data() {
|
||||
return {
|
||||
time: '',
|
||||
passwd: '',
|
||||
passwdError: false,
|
||||
pass: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getTime();
|
||||
setInterval(() => {
|
||||
this.getTime();
|
||||
}, 1000);
|
||||
},
|
||||
mounted() {},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'tag', 'lockPasswd']),
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
getTime() {
|
||||
this.time = this.$dayjs().format('YYYY年MM月DD日 HH:mm:ss');
|
||||
},
|
||||
handleLogout() {
|
||||
this.$confirm('是否退出系统, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
this.$router.push({ path: '/login' });
|
||||
});
|
||||
});
|
||||
},
|
||||
handleLogin() {
|
||||
if (this.passwd != this.lockPasswd) {
|
||||
this.passwd = '';
|
||||
this.$message({
|
||||
message: '解锁密码错误,请重新输入',
|
||||
type: 'error',
|
||||
});
|
||||
this.passwdError = true;
|
||||
setTimeout(() => {
|
||||
this.passwdError = false;
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
this.pass = true;
|
||||
setTimeout(() => {
|
||||
this.$store.commit('CLEAR_LOCK');
|
||||
this.$router.push({
|
||||
path: this.tag.path,
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
components: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
18
src/page/login/authredirect.vue
Normal file
18
src/page/login/authredirect.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'authredirect',
|
||||
created() {
|
||||
window.close();
|
||||
const params = this.$route.query;
|
||||
const state = params.state;
|
||||
const code = params.code;
|
||||
window.opener.location.href = `${window.location.origin}/#/login?state=${state}&code=${code}`;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
139
src/page/login/codelogin.vue
Normal file
139
src/page/login/codelogin.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<el-form
|
||||
class="login-form"
|
||||
status-icon
|
||||
:rules="loginRules"
|
||||
ref="loginForm"
|
||||
:model="loginForm"
|
||||
label-width="0"
|
||||
>
|
||||
<el-form-item prop="phone">
|
||||
<el-input
|
||||
@keyup.enter="handleLogin"
|
||||
v-model="loginForm.phone"
|
||||
auto-complete="off"
|
||||
:placeholder="$t('login.phone')"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="icon-shouji" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-input
|
||||
@keyup.enter="handleLogin"
|
||||
v-model="loginForm.code"
|
||||
auto-complete="off"
|
||||
:placeholder="$t('login.code')"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="icon-yanzhengma" style="margin-top: 6px" />
|
||||
</template>
|
||||
<template #append>
|
||||
<span @click="handleSend" class="msg-text" :class="[{ display: msgKey }]">{{
|
||||
msgText
|
||||
}}</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click.prevent="handleLogin" class="login-submit"
|
||||
>{{ $t('login.submit') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isvalidatemobile } from '@/utils/validate';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'codelogin',
|
||||
data() {
|
||||
const validatePhone = (rule, value, callback) => {
|
||||
if (isvalidatemobile(value)[0]) {
|
||||
callback(new Error(isvalidatemobile(value)[1]));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
const validateCode = (rule, value, callback) => {
|
||||
if (value.length !== 4) {
|
||||
callback(new Error('请输入4位数的验证码'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
msgText: '',
|
||||
msgTime: '',
|
||||
msgKey: false,
|
||||
loginForm: {
|
||||
phone: '',
|
||||
code: '',
|
||||
},
|
||||
loginRules: {
|
||||
phone: [{ required: true, trigger: 'blur', validator: validatePhone }],
|
||||
code: [{ required: true, trigger: 'blur', validator: validateCode }],
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.msgText = this.config.MSGINIT;
|
||||
this.msgTime = this.config.MSGTIME;
|
||||
},
|
||||
mounted() {},
|
||||
computed: {
|
||||
...mapGetters(['tagWel']),
|
||||
config() {
|
||||
return {
|
||||
MSGINIT: this.$t('login.msgText'),
|
||||
MSGSCUCCESS: this.$t('login.msgSuccess'),
|
||||
MSGTIME: 60,
|
||||
};
|
||||
},
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
handleSend() {
|
||||
if (this.msgKey) return;
|
||||
this.msgText = this.msgTime + this.config.MSGSCUCCESS;
|
||||
this.msgKey = true;
|
||||
const time = setInterval(() => {
|
||||
this.msgTime--;
|
||||
this.msgText = this.msgTime + this.config.MSGSCUCCESS;
|
||||
if (this.msgTime === 0) {
|
||||
this.msgTime = this.config.MSGTIME;
|
||||
this.msgText = this.config.MSGINIT;
|
||||
this.msgKey = false;
|
||||
clearInterval(time);
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.$store.dispatch('LoginByPhone', this.loginForm).then(() => {
|
||||
this.$router.push(this.tagWel);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.msg-text {
|
||||
display: block;
|
||||
width: 60px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.msg-text.display {
|
||||
color: #ccc;
|
||||
}
|
||||
</style>
|
||||
39
src/page/login/facelogin.vue
Normal file
39
src/page/login/facelogin.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<basic-video ref="video" :width="350"></basic-video>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import basicVideo from '@/components/basic-video/main.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
basicVideo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loginForm: {
|
||||
username: 'admin',
|
||||
password: '123456',
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
setTimeout(() => {
|
||||
this.handleLogin();
|
||||
}, 6000);
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['tagWel']),
|
||||
},
|
||||
methods: {
|
||||
handleLogin() {
|
||||
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
|
||||
this.$router.push(this.tagWel);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
375
src/page/login/index.vue
Normal file
375
src/page/login/index.vue
Normal file
@@ -0,0 +1,375 @@
|
||||
<template>
|
||||
<div class="login-container" ref="login" @keyup.enter="handleLogin">
|
||||
<div class="stars"></div>
|
||||
<div class="stars2"></div>
|
||||
<div class="stars3"></div>
|
||||
<div class="login-weaper animated bounceInDown">
|
||||
<div class="login-left">
|
||||
<div class="login-time">
|
||||
{{ time }}
|
||||
</div>
|
||||
<div class="login-left-content">
|
||||
<h1 class="title">智能设备管理系统</h1>
|
||||
<p class="subtitle">专业的设备管理解决方案</p>
|
||||
<div class="feature-box">
|
||||
<div class="feature-item">
|
||||
<span>设备实时监控</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<span>数据分析统计</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<span>智能预警</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<span>远程控制</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-border">
|
||||
<div class="login-main">
|
||||
<h4 class="login-title">
|
||||
登录 saber
|
||||
<top-lang></top-lang>
|
||||
</h4>
|
||||
<userLogin></userLogin>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import userLogin from './userlogin.vue';
|
||||
import codeLogin from './codelogin.vue';
|
||||
import thirdLogin from './thirdlogin.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { validatenull } from '@/utils/validate';
|
||||
import topLang from '@/page/index/top/top-lang.vue';
|
||||
import { getQueryString, getTopUrl } from '@/utils/util';
|
||||
import website from '@/config/website';
|
||||
|
||||
export default {
|
||||
name: 'login',
|
||||
components: {
|
||||
userLogin,
|
||||
codeLogin,
|
||||
thirdLogin,
|
||||
topLang,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
website: website,
|
||||
time: '',
|
||||
activeName: 'user',
|
||||
socialForm: {
|
||||
tenantId: '000000',
|
||||
source: '',
|
||||
code: '',
|
||||
state: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.handleLogin();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.handleLogin();
|
||||
this.getTime();
|
||||
},
|
||||
mounted() {},
|
||||
computed: {
|
||||
...mapGetters(['tagWel']),
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
getTime() {
|
||||
setInterval(() => {
|
||||
this.time = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
}, 1000);
|
||||
},
|
||||
handleLogin() {
|
||||
const topUrl = getTopUrl();
|
||||
const redirectUrl = '/oauth/redirect/';
|
||||
const ssoCode = '?code=';
|
||||
this.socialForm.source = getQueryString('source');
|
||||
this.socialForm.code = getQueryString('code');
|
||||
this.socialForm.state = getQueryString('state');
|
||||
if (validatenull(this.socialForm.source) && topUrl.includes(redirectUrl)) {
|
||||
let source = topUrl.split('?')[0];
|
||||
source = source.split(redirectUrl)[1];
|
||||
this.socialForm.source = source;
|
||||
}
|
||||
if (
|
||||
topUrl.includes(redirectUrl) &&
|
||||
!validatenull(this.socialForm.source) &&
|
||||
!validatenull(this.socialForm.code) &&
|
||||
!validatenull(this.socialForm.state)
|
||||
) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '第三方系统登录中,请稍后',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
});
|
||||
this.$store
|
||||
.dispatch('LoginBySocial', this.socialForm)
|
||||
.then(() => {
|
||||
window.location.href = topUrl.split(redirectUrl)[0];
|
||||
//加载工作流路由集
|
||||
this.loadFlowRoutes();
|
||||
this.$router.push(this.tagWel);
|
||||
loading.close();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.close();
|
||||
});
|
||||
} else if (
|
||||
!topUrl.includes(redirectUrl) &&
|
||||
!validatenull(this.socialForm.code) &&
|
||||
!validatenull(this.socialForm.state)
|
||||
) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '单点系统登录中,请稍后',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
});
|
||||
this.$store
|
||||
.dispatch('LoginBySso', this.socialForm)
|
||||
.then(() => {
|
||||
window.location.href = topUrl.split(ssoCode)[0];
|
||||
//加载工作流路由集
|
||||
this.loadFlowRoutes();
|
||||
this.$router.push(this.tagWel);
|
||||
loading.close();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
},
|
||||
loadFlowRoutes() {
|
||||
this.$store.dispatch('FlowRoutes').then(() => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.login-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@function multiple-box-shadow($n) {
|
||||
$value: '#{random(2000)}px #{random(2000)}px #FFF';
|
||||
@for $i from 2 through $n {
|
||||
$value: '#{$value} , #{random(2000)}px #{random(2000)}px #FFF';
|
||||
}
|
||||
@return unquote($value);
|
||||
}
|
||||
|
||||
$shadows-small: multiple-box-shadow(700);
|
||||
$shadows-medium: multiple-box-shadow(200);
|
||||
$shadows-big: multiple-box-shadow(100);
|
||||
|
||||
.stars {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
background: transparent;
|
||||
box-shadow: $shadows-small;
|
||||
animation: animateStars 50s linear infinite;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 2000px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
background: transparent;
|
||||
box-shadow: $shadows-small;
|
||||
}
|
||||
}
|
||||
|
||||
.stars2 {
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
background: transparent;
|
||||
box-shadow: $shadows-medium;
|
||||
animation: animateStars 100s linear infinite;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 2000px;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
background: transparent;
|
||||
box-shadow: $shadows-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.stars3 {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
background: transparent;
|
||||
box-shadow: $shadows-big;
|
||||
animation: animateStars 150s linear infinite;
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 2000px;
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
background: transparent;
|
||||
box-shadow: $shadows-big;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animateStars {
|
||||
from {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
to {
|
||||
transform: translateY(-2000px);
|
||||
}
|
||||
}
|
||||
|
||||
.login-weaper {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.login-left {
|
||||
width: 50%;
|
||||
background: linear-gradient(135deg, rgba(27, 39, 53, 0.95) 0%, rgba(9, 10, 15, 0.95) 100%);
|
||||
padding: 40px;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: radial-gradient(circle at 50% 50%, rgba(33, 147, 176, 0.3) 0%, transparent 50%),
|
||||
radial-gradient(circle at 20% 80%, rgba(40, 60, 190, 0.3) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.login-time {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.login-left-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 16px;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.feature-box {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 15px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 15px 10px;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(5px);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
|
||||
&::before {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-border {
|
||||
width: 50%;
|
||||
padding: 40px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-main {
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
71
src/page/login/thirdlogin.vue
Normal file
71
src/page/login/thirdlogin.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="social-container">
|
||||
<div @click="handleClick('github')">
|
||||
<span class="container" :style="{ backgroundColor: '#61676D' }">
|
||||
<i icon-class="github" class="iconfont icongithub"></i>
|
||||
</span>
|
||||
<p class="title">{{ $t('login.github') }}</p>
|
||||
</div>
|
||||
<div @click="handleClick('gitee')">
|
||||
<span class="container" :style="{ backgroundColor: '#c35152' }">
|
||||
<i icon-class="gitee" class="iconfont icongitee2"></i>
|
||||
</span>
|
||||
<p class="title">{{ $t('login.gitee') }}</p>
|
||||
</div>
|
||||
<div @click="handleClick('wechat_open')">
|
||||
<span class="container" :style="{ backgroundColor: '#8dc349' }">
|
||||
<i icon-class="wechat" class="iconfont icon-weixin" />
|
||||
</span>
|
||||
<p class="title">{{ $t('login.wechat') }}</p>
|
||||
</div>
|
||||
<div @click="handleClick('qq')">
|
||||
<span class="container" :style="{ backgroundColor: '#6ba2d6' }">
|
||||
<i icon-class="qq" class="iconfont icon-qq" />
|
||||
</span>
|
||||
<p class="title">{{ $t('login.qq') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import website from '@/config/website';
|
||||
|
||||
export default {
|
||||
name: 'thirdLogin',
|
||||
methods: {
|
||||
handleClick(source) {
|
||||
window.location.href = `${website.authUrl}/${source}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.social-container {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
|
||||
.iconfont {
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.container {
|
||||
$height: 50px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: $height;
|
||||
height: $height;
|
||||
line-height: $height;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
415
src/page/login/userlogin.vue
Normal file
415
src/page/login/userlogin.vue
Normal file
@@ -0,0 +1,415 @@
|
||||
<template>
|
||||
<el-form
|
||||
class="login-form"
|
||||
status-icon
|
||||
:rules="loginRules"
|
||||
ref="loginForm"
|
||||
:model="loginForm"
|
||||
label-width="0"
|
||||
>
|
||||
<el-form-item v-if="tenantMode" prop="tenantId">
|
||||
<el-input
|
||||
@keyup.enter="handleLogin"
|
||||
v-model="loginForm.tenantId"
|
||||
auto-complete="off"
|
||||
:placeholder="$t('login.tenantId')"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="icon-quanxian" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
@keyup.enter="handleLogin"
|
||||
v-model="loginForm.username"
|
||||
auto-complete="off"
|
||||
:placeholder="$t('login.username')"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="icon-yonghu" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
@keyup.enter="handleLogin"
|
||||
:type="passwordType"
|
||||
v-model="loginForm.password"
|
||||
auto-complete="off"
|
||||
:placeholder="$t('login.password')"
|
||||
>
|
||||
<template #suffix>
|
||||
<i class="el-icon-view el-input__icon" @click="showPassword" />
|
||||
</template>
|
||||
<template #prefix>
|
||||
<i class="icon-mima" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="this.website.captchaMode" prop="code">
|
||||
<el-row :span="24">
|
||||
<el-col :span="16">
|
||||
<el-input
|
||||
@keyup.enter="handleLogin"
|
||||
v-model="loginForm.code"
|
||||
auto-complete="off"
|
||||
:placeholder="$t('login.code')"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="icon-yanzhengma" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="login-code">
|
||||
<img :src="loginForm.image" class="login-code-img" @click="refreshCode" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click.prevent="handleLogin" class="login-submit"
|
||||
>{{ $t('login.submit') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-dialog title="用户信息选择" append-to-body v-model="userBox" width="350px">
|
||||
<avue-form :option="userOption" v-model="userForm" @submit="submitLogin" />
|
||||
</el-dialog>
|
||||
<el-dialog title="用户信息注册" append-to-body v-model="registerBox" width="350px">
|
||||
<avue-form :option="registerOption" v-model="registerForm" @submit="submitRegister" />
|
||||
</el-dialog>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { info } from '@/api/system/tenant';
|
||||
import { getCaptcha } from '@/api/user';
|
||||
import { getTopUrl } from '@/utils/util';
|
||||
|
||||
export default {
|
||||
name: 'userlogin',
|
||||
data() {
|
||||
return {
|
||||
tenantMode: this.website.tenantMode,
|
||||
loginForm: {
|
||||
//租户ID
|
||||
tenantId: '000000',
|
||||
//部门ID
|
||||
deptId: '',
|
||||
//角色ID
|
||||
roleId: '',
|
||||
//用户名
|
||||
username: 'admin',
|
||||
//密码
|
||||
password: 'admin',
|
||||
//账号类型
|
||||
type: 'account',
|
||||
//验证码的值
|
||||
code: '',
|
||||
//验证码的索引
|
||||
key: '',
|
||||
//预加载白色背景
|
||||
image: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
|
||||
},
|
||||
loginRules: {
|
||||
tenantId: [{ required: false, message: '请输入租户ID', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 1, message: '密码长度最少为6位', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
passwordType: 'password',
|
||||
userBox: false,
|
||||
userForm: {
|
||||
deptId: '',
|
||||
roleId: '',
|
||||
},
|
||||
userOption: {
|
||||
labelWidth: 70,
|
||||
submitBtn: true,
|
||||
emptyBtn: false,
|
||||
submitText: '登录',
|
||||
column: [
|
||||
{
|
||||
label: '部门',
|
||||
prop: 'deptId',
|
||||
type: 'select',
|
||||
props: {
|
||||
label: 'deptName',
|
||||
value: 'id',
|
||||
},
|
||||
dicUrl: '/blade-system/dept/select',
|
||||
span: 24,
|
||||
display: false,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择部门',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '角色',
|
||||
prop: 'roleId',
|
||||
type: 'select',
|
||||
props: {
|
||||
label: 'roleName',
|
||||
value: 'id',
|
||||
},
|
||||
dicUrl: '/blade-system/role/select',
|
||||
span: 24,
|
||||
display: false,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择角色',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
registerBox: false,
|
||||
registerForm: {},
|
||||
registerOption: {
|
||||
labelWidth: 90,
|
||||
submitBtn: true,
|
||||
emptyBtn: false,
|
||||
submitText: '注册',
|
||||
column: [
|
||||
{
|
||||
label: '租户编号',
|
||||
prop: 'tenantId',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写租户编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '用户姓名',
|
||||
prop: 'name',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入用户姓名',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '用户账号',
|
||||
prop: 'account',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写用户账号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '手机',
|
||||
prop: 'phone',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写手机',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '邮箱',
|
||||
prop: 'email',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写邮箱',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '密码',
|
||||
prop: 'password',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '确认密码',
|
||||
prop: 'password2',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写确认密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getTenant();
|
||||
this.refreshCode();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {});
|
||||
},
|
||||
watch: {
|
||||
'loginForm.deptId'() {
|
||||
const column = this.findObject(this.userOption.column, 'deptId');
|
||||
if (this.loginForm.deptId.includes(',')) {
|
||||
column.dicUrl = `/blade-system/dept/select?deptId=${this.loginForm.deptId}`;
|
||||
column.display = true;
|
||||
} else {
|
||||
column.dicUrl = '';
|
||||
}
|
||||
},
|
||||
'loginForm.roleId'() {
|
||||
const column = this.findObject(this.userOption.column, 'roleId');
|
||||
if (this.loginForm.roleId.includes(',')) {
|
||||
column.dicUrl = `/blade-system/role/select?roleId=${this.loginForm.roleId}`;
|
||||
column.display = true;
|
||||
} else {
|
||||
column.dicUrl = '';
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['tagWel', 'userInfo']),
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
refreshCode() {
|
||||
if (this.website.captchaMode) {
|
||||
getCaptcha().then(res => {
|
||||
const data = res.data;
|
||||
this.loginForm.key = data.key;
|
||||
this.loginForm.image = data.image;
|
||||
});
|
||||
}
|
||||
},
|
||||
showPassword() {
|
||||
this.passwordType === '' ? (this.passwordType = 'password') : (this.passwordType = '');
|
||||
},
|
||||
submitLogin(form, done) {
|
||||
if (form.deptId !== '') {
|
||||
this.loginForm.deptId = form.deptId;
|
||||
}
|
||||
if (form.roleId !== '') {
|
||||
this.loginForm.roleId = form.roleId;
|
||||
}
|
||||
this.handleLogin();
|
||||
done();
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '登录中,请稍后',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
});
|
||||
this.$store
|
||||
.dispatch('LoginByUsername', this.loginForm)
|
||||
.then(() => {
|
||||
if (this.website.switchMode) {
|
||||
const deptId = this.userInfo.dept_id;
|
||||
const roleId = this.userInfo.role_id;
|
||||
if (deptId.includes(',') || roleId.includes(',')) {
|
||||
this.loginForm.deptId = deptId;
|
||||
this.loginForm.roleId = roleId;
|
||||
this.userBox = true;
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
loading.close();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
loading.close();
|
||||
//加载工作流路由集
|
||||
this.loadFlowRoutes();
|
||||
this.$router.push(this.tagWel);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
loading.close();
|
||||
this.refreshCode();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleRegister() {
|
||||
this.registerBox = true;
|
||||
},
|
||||
submitRegister(form, done) {
|
||||
if (form.password !== form.password2) {
|
||||
this.$message.warning('两次密码输入不一致');
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '注册中,请稍后',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
});
|
||||
this.$store
|
||||
.dispatch('RegisterUser', form)
|
||||
.then(() => {
|
||||
this.$alert('注册成功,请耐心等待管理员审核后分配权限', '注册成功', {
|
||||
confirmButtonText: '确定',
|
||||
callback: () => {
|
||||
this.$router.push(this.tagWel);
|
||||
},
|
||||
});
|
||||
this.registerBox = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
loading.close();
|
||||
done();
|
||||
},
|
||||
loadFlowRoutes() {
|
||||
this.$store.dispatch('FlowRoutes').then(() => {});
|
||||
},
|
||||
getTenant() {
|
||||
let domain = getTopUrl();
|
||||
// 临时指定域名,方便测试
|
||||
//domain = "https://bladex.cn";
|
||||
info(domain).then(res => {
|
||||
const data = res.data;
|
||||
if (data.success && data.data.tenantId) {
|
||||
this.tenantMode = false;
|
||||
this.loginForm.tenantId = data.data.tenantId;
|
||||
this.$parent.$refs.login.style.backgroundImage = `url(${data.data.backgroundUrl})`;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
58
src/permission.js
Normal file
58
src/permission.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import router from './router/';
|
||||
import store from './store';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import NProgress from 'nprogress'; // progress bar
|
||||
import 'nprogress/nprogress.css'; // progress bar style
|
||||
NProgress.configure({ showSpinner: false });
|
||||
const lockPage = '/lock'; //锁屏页
|
||||
router.beforeEach((to, from, next) => {
|
||||
const meta = to.meta || {};
|
||||
const isMenu = meta.menu === undefined ? to.query.menu : meta.menu;
|
||||
store.commit('SET_IS_MENU', isMenu === undefined);
|
||||
if (getToken()) {
|
||||
if (store.getters.isLock && to.path !== lockPage) {
|
||||
//如果系统激活锁屏,全部跳转到锁屏页
|
||||
next({ path: lockPage });
|
||||
} else if (to.path === '/login') {
|
||||
//如果登录成功访问登录页跳转到主页
|
||||
next({ path: '/' });
|
||||
} else {
|
||||
if (store.getters.token.length === 0) {
|
||||
store.dispatch('FedLogOut').then(() => {
|
||||
next({ path: '/login' });
|
||||
});
|
||||
} else {
|
||||
const meta = to.meta || {};
|
||||
const query = to.query || {};
|
||||
if (meta.target) {
|
||||
window.open(query.url.replace(/#/g, '&'));
|
||||
return;
|
||||
} else if (meta.isTab !== false) {
|
||||
store.commit('ADD_TAG', {
|
||||
name: query.name || to.name,
|
||||
path: to.path,
|
||||
fullPath: to.path,
|
||||
params: to.params,
|
||||
query: to.query,
|
||||
meta: meta,
|
||||
});
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//判断是否需要认证,没有登录访问去登录页
|
||||
if (meta.isAuth === false) {
|
||||
next();
|
||||
} else {
|
||||
next('/login');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.afterEach(to => {
|
||||
NProgress.done();
|
||||
let title = router.$avueRouter.generateTitle(to, { label: 'name' });
|
||||
router.$avueRouter.setTitle(title);
|
||||
store.commit('SET_IS_SEARCH', false);
|
||||
});
|
||||
162
src/router/avue-router.js
Normal file
162
src/router/avue-router.js
Normal file
@@ -0,0 +1,162 @@
|
||||
import website from '@/config/website';
|
||||
|
||||
const modules = import.meta.glob('../**/**/*.vue');
|
||||
|
||||
function isURL(s) {
|
||||
return /^http[s]?:\/\/.*/.test(s);
|
||||
}
|
||||
|
||||
let RouterPlugin = function () {
|
||||
this.$router = null;
|
||||
this.$store = null;
|
||||
};
|
||||
RouterPlugin.install = function (option = {}) {
|
||||
this.$router = option.router;
|
||||
this.$store = option.store;
|
||||
let i18n = option.i18n.global;
|
||||
this.$router.$avueRouter = {
|
||||
safe: this,
|
||||
// 设置标题
|
||||
setTitle: title => {
|
||||
const defaultTitle = i18n.t('title');
|
||||
title = title ? `${title} | ${defaultTitle}` : defaultTitle;
|
||||
document.title = title;
|
||||
},
|
||||
closeTag: value => {
|
||||
let tag = value || this.$store.getters.tag;
|
||||
if (typeof value === 'string') {
|
||||
tag = this.$store.getters.tagList.find(ele => ele.fullPath === value);
|
||||
}
|
||||
this.$store.commit('DEL_TAG', tag);
|
||||
},
|
||||
generateTitle: (item, props = {}) => {
|
||||
let query = item[props.query || 'query'] || {};
|
||||
let title = query.name || item[props.label || 'label'];
|
||||
let meta = item[props.meta || 'meta'] || {};
|
||||
let key = meta.i18n;
|
||||
if (key) {
|
||||
const hasKey = i18n.te('route.' + key);
|
||||
if (hasKey) return i18n.t('route.' + key);
|
||||
}
|
||||
return title;
|
||||
},
|
||||
//动态路由
|
||||
formatRoutes: function (aMenu = [], first) {
|
||||
const aRouter = [];
|
||||
const propsDefault = website.menu;
|
||||
if (aMenu && aMenu.length === 0) return;
|
||||
for (let i = 0; i < aMenu.length; i++) {
|
||||
const oMenu = aMenu[i];
|
||||
let path = oMenu[propsDefault.path],
|
||||
isComponent = true,
|
||||
component = oMenu.component,
|
||||
name = oMenu[propsDefault.label],
|
||||
icon = oMenu[propsDefault.icon],
|
||||
children = oMenu[propsDefault.children],
|
||||
query = oMenu[propsDefault.query],
|
||||
meta = oMenu[propsDefault.meta];
|
||||
if (option.keepAlive) {
|
||||
meta.keepAlive = option.keepAlive;
|
||||
}
|
||||
const isChild = !!(children && children.length !== 0);
|
||||
const oRouter = {
|
||||
path: path,
|
||||
component: (() => {
|
||||
// 判断是否为首路由
|
||||
if (first) {
|
||||
return modules[
|
||||
option.store.getters.isMacOs
|
||||
? '../page/index/layout.vue'
|
||||
: '../page/index/index.vue'
|
||||
];
|
||||
// 判断是否为多层路由
|
||||
} else if (isChild && !first) {
|
||||
return modules['../page/index/layout.vue'];
|
||||
// 判断是否为最终的页面视图
|
||||
} else {
|
||||
let result = modules[`../${component}.vue`];
|
||||
if (result) result().then(mod => (mod.default.name = path));
|
||||
else {
|
||||
isComponent = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
})(),
|
||||
name,
|
||||
icon,
|
||||
meta,
|
||||
query,
|
||||
redirect: (() => {
|
||||
if (!isChild && first) return `${path}`;
|
||||
else return '';
|
||||
})(),
|
||||
// 处理是否为一级路由
|
||||
children: !isChild
|
||||
? (() => {
|
||||
if (first) {
|
||||
oMenu[propsDefault.path] = `${path}`;
|
||||
let result = modules[`../${component}.vue`];
|
||||
if (result) result().then(mod => (mod.default.name = path));
|
||||
else {
|
||||
isComponent = false;
|
||||
}
|
||||
return [
|
||||
{
|
||||
component: result,
|
||||
icon: icon,
|
||||
name: name,
|
||||
meta: meta,
|
||||
query: query,
|
||||
path: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
return [];
|
||||
})()
|
||||
: (() => {
|
||||
return this.formatRoutes(children, false);
|
||||
})(),
|
||||
};
|
||||
if (!isURL(path) && isComponent) aRouter.push(oRouter);
|
||||
}
|
||||
if (first) {
|
||||
aRouter.forEach(ele => this.safe.$router.addRoute(ele));
|
||||
} else {
|
||||
return aRouter;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
export const formatPath = (ele, first) => {
|
||||
const propsDefault = website.menu;
|
||||
const icon = ele[propsDefault.icon];
|
||||
ele[propsDefault.icon] = !icon ? propsDefault.iconDefault : icon;
|
||||
ele.meta = { keepAlive: ele.isOpen === 2 };
|
||||
const iframeComponent = 'components/iframe/main';
|
||||
const iframeSrc = href => {
|
||||
return href.replace(/&/g, '#');
|
||||
};
|
||||
const isChild = !!(ele[propsDefault.children] && ele[propsDefault.children].length !== 0);
|
||||
if (!isChild && first) {
|
||||
ele.component = 'views' + ele[propsDefault.path];
|
||||
if (isURL(ele[propsDefault.href])) {
|
||||
let href = ele[propsDefault.href];
|
||||
ele.component = iframeComponent;
|
||||
ele[propsDefault.query] = { url: iframeSrc(href) };
|
||||
}
|
||||
} else {
|
||||
ele[propsDefault.children] &&
|
||||
ele[propsDefault.children].forEach(child => {
|
||||
child.component = 'views' + child[propsDefault.path];
|
||||
child.meta = { keepAlive: child.isOpen === 2 };
|
||||
if (isURL(child[propsDefault.href])) {
|
||||
let href = child[propsDefault.href];
|
||||
child[propsDefault.path] = ele[propsDefault.path] + '/' + child.code;
|
||||
child.component = iframeComponent;
|
||||
child[propsDefault.query] = { url: iframeSrc(href) };
|
||||
}
|
||||
formatPath(child);
|
||||
});
|
||||
}
|
||||
};
|
||||
export default RouterPlugin;
|
||||
37
src/router/index.js
Normal file
37
src/router/index.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import PageRouter from './page/';
|
||||
import ViewsRouter from './views/';
|
||||
import AvueRouter from './avue-router';
|
||||
import i18n from '@/lang';
|
||||
import Store from '@/store/';
|
||||
import Layout from '@/page/index/index.vue';
|
||||
|
||||
//创建路由
|
||||
const Router = createRouter({
|
||||
base: import.meta.env.VITE_APP_BASE,
|
||||
history: createWebHistory(import.meta.env.VITE_APP_BASE),
|
||||
routes: [
|
||||
...PageRouter,
|
||||
...ViewsRouter,
|
||||
],
|
||||
});
|
||||
AvueRouter.install({
|
||||
store: Store,
|
||||
router: Router,
|
||||
i18n: i18n,
|
||||
});
|
||||
|
||||
Router.$avueRouter.formatRoutes(Store.getters.menuAll, true);
|
||||
|
||||
export function resetRouter() {
|
||||
// 重置路由 比如用于身份验证失败,需要重新登录时 先清空当前的路有权限
|
||||
const newRouter = createRouter();
|
||||
Router.matcher = newRouter.matcher; // reset router
|
||||
AvueRouter.install(Vue, {
|
||||
router: Router,
|
||||
store: Store,
|
||||
i18n: i18n,
|
||||
});
|
||||
}
|
||||
|
||||
export default Router;
|
||||
72
src/router/page/index.js
Normal file
72
src/router/page/index.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import Store from '@/store/';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/login',
|
||||
name: '登录页',
|
||||
component: () =>
|
||||
Store.getters.isMacOs ? import('@/mac/login.vue') : import('@/page/login/index.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
isTab: false,
|
||||
isAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/oauth/redirect/:source',
|
||||
name: '第三方登录',
|
||||
component: () =>
|
||||
Store.getters.isMacOs ? import('@/mac/login.vue') : import('@/page/login/index.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
isTab: false,
|
||||
isAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/lock',
|
||||
name: '锁屏页',
|
||||
component: () =>
|
||||
Store.getters.isMacOs ? import('@/mac/lock.vue') : import('@/page/lock/index.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
isTab: false,
|
||||
isAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import(/* webpackChunkName: "page" */ '@/components/error-page/404.vue'),
|
||||
name: '404',
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
isTab: false,
|
||||
isAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/403',
|
||||
component: () => import(/* webpackChunkName: "page" */ '@/components/error-page/403.vue'),
|
||||
name: '403',
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
isTab: false,
|
||||
isAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/500',
|
||||
component: () => import(/* webpackChunkName: "page" */ '@/components/error-page/500.vue'),
|
||||
name: '500',
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
isTab: false,
|
||||
isAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: '主页',
|
||||
redirect: '/wel',
|
||||
},
|
||||
];
|
||||
45
src/router/views/index.js
Normal file
45
src/router/views/index.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import Layout from '@/page/index/index.vue';
|
||||
import Store from '@/store/';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/wel',
|
||||
component: () =>
|
||||
Store.getters.isMacOs ? import('@/mac/index.vue') : import('@/page/index/index.vue'),
|
||||
redirect: '/wel/index',
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: '首页',
|
||||
meta: {
|
||||
i18n: 'dashboard',
|
||||
},
|
||||
component: () => import(/* webpackChunkName: "views" */ '@/views/wel/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
name: '控制台',
|
||||
meta: {
|
||||
i18n: 'dashboard',
|
||||
menu: false,
|
||||
},
|
||||
component: () => import(/* webpackChunkName: "views" */ '@/views/wel/dashboard.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/info',
|
||||
component: Layout,
|
||||
redirect: '/info/index',
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: '个人信息',
|
||||
meta: {
|
||||
i18n: 'info',
|
||||
},
|
||||
component: () => import(/* webpackChunkName: "views" */ '@/views/system/userinfo.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
36
src/store/getters.js
Normal file
36
src/store/getters.js
Normal file
@@ -0,0 +1,36 @@
|
||||
const getters = {
|
||||
tag: state => state.tags.tag,
|
||||
language: state => state.common.language,
|
||||
setting: state => state.common.setting,
|
||||
userInfo: state => state.user.userInfo,
|
||||
themeName: state => state.common.themeName,
|
||||
isMacOs: (state, getters) => getters.themeName === 'mac-os',
|
||||
isRefresh: state => state.common.isRefresh,
|
||||
isSearch: state => state.common.isSearch,
|
||||
isHorizontal: state => state.common.setting.sidebar === 'horizontal',
|
||||
isCollapse: state => state.common.isCollapse,
|
||||
isLock: state => state.common.isLock,
|
||||
isFullScren: state => state.common.isFullScren,
|
||||
isMenu: state => state.common.isMenu,
|
||||
lockPasswd: state => state.common.lockPasswd,
|
||||
tagList: state => state.tags.tagList,
|
||||
tagsKeep: (state, getters) => {
|
||||
return getters.tagList
|
||||
.filter(ele => {
|
||||
return (ele.meta || {}).keepAlive;
|
||||
})
|
||||
.map(ele => ele.fullPath);
|
||||
},
|
||||
tagWel: state => state.tags.tagWel,
|
||||
token: state => state.user.token,
|
||||
roles: state => state.user.roles,
|
||||
permission: state => state.user.permission,
|
||||
menuId: state => state.user.menuId,
|
||||
menu: state => state.user.menu,
|
||||
menuAll: state => state.user.menuAll,
|
||||
logsList: state => state.logs.logsList,
|
||||
logsLen: state => state.logs.logsList.length || 0,
|
||||
logsFlag: (state, getters) => getters.logsLen === 0,
|
||||
flowRoutes: state => state.dict.flowRoutes,
|
||||
};
|
||||
export default getters;
|
||||
20
src/store/index.js
Normal file
20
src/store/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createStore } from 'vuex';
|
||||
import user from './modules/user';
|
||||
import common from './modules/common';
|
||||
import tags from './modules/tags';
|
||||
import logs from './modules/logs';
|
||||
import dict from './modules/dict';
|
||||
import getters from './getters';
|
||||
|
||||
const store = createStore({
|
||||
modules: {
|
||||
user,
|
||||
common,
|
||||
logs,
|
||||
tags,
|
||||
dict,
|
||||
},
|
||||
getters,
|
||||
});
|
||||
|
||||
export default store;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user