封装导出下载
This commit is contained in:
parent
4ab5a2eee3
commit
b32dee5886
@ -10,8 +10,8 @@ VUE_APP_API_BASEURL = https://xwapi.dev.dwoodauto.com/api/v1
|
|||||||
VUE_APP_API_DEV = https://xwapi.dev.dwoodauto.com
|
VUE_APP_API_DEV = https://xwapi.dev.dwoodauto.com
|
||||||
|
|
||||||
# WS地址
|
# WS地址
|
||||||
VUE_APP_WS_URL = wss://api.dev.dwoodauto.com/wss
|
VUE_APP_WS_URL = wss://xwapi.dev.dwoodauto.com/wss
|
||||||
VUE_APP_WSS_URL = wss://api.dev.dwoodauto.com/wss
|
VUE_APP_WSS_URL = wss://xwapi.dev.dwoodauto.com/wss
|
||||||
|
|
||||||
# 本地端口
|
# 本地端口
|
||||||
VUE_APP_PORT = 2801
|
VUE_APP_PORT = 2801
|
||||||
|
|||||||
@ -212,6 +212,13 @@ export default {
|
|||||||
post: async function (params) {
|
post: async function (params) {
|
||||||
return await http.post(this.url,params);
|
return await http.post(this.url,params);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
export:{
|
||||||
|
url: `${config.API_URL}/organization.export`,
|
||||||
|
name: "公司资料导出",
|
||||||
|
post: async function (params) {
|
||||||
|
return await http.post(this.url,params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dept: {
|
dept: {
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M554.666667 426.666667h213.333333l-256 256-256-256h213.333333V128h85.333334v298.666667z m-384 384h682.666666v-298.666667h85.333334v341.333333a42.666667 42.666667 0 0 1-42.666667 42.666667H128a42.666667 42.666667 0 0 1-42.666667-42.666667v-341.333333h85.333334v298.666667z" p-id="26056"></path></svg>
|
<svg t="1720852160381" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3290" width="200" height="200"><path d="M519.64586667 75.09333333a36.40888889 36.40888889 0 0 1 36.40888888 36.40888889v501.49603556l182.04444445-177.96664889a36.40888889 36.40888889 0 1 1 50.97244445 52.06471111l-243.93955556 238.47822222a36.40888889 36.40888889 0 0 1-51.40935111-0.43690667L257.13777778 486.73223111a36.40888889 36.40888889 0 0 1 51.70062222-51.26371556l174.39857778 175.70929778V111.50222222a36.40888889 36.40888889 0 0 1 36.40888889-36.40888889z" fill="" p-id="3291"></path><path d="M111.50222222 584.67214222a36.40888889 36.40888889 0 0 1 36.40888889 36.40888889v218.45333334a36.40888889 36.40888889 0 0 0 36.40888889 36.40888888h655.36a36.40888889 36.40888889 0 0 0 36.40888889-36.40888888v-218.45333334a36.40888889 36.40888889 0 0 1 72.81777778 0v218.45333334a109.22666667 109.22666667 0 0 1-109.22666667 109.22666666h-655.36a109.22666667 109.22666667 0 0 1-109.22666667-109.22666666v-218.45333334a36.40888889 36.40888889 0 0 1 36.40888889-36.40888889z" fill="" p-id="3292"></path></svg>
|
||||||
</template>
|
</template>
|
||||||
13
src/assets/icons/Finish.vue
Normal file
13
src/assets/icons/Finish.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<svg t="1720855403788" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3434" width="200" height="200"><path d="M512.170667 6.144a504.917333 504.917333 0 0 0-504.32 504.32 504.917333 504.917333 0 0 0 504.32 504.405333 504.917333 504.917333 0 0 0 504.32-504.32 504.917333 504.917333 0 0 0-504.32-504.32zM794.453333 413.866667L466.432 750.08a42.069333 42.069333 0 0 1-29.866667 12.629333h-0.170666a42.069333 42.069333 0 0 1-29.696-12.288L230.314667 574.037333a41.984 41.984 0 1 1 59.392-59.392L436.053333 660.906667l298.24-305.834667a42.069333 42.069333 0 0 1 60.16 58.794667z" fill="#0DA525" p-id="3435"></path></svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Finish"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -21,6 +21,7 @@ export { default as Secure } from './Secure.vue'
|
|||||||
export { default as UserLog } from './Log.vue'
|
export { default as UserLog } from './Log.vue'
|
||||||
export { default as WechartRound } from './WechartRound.vue'
|
export { default as WechartRound } from './WechartRound.vue'
|
||||||
export { default as Cost } from './Cost.vue'
|
export { default as Cost } from './Cost.vue'
|
||||||
|
export { default as Finish } from './Finish.vue'
|
||||||
|
|
||||||
// 列表按钮
|
// 列表按钮
|
||||||
export { default as Delete } from './Delete.vue'
|
export { default as Delete } from './Delete.vue'
|
||||||
|
|||||||
102
src/components/scExport/index.vue
Normal file
102
src/components/scExport/index.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<el-popover
|
||||||
|
placement="bottom-start"
|
||||||
|
title=""
|
||||||
|
trigger="click"
|
||||||
|
content=""
|
||||||
|
width="280"
|
||||||
|
:visible="exportVisible"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button v-bind="$attrs" :size="size" icon="sc-icon-Download" @click="exportClick">下载</el-button>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<div class="exportHeader">
|
||||||
|
<div class="name">{{info.type_desc}}</div>
|
||||||
|
<div class="status" v-if="info.status==0">{{info.msg}}</div>
|
||||||
|
<div class="finish" v-if="info.status==1"><i class="icon"><sc-icon-Finish/></i> 文件生成完成</div>
|
||||||
|
</div>
|
||||||
|
<el-progress class="exportPopover" :text-inside="true" :stroke-width="12" :percentage="info.rate" />
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "index",
|
||||||
|
props:{
|
||||||
|
size:{ type: String, default: "small" },
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return{
|
||||||
|
exportVisible:false,
|
||||||
|
info:{
|
||||||
|
name:"",
|
||||||
|
status:"",
|
||||||
|
rate:0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取新消息
|
||||||
|
this.$socketApi.getSock(this.getWsResult);
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
getWsResult(res){
|
||||||
|
if(res.data && res.data.type == 6){
|
||||||
|
if(res.data.status == 0){
|
||||||
|
this.exportVisible = true;
|
||||||
|
}
|
||||||
|
this.info = res.data;
|
||||||
|
if(res.data.status==1){
|
||||||
|
this.exportVisible = false;
|
||||||
|
this.info = {};
|
||||||
|
this.down(res.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
down(item){
|
||||||
|
const blob = new Blob([item.file_url]);
|
||||||
|
let fileName = item.type_desc+".xlsx";
|
||||||
|
if ('download' in document.createElement('a')) { // 非IE下载
|
||||||
|
let eLink = document.createElement('a');
|
||||||
|
eLink.download = fileName
|
||||||
|
eLink.style.display = 'none';
|
||||||
|
eLink.href = URL.createObjectURL(blob);
|
||||||
|
document.body.appendChild(eLink);
|
||||||
|
eLink.click();
|
||||||
|
URL.revokeObjectURL(eLink.href); // 释放URL 对象
|
||||||
|
document.body.removeChild(eLink);
|
||||||
|
} else { // IE10+下载
|
||||||
|
navigator.msSaveBlob(blob, fileName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exportClick(){
|
||||||
|
if(this.exportVisible){
|
||||||
|
this.exportVisible = false;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$emit('exportData');
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.exportHeader{
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;align-items: center;justify-content: space-around;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
.name{width: 60%;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;}
|
||||||
|
.status{width: 40%;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;}
|
||||||
|
.finish{
|
||||||
|
display: flex;align-items: center;justify-content: flex-end;color: var(--el-color-success);
|
||||||
|
.icon{width: 14px;height: 14px;margin-right: 4px;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.exportPopover :deep(.el-progress-bar__innerText){
|
||||||
|
height: 100%;
|
||||||
|
display: flex;align-items: center;justify-content: flex-end;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -242,9 +242,18 @@
|
|||||||
created() {
|
created() {
|
||||||
this.onLayoutResize();
|
this.onLayoutResize();
|
||||||
window.addEventListener('resize', this.onLayoutResize);
|
window.addEventListener('resize', this.onLayoutResize);
|
||||||
var menu = this.$router.sc_getMenu();
|
const menu = this.$router.sc_getMenu();
|
||||||
this.menu = this.filterUrl(menu);
|
this.menu = this.filterUrl(menu);
|
||||||
this.showThis()
|
this.showThis();
|
||||||
|
|
||||||
|
let token = this.$TOOL.cookie.get('TOKEN');
|
||||||
|
if (token && token != null) {
|
||||||
|
let global_callback = function () {};
|
||||||
|
this.$socketApi.createWebSocket(global_callback);
|
||||||
|
|
||||||
|
// 获取新消息
|
||||||
|
// this.$socketApi.getSock(this.getWsResult);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route() {
|
$route() {
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import scMultipleSelect from "./components/scMultipleSelect";
|
|||||||
import scInput from "./components/scInput";
|
import scInput from "./components/scInput";
|
||||||
import scVgInput from "./components/scInput/inputVague";
|
import scVgInput from "./components/scInput/inputVague";
|
||||||
import scSearch from "./components/scSearch";
|
import scSearch from "./components/scSearch";
|
||||||
|
import scExport from "./components/scExport";
|
||||||
|
|
||||||
import scStatusIndicator from './components/scMini/scStatusIndicator'
|
import scStatusIndicator from './components/scMini/scStatusIndicator'
|
||||||
import scTrend from './components/scMini/scTrend'
|
import scTrend from './components/scMini/scTrend'
|
||||||
@ -40,6 +41,7 @@ import errorHandler from './utils/errorHandler'
|
|||||||
|
|
||||||
import * as elIcons from '@element-plus/icons-vue'
|
import * as elIcons from '@element-plus/icons-vue'
|
||||||
import * as scIcons from './assets/icons'
|
import * as scIcons from './assets/icons'
|
||||||
|
import * as socketApi from "@/utils/websocket";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(app) {
|
install(app) {
|
||||||
@ -50,6 +52,7 @@ export default {
|
|||||||
app.config.globalProperties.$API = api;
|
app.config.globalProperties.$API = api;
|
||||||
app.config.globalProperties.$AUTH = permission;
|
app.config.globalProperties.$AUTH = permission;
|
||||||
app.config.globalProperties.$ROLE = rolePermission;
|
app.config.globalProperties.$ROLE = rolePermission;
|
||||||
|
app.config.globalProperties.$socketApi = socketApi;
|
||||||
|
|
||||||
//注册全局组件
|
//注册全局组件
|
||||||
app.component('scTable', scTable);
|
app.component('scTable', scTable);
|
||||||
@ -76,6 +79,7 @@ export default {
|
|||||||
app.component('scInput', scInput);
|
app.component('scInput', scInput);
|
||||||
app.component('scVgInput', scVgInput);
|
app.component('scVgInput', scVgInput);
|
||||||
app.component('scSearch', scSearch);
|
app.component('scSearch', scSearch);
|
||||||
|
app.component('scExport', scExport);
|
||||||
|
|
||||||
//注册全局指令
|
//注册全局指令
|
||||||
app.directive('auth', auth)
|
app.directive('auth', auth)
|
||||||
|
|||||||
194
src/utils/websocket.js
Normal file
194
src/utils/websocket.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
//@eslint-disable
|
||||||
|
|
||||||
|
import tool from '@/utils/tool';
|
||||||
|
import systemConfig from '@/config';
|
||||||
|
import api from '../api';
|
||||||
|
import router from "@/router";
|
||||||
|
import {ElNotification} from 'element-plus';
|
||||||
|
// import store from "../store";
|
||||||
|
|
||||||
|
let websocket = null;
|
||||||
|
let global_callback = function () {};
|
||||||
|
let timeoutObj = null;
|
||||||
|
let timeout = 28 * 1000; //30秒一次心跳
|
||||||
|
let serverTimeoutObj = 60; //心跳倒计时
|
||||||
|
let timeOutNum = 60; //断开 重连倒计时
|
||||||
|
let lockReconnect = false; //是否真正建立连接
|
||||||
|
const wsUri = systemConfig.WS_URL;
|
||||||
|
let showNot = null;
|
||||||
|
|
||||||
|
function networkDes() {
|
||||||
|
ElNotification.error({
|
||||||
|
title: '网络已断开',
|
||||||
|
message: '网络已断开,正在重连……'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function reConnect() {//重新连接
|
||||||
|
if (lockReconnect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lockReconnect = true;
|
||||||
|
//没连接上会一直重连,设置延迟避免请求过多
|
||||||
|
timeOutNum && clearTimeout(timeOutNum);
|
||||||
|
timeOutNum = setTimeout(function () {
|
||||||
|
//新连接
|
||||||
|
createWebSocket(global_callback);
|
||||||
|
lockReconnect = false;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startHeartbeat() {
|
||||||
|
//清除时间
|
||||||
|
clearTimeout(timeoutObj);
|
||||||
|
clearTimeout(serverTimeoutObj);
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {//开启心跳
|
||||||
|
timeoutObj && clearTimeout(timeoutObj);
|
||||||
|
serverTimeoutObj && clearTimeout(serverTimeoutObj);
|
||||||
|
timeoutObj = setTimeout(function () {
|
||||||
|
//这里发送一个心跳,后端收到后,返回一个心跳消息,
|
||||||
|
if (websocket.readyState === 1) {//如果连接正常
|
||||||
|
const heart = {type: "heart"}
|
||||||
|
websocket.send(JSON.stringify(heart));
|
||||||
|
} else {//否则重连
|
||||||
|
reConnect();
|
||||||
|
}
|
||||||
|
serverTimeoutObj = setTimeout(function () {
|
||||||
|
//超时关闭
|
||||||
|
closeSock(false);
|
||||||
|
}, timeout);
|
||||||
|
}, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWebSocket(callback, token) {
|
||||||
|
if (websocket == null || typeof websocket !== WebSocket) {
|
||||||
|
initWebSocket(callback, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initWebSocket(callback, token) {
|
||||||
|
global_callback = callback;
|
||||||
|
// 初始化websocket
|
||||||
|
let reToken = token === undefined ? tool.cookie.get('TOKEN') : token;
|
||||||
|
if(!reToken) return // 没有token 不执行ws创建
|
||||||
|
websocket = new WebSocket(wsUri + "?token=Bearer " + reToken);
|
||||||
|
websocket.onmessage = function (e) {
|
||||||
|
webSocketOnMessage(e);
|
||||||
|
};
|
||||||
|
websocket.onclose = function (e) {
|
||||||
|
webSocketClose(e);
|
||||||
|
};
|
||||||
|
websocket.onopen = function () {
|
||||||
|
websocketOpen();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 连接发生错误的回调方法
|
||||||
|
websocket.onerror = function () {
|
||||||
|
networkDes()
|
||||||
|
reConnect()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实际调用的方法
|
||||||
|
function sendSock(agentData) {
|
||||||
|
if (websocket.readyState === websocket.OPEN) {
|
||||||
|
// 若是ws开启状态
|
||||||
|
webSocketSend(agentData);
|
||||||
|
} else if (websocket.readyState === websocket.CONNECTING) {
|
||||||
|
// 若是 正在开启状态,则等待1s后重新调用
|
||||||
|
setTimeout(function () {
|
||||||
|
sendSock(agentData);
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
// 若未开启 ,则等待1s后重新调用
|
||||||
|
setTimeout(function () {
|
||||||
|
sendSock(agentData);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSock(active) {
|
||||||
|
lockReconnect = active; // 主动断开时不重连
|
||||||
|
websocket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据接收
|
||||||
|
function webSocketOnMessage(msg) {
|
||||||
|
// 收到信息为Blob类型时
|
||||||
|
let result = null;
|
||||||
|
// debugger
|
||||||
|
// 二进制文件
|
||||||
|
if (msg.data instanceof Blob) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsText(msg.data, "UTF-8");
|
||||||
|
reader.onload = () => {
|
||||||
|
result = JSON.parse(reader.result);
|
||||||
|
global_callback(result);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if(msg.type === "") return
|
||||||
|
result = JSON.parse(msg.data);
|
||||||
|
// if(result.type == 13){
|
||||||
|
// store.commit("SET_WS_Msg_NUM", result.data.todo_msg_count);
|
||||||
|
// }
|
||||||
|
if(global_callback){
|
||||||
|
global_callback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.type == -1 || result.type == 8 || result.type == 9) {
|
||||||
|
if(result.type == -1){
|
||||||
|
if(result.data && result.data.token){
|
||||||
|
tool.cookie.set("TOKEN", result.data.token);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
showNot = ElNotification.error({
|
||||||
|
title: '系统退出',
|
||||||
|
message: result.msg,
|
||||||
|
duration:0
|
||||||
|
});
|
||||||
|
handleError('系统退出', result.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result.type == 'init'){
|
||||||
|
if(showNot && showNot.close){
|
||||||
|
showNot.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startHeartbeat()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleError() {
|
||||||
|
api.system.user.logout.post().then();
|
||||||
|
router.replace({ path: "/login" }).then();
|
||||||
|
closeSock(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSock(callback) {
|
||||||
|
global_callback = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据发送
|
||||||
|
function webSocketSend(agentData) {
|
||||||
|
websocket.send(agentData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
function webSocketClose() {
|
||||||
|
reConnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
function websocketOpen() {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
sendSock,
|
||||||
|
createWebSocket,
|
||||||
|
closeSock,
|
||||||
|
getSock,
|
||||||
|
reConnect,
|
||||||
|
};
|
||||||
@ -6,7 +6,7 @@
|
|||||||
<el-button type="primary" :size="size" plain>批量导入</el-button>
|
<el-button type="primary" :size="size" plain>批量导入</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-panel">
|
<div class="right-panel">
|
||||||
<el-button :size="size" icon="sc-icon-Download">下载</el-button>
|
<scExport :size="size" @exportData="exportData"></scExport>
|
||||||
</div>
|
</div>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="nopadding">
|
<el-main class="nopadding">
|
||||||
@ -206,6 +206,12 @@ export default {
|
|||||||
delete row.$switch_yx;
|
delete row.$switch_yx;
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
|
async exportData() {
|
||||||
|
const res = await this.$API.system.company.export.post();
|
||||||
|
if(res.code == 200){
|
||||||
|
this.$message.success('开始导出');
|
||||||
|
}
|
||||||
|
},
|
||||||
upSearch(){
|
upSearch(){
|
||||||
this.$refs.table.upData(this.params);
|
this.$refs.table.upData(this.params);
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user