fix:相关漏洞修复
This commit is contained in:
1 parent
0e66d461a7
commit
766bdea32a
6 files changed
+370
-294
No files matched your search
@@ -3,7 +3,9 @@
|
||||
<div v-loading="mainLoading" class="msg-main">
|
||||
<div id="msg-div" class="msg-div">
|
||||
<div v-if="!tableLoading">
|
||||
<div v-if="loadMore" class="el-table__empty-block" @click="loadingMore"><span class="el-table__empty-text">点击加载更多</span></div>
|
||||
<div v-if="loadMore" class="el-table__empty-block" @click="loadingMore">
|
||||
<span class="el-table__empty-text">点击加载更多</span>
|
||||
</div>
|
||||
<div v-if="!loadMore" class="el-table__empty-block"><span class="el-table__empty-text">没有更多了</span></div>
|
||||
</div>
|
||||
<div v-for="item in tableData" :key="item.id" class="execution" id="msgTable">
|
||||
@@ -109,125 +111,125 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="wx-msg">
|
||||
import { fetchList, addObj } from '/@/api/mp/wx-fans-msg';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getMaterialVideo } from '/@/api/mp/wx-material';
|
||||
import { fetchList, addObj } from "/@/api/mp/wx-fans-msg"
|
||||
import { useMessage } from "/@/hooks/message"
|
||||
import { getMaterialVideo } from "/@/api/mp/wx-material"
|
||||
|
||||
const WxReply = defineAsyncComponent(() => import('../wx-reply/index.vue'));
|
||||
const WxNews = defineAsyncComponent(() => import('../wx-news/index.vue'));
|
||||
const WxReply = defineAsyncComponent(() => import("../wx-reply/index.vue"))
|
||||
const WxNews = defineAsyncComponent(() => import("../wx-news/index.vue"))
|
||||
|
||||
const NameAvatar = defineAsyncComponent(() => import('/@/components/NameAvatar/index.vue'));
|
||||
const NameAvatar = defineAsyncComponent(() => import("/@/components/NameAvatar/index.vue"))
|
||||
|
||||
const visible = ref(false);
|
||||
const visible = ref(false)
|
||||
|
||||
// 各种loading
|
||||
const mainLoading = ref(false);
|
||||
const sendLoading = ref(false);
|
||||
const mainLoading = ref(false)
|
||||
const sendLoading = ref(false)
|
||||
|
||||
const loadMore = ref(false);
|
||||
const loadMore = ref(false)
|
||||
|
||||
const objData = ref({
|
||||
repType: 'text',
|
||||
appId: '',
|
||||
}) as any;
|
||||
repType: "text",
|
||||
appId: "",
|
||||
}) as any
|
||||
|
||||
const page = reactive({
|
||||
total: 0, // 总页数
|
||||
currentPage: 1, // 当前页数
|
||||
pageSize: 10, // 每页显示多少条
|
||||
ascs: [], //升序字段
|
||||
descs: 'create_time', //降序字段
|
||||
});
|
||||
descs: "create_time", //降序字段
|
||||
})
|
||||
|
||||
const wxData = reactive({
|
||||
appId: '',
|
||||
wxUserId: '',
|
||||
});
|
||||
appId: "",
|
||||
wxUserId: "",
|
||||
})
|
||||
|
||||
const sendMsg = () => {
|
||||
if (objData.value) {
|
||||
if (objData.value.repType === 'news') {
|
||||
if (objData.value.repType === "news") {
|
||||
if (JSON.parse(objData.value.content).length > 1) {
|
||||
useMessage().error('图文消息条数限制在1条以内,已默认发送第一条');
|
||||
objData.value.content = JSON.parse(objData.value.content)[0];
|
||||
useMessage().error("图文消息条数限制在1条以内,已默认发送第一条")
|
||||
objData.value.content = JSON.parse(objData.value.content)[0]
|
||||
}
|
||||
}
|
||||
sendLoading.value = true;
|
||||
sendLoading.value = true
|
||||
addObj(
|
||||
Object.assign(
|
||||
{
|
||||
wxUserId: wxData.wxUserId,
|
||||
appId: wxData.appId,
|
||||
},
|
||||
objData.value
|
||||
)
|
||||
objData.value,
|
||||
),
|
||||
)
|
||||
.then(() => {
|
||||
tableData.value = [];
|
||||
tableData.value = []
|
||||
getData().then(() => {
|
||||
//box-container是添加overflow的父div,也就是出现滚动条的div
|
||||
var scrollTarget = document.getElementById('msg-div');
|
||||
var scrollTarget = document.getElementById("msg-div")
|
||||
//scrollTarget.scrollHeight是获取dom元素的高度,然后设置scrollTop
|
||||
scrollTarget.scrollTop = scrollTarget.scrollHeight;
|
||||
});
|
||||
scrollTarget.scrollTop = scrollTarget.scrollHeight
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
sendLoading.value = false;
|
||||
});
|
||||
sendLoading.value = false
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const tableData = ref([] as any);
|
||||
const tableLoading = ref(false);
|
||||
const tableData = ref([] as any)
|
||||
const tableLoading = ref(false)
|
||||
|
||||
const openDialog = (data: any) => {
|
||||
wxData.wxUserId = data.wxUserId;
|
||||
wxData.appId = data.appId;
|
||||
objData.value.appId = data.appId;
|
||||
getData();
|
||||
visible.value = true;
|
||||
};
|
||||
wxData.wxUserId = data.wxUserId
|
||||
wxData.appId = data.appId
|
||||
objData.value.appId = data.appId
|
||||
getData()
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const getData = () => {
|
||||
tableLoading.value = true;
|
||||
tableLoading.value = true
|
||||
return fetchList({
|
||||
...page,
|
||||
...wxData,
|
||||
}).then((res) => {
|
||||
const data = res.data.records.reverse();
|
||||
tableData.value = [...data, ...tableData.value];
|
||||
page.total = res.data.total;
|
||||
tableLoading.value = false;
|
||||
const data = res.data.records.reverse()
|
||||
tableData.value = [...data, ...tableData.value]
|
||||
page.total = res.data.total
|
||||
tableLoading.value = false
|
||||
if (data.length < page.pageSize || data.length === 0) {
|
||||
loadMore.value = false;
|
||||
loadMore.value = false
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
const loadVideo = (item) => {
|
||||
getMaterialVideo({
|
||||
mediaId: item.repMediaId,
|
||||
appId: item.appId,
|
||||
}).then((response) => {
|
||||
const data = response.data;
|
||||
window.open(data.downUrl, 'target', '');
|
||||
});
|
||||
};
|
||||
// const data = response.data
|
||||
// window.open(data.downUrl, 'target', '');
|
||||
})
|
||||
}
|
||||
|
||||
const loadingMore = () => {
|
||||
page.currentPage = page.currentPage + 1;
|
||||
getData();
|
||||
};
|
||||
page.currentPage = page.currentPage + 1
|
||||
getData()
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './comment.scss';
|
||||
@import './card.scss';
|
||||
@import "./comment.scss";
|
||||
@import "./card.scss";
|
||||
|
||||
.msg-main {
|
||||
margin-top: -30px;
|
||||
|
||||
@@ -99,136 +99,136 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="wx-reply">
|
||||
import { getMaterialVideo } from '/@/api/mp/wx-material';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
const WxMaterialSelect = defineAsyncComponent(() => import('/@/components/Wechat/wx-material-select/main.vue'));
|
||||
import { getMaterialVideo } from "/@/api/mp/wx-material"
|
||||
import { useMessage } from "/@/hooks/message"
|
||||
const WxMaterialSelect = defineAsyncComponent(() => import("/@/components/Wechat/wx-material-select/main.vue"))
|
||||
|
||||
const WxFileUpload = defineAsyncComponent(() => import('/@/components/Wechat/fileUpload/index.vue'));
|
||||
const WxFileUpload = defineAsyncComponent(() => import("/@/components/Wechat/fileUpload/index.vue"))
|
||||
|
||||
const WxNews = defineAsyncComponent(() => import('/@/components/Wechat/wx-news/index.vue'));
|
||||
const WxNews = defineAsyncComponent(() => import("/@/components/Wechat/wx-news/index.vue"))
|
||||
|
||||
const props = defineProps({
|
||||
objData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
repType: '',
|
||||
repContent: '',
|
||||
repName: '',
|
||||
repDesc: '',
|
||||
repUrl: '',
|
||||
};
|
||||
repType: "",
|
||||
repContent: "",
|
||||
repName: "",
|
||||
repDesc: "",
|
||||
repUrl: "",
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const uploadData = reactive({
|
||||
mediaType: props.objData.repType,
|
||||
title: '',
|
||||
introduction: '',
|
||||
title: "",
|
||||
introduction: "",
|
||||
appId: props.objData.appId,
|
||||
});
|
||||
})
|
||||
|
||||
const tempObj = ref({}) as any;
|
||||
const tempObj = ref({}) as any
|
||||
|
||||
const handleClick = (tab) => {
|
||||
uploadData.mediaType = tab.paneName;
|
||||
uploadData.appId = props.objData.appId;
|
||||
uploadData.mediaType = tab.paneName
|
||||
uploadData.appId = props.objData.appId
|
||||
|
||||
const tempObjItem = tempObj.value[tab.paneName];
|
||||
const tempObjItem = tempObj.value[tab.paneName]
|
||||
if (tempObjItem) {
|
||||
props.objData.repName = tempObjItem.repName ? tempObjItem.repName : null;
|
||||
props.objData.repMediaId = tempObjItem.repMediaId ? tempObjItem.repMediaId : null;
|
||||
props.objData.media_id = tempObjItem.media_id ? tempObjItem.media_id : null;
|
||||
props.objData.repUrl = tempObjItem.repUrl ? tempObjItem.repUrl : null;
|
||||
props.objData.content = tempObjItem.content ? tempObjItem.content : null;
|
||||
props.objData.repDesc = tempObjItem.repDesc ? tempObjItem.repDesc : null;
|
||||
props.objData.repName = tempObjItem.repName ? tempObjItem.repName : null
|
||||
props.objData.repMediaId = tempObjItem.repMediaId ? tempObjItem.repMediaId : null
|
||||
props.objData.media_id = tempObjItem.media_id ? tempObjItem.media_id : null
|
||||
props.objData.repUrl = tempObjItem.repUrl ? tempObjItem.repUrl : null
|
||||
props.objData.content = tempObjItem.content ? tempObjItem.content : null
|
||||
props.objData.repDesc = tempObjItem.repDesc ? tempObjItem.repDesc : null
|
||||
} else {
|
||||
props.objData.repName = '';
|
||||
props.objData.repMediaId = '';
|
||||
props.objData.media_id = '';
|
||||
props.objData.repUrl = '';
|
||||
props.objData.content = '';
|
||||
props.objData.repDesc = '';
|
||||
props.objData.repName = ""
|
||||
props.objData.repMediaId = ""
|
||||
props.objData.media_id = ""
|
||||
props.objData.repUrl = ""
|
||||
props.objData.content = ""
|
||||
props.objData.repDesc = ""
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const deleteObj = () => {
|
||||
props.objData.repName = '';
|
||||
props.objData.repUrl = '';
|
||||
props.objData.content = '';
|
||||
};
|
||||
props.objData.repName = ""
|
||||
props.objData.repUrl = ""
|
||||
props.objData.content = ""
|
||||
}
|
||||
|
||||
const openMaterial = (data: any) => {
|
||||
dialogNewsRef.value.openDialog(data);
|
||||
};
|
||||
dialogNewsRef.value.openDialog(data)
|
||||
}
|
||||
|
||||
const dialogNewsRef = ref();
|
||||
const dialogNewsRef = ref()
|
||||
|
||||
const selectMaterial = (item, appId) => {
|
||||
let tempObjItem = {
|
||||
repType: '',
|
||||
repMediaId: '',
|
||||
media_id: '',
|
||||
content: '',
|
||||
} as any;
|
||||
repType: "",
|
||||
repMediaId: "",
|
||||
media_id: "",
|
||||
content: "",
|
||||
} as any
|
||||
|
||||
tempObjItem.repType = props.objData.repType;
|
||||
tempObjItem.repMediaId = item.mediaId;
|
||||
tempObjItem.media_id = item.mediaId;
|
||||
tempObjItem.content = item.content;
|
||||
tempObjItem.repType = props.objData.repType
|
||||
tempObjItem.repMediaId = item.mediaId
|
||||
tempObjItem.media_id = item.mediaId
|
||||
tempObjItem.content = item.content
|
||||
|
||||
props.objData.repMediaId = item.mediaId;
|
||||
props.objData.media_id = item.mediaId;
|
||||
props.objData.content = item.content;
|
||||
if (props.objData.repType === 'music') {
|
||||
tempObjItem.repThumbMediaId = item.mediaId;
|
||||
tempObjItem.repThumbUrl = item.url;
|
||||
props.objData.repThumbMediaId = item.mediaId;
|
||||
props.objData.repThumbUrl = item.url;
|
||||
props.objData.repMediaId = item.mediaId
|
||||
props.objData.media_id = item.mediaId
|
||||
props.objData.content = item.content
|
||||
if (props.objData.repType === "music") {
|
||||
tempObjItem.repThumbMediaId = item.mediaId
|
||||
tempObjItem.repThumbUrl = item.url
|
||||
props.objData.repThumbMediaId = item.mediaId
|
||||
props.objData.repThumbUrl = item.url
|
||||
} else {
|
||||
tempObjItem.repName = item.name;
|
||||
tempObjItem.repUrl = item.url;
|
||||
props.objData.repName = item.name;
|
||||
props.objData.repUrl = item.url;
|
||||
tempObjItem.repName = item.name
|
||||
tempObjItem.repUrl = item.url
|
||||
props.objData.repName = item.name
|
||||
props.objData.repUrl = item.url
|
||||
}
|
||||
if (props.objData.repType === 'video') {
|
||||
if (props.objData.repType === "video") {
|
||||
getMaterialVideo({
|
||||
mediaId: item.mediaId,
|
||||
appId: appId,
|
||||
}).then((response) => {
|
||||
const data = response.data;
|
||||
tempObjItem.repDesc = data.description || '';
|
||||
tempObjItem.repUrl = data.downUrl;
|
||||
props.objData.repName = data.title;
|
||||
props.objData.repDesc = data.description || '';
|
||||
props.objData.repUrl = data.downUrl;
|
||||
});
|
||||
const data = response.data
|
||||
tempObjItem.repDesc = data.description || ""
|
||||
tempObjItem.repUrl = data.downUrl
|
||||
props.objData.repName = data.title
|
||||
props.objData.repDesc = data.description || ""
|
||||
props.objData.repUrl = data.downUrl
|
||||
})
|
||||
}
|
||||
if (props.objData.repType === 'news') {
|
||||
props.objData.content = JSON.stringify(item.content.newsItem);
|
||||
if (props.objData.repType === "news") {
|
||||
props.objData.content = JSON.stringify(item.content.newsItem)
|
||||
}
|
||||
tempObj.value[props.objData.repType] = tempObjItem;
|
||||
};
|
||||
tempObj.value[props.objData.repType] = tempObjItem
|
||||
}
|
||||
|
||||
const handelUpload = (response) => {
|
||||
if (response.code === 0) {
|
||||
const item = response.data;
|
||||
selectMaterial(item, props.objData.appId);
|
||||
const item = response.data
|
||||
selectMaterial(item, props.objData.appId)
|
||||
} else {
|
||||
useMessage().error('上传错误' + response.msg);
|
||||
useMessage().error("上传错误" + response.msg)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const loadVideo = (item) => {
|
||||
getMaterialVideo({
|
||||
mediaId: item.repMediaId,
|
||||
appId: item.appId,
|
||||
}).then((response) => {
|
||||
const data = response.data;
|
||||
window.open(data.downUrl, 'target', '');
|
||||
});
|
||||
};
|
||||
// const data = response.data
|
||||
// window.open(data.downUrl, 'target', '');
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -28,74 +28,77 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="layoutBreadcrumbSearch">
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
import { useI18n } from "vue-i18n"
|
||||
import { useTagsViewRoutes } from "/@/stores/tagsViewRoutes"
|
||||
|
||||
// 定义变量内容
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes);
|
||||
const layoutMenuAutocompleteRef = ref();
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes()
|
||||
const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes)
|
||||
const layoutMenuAutocompleteRef = ref()
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const state = reactive<SearchState>({
|
||||
isShowSearch: false,
|
||||
menuQuery: '',
|
||||
menuQuery: "",
|
||||
tagsViewList: [],
|
||||
});
|
||||
})
|
||||
|
||||
// 搜索弹窗打开
|
||||
const openSearch = () => {
|
||||
state.menuQuery = '';
|
||||
state.isShowSearch = true;
|
||||
initTageView();
|
||||
state.menuQuery = ""
|
||||
state.isShowSearch = true
|
||||
initTageView()
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
layoutMenuAutocompleteRef.value.focus();
|
||||
});
|
||||
});
|
||||
};
|
||||
layoutMenuAutocompleteRef.value.focus()
|
||||
})
|
||||
})
|
||||
}
|
||||
// 搜索弹窗关闭
|
||||
const closeSearch = () => {
|
||||
state.isShowSearch = false;
|
||||
};
|
||||
state.isShowSearch = false
|
||||
}
|
||||
// 菜单搜索数据过滤
|
||||
const menuSearch = (queryString: string, cb: Function) => {
|
||||
let results = queryString ? state.tagsViewList.filter(createFilter(queryString)) : state.tagsViewList;
|
||||
cb(results);
|
||||
};
|
||||
let results = queryString ? state.tagsViewList.filter(createFilter(queryString)) : state.tagsViewList
|
||||
cb(results)
|
||||
}
|
||||
// 菜单搜索过滤
|
||||
const createFilter = (queryString: string) => {
|
||||
return (restaurant: RouteItem) => {
|
||||
return restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 || t(restaurant!.name!).indexOf(queryString.toLowerCase()) > -1;
|
||||
};
|
||||
};
|
||||
return (
|
||||
restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 || t(restaurant!.name!).indexOf(queryString.toLowerCase()) > -1
|
||||
)
|
||||
}
|
||||
}
|
||||
// 初始化菜单数据
|
||||
const initTageView = () => {
|
||||
if (state.tagsViewList.length > 0) return false;
|
||||
if (state.tagsViewList.length > 0) return false
|
||||
tagsViewRoutes.value.map((v: RouteItem) => {
|
||||
if (!v.meta?.isHide) state.tagsViewList.push({ ...v });
|
||||
});
|
||||
};
|
||||
if (!v.meta?.isHide) state.tagsViewList.push({ ...v })
|
||||
})
|
||||
}
|
||||
// 当前菜单选中时
|
||||
const onHandleSelect = (item: RouteItem) => {
|
||||
let { path, redirect } = item;
|
||||
if (item.meta?.isLink && !item.meta?.isIframe) window.open(item.meta?.isLink);
|
||||
else if (redirect) router.push(redirect);
|
||||
else router.push(path);
|
||||
closeSearch();
|
||||
};
|
||||
let { path, redirect } = item
|
||||
if (item.meta?.isLink && !item.meta?.isIframe) {
|
||||
// window.open(item.meta?.isLink)
|
||||
} else if (redirect) router.push(redirect)
|
||||
else router.push(path)
|
||||
closeSearch()
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openSearch,
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-search-dialog {
|
||||
position: relative;
|
||||
:deep(.el-dialog) {
|
||||
width: 560px;
|
||||
width: 560px;
|
||||
.el-dialog__header,
|
||||
.el-dialog__body {
|
||||
display: none;
|
||||
@@ -108,8 +111,8 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
:deep(.el-autocomplete) {
|
||||
position: absolute;
|
||||
width: 560px;
|
||||
position: absolute;
|
||||
width: 560px;
|
||||
top: 53vh;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
@@ -14,31 +14,34 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="layoutLinkView">
|
||||
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||
import { verifyUrl } from "/@/utils/toolsValidate"
|
||||
|
||||
// 定义变量内容
|
||||
const route = useRoute();
|
||||
const route = useRoute()
|
||||
const state = reactive<LinkViewState>({
|
||||
title: '',
|
||||
isLink: '',
|
||||
});
|
||||
title: "",
|
||||
isLink: "",
|
||||
})
|
||||
|
||||
// 立即前往
|
||||
const onGotoFullPage = () => {
|
||||
if (verifyUrl(<string>state.isLink)) window.open(state.isLink);
|
||||
else window.open(`${state.isLink}`);
|
||||
};
|
||||
if (verifyUrl(<string>state.isLink)) {
|
||||
window.open(state.isLink)
|
||||
} else {
|
||||
window.open(`${state.isLink}`)
|
||||
}
|
||||
}
|
||||
// 监听路由的变化,设置内容
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
state.title = <string>route.name;
|
||||
state.isLink = <string>route.meta.isLink;
|
||||
state.title = <string>route.name
|
||||
state.isLink = <string>route.meta.isLink
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -56,7 +59,7 @@ watch(
|
||||
color: var(--el-color-primary);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 0;
|
||||
|
||||
+93
-25
@@ -167,13 +167,13 @@ export const openWindow = (url: string, title: string, w: number, h: number) =>
|
||||
const width = window.innerWidth
|
||||
? window.innerWidth
|
||||
: document.documentElement.clientWidth
|
||||
? document.documentElement.clientWidth
|
||||
: screen.width
|
||||
? document.documentElement.clientWidth
|
||||
: screen.width
|
||||
const height = window.innerHeight
|
||||
? window.innerHeight
|
||||
: document.documentElement.clientHeight
|
||||
? document.documentElement.clientHeight
|
||||
: screen.height
|
||||
? document.documentElement.clientHeight
|
||||
: screen.height
|
||||
|
||||
const left = width / 2 - w / 2 + dualScreenLeft
|
||||
const top = height / 2 - h / 2 + dualScreenTop
|
||||
@@ -181,13 +181,13 @@ export const openWindow = (url: string, title: string, w: number, h: number) =>
|
||||
url,
|
||||
title,
|
||||
"toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=" +
|
||||
w +
|
||||
", height=" +
|
||||
h +
|
||||
", top=" +
|
||||
top +
|
||||
", left=" +
|
||||
left,
|
||||
w +
|
||||
", height=" +
|
||||
h +
|
||||
", top=" +
|
||||
top +
|
||||
", left=" +
|
||||
left,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -290,25 +290,93 @@ export function postDownBlobFile(url: any, data: any, fileName: string) {
|
||||
*/
|
||||
export function handleBlobFile(response: any, fileName: string) {
|
||||
// 处理返回的文件流
|
||||
const blob = response
|
||||
if (blob && blob.size === 0) {
|
||||
useMessage().error("内容为空,无法下载")
|
||||
// const blob = response
|
||||
// if (blob && blob.size === 0) {
|
||||
// useMessage().error("内容为空,无法下载")
|
||||
// return
|
||||
// }
|
||||
// const link = document.createElement("a")
|
||||
|
||||
// // 兼容一下 入参不是 File Blob 类型情况
|
||||
// var binaryData = [] as any
|
||||
// binaryData.push(response)
|
||||
// link.href = window.URL.createObjectURL(new Blob(binaryData))
|
||||
// link.download = fileName
|
||||
// document.body.appendChild(link)
|
||||
// link.click()
|
||||
// window.setTimeout(function () {
|
||||
// // @ts-ignore
|
||||
// URL.revokeObjectURL(blob)
|
||||
// document.body.removeChild(link)
|
||||
// }, 0)
|
||||
|
||||
// 1. 验证response类型和结构
|
||||
if (!response || typeof response !== "object" || response.size === 0) {
|
||||
useMessage().error("无效的响应数据")
|
||||
return
|
||||
}
|
||||
const link = document.createElement("a")
|
||||
|
||||
// 兼容一下 入参不是 File Blob 类型情况
|
||||
var binaryData = [] as any
|
||||
binaryData.push(response)
|
||||
link.href = window.URL.createObjectURL(new Blob(binaryData))
|
||||
link.download = fileName
|
||||
// 2. 验证blob类型
|
||||
let blob: Blob
|
||||
try {
|
||||
if (response instanceof Blob) {
|
||||
blob = response
|
||||
} else if (response instanceof File) {
|
||||
blob = response
|
||||
} else if (response.data && response.data instanceof Blob) {
|
||||
blob = response.data
|
||||
} else {
|
||||
// 尝试构造安全的blob
|
||||
const safeData = Array.isArray(response) ? response : [response]
|
||||
blob = new Blob(safeData, { type: "application/octet-stream" })
|
||||
}
|
||||
} catch (error) {
|
||||
useMessage().error("文件数据格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 3. 验证文件大小 (防止过大文件)
|
||||
const MAX_FILE_SIZE = 100 * 1024 * 1024 // 100MB限制
|
||||
if (blob.size > MAX_FILE_SIZE) {
|
||||
useMessage().error("文件过大,无法下载")
|
||||
return
|
||||
}
|
||||
|
||||
// 4. 验证文件类型 (白名单)
|
||||
const allowedTypes = [
|
||||
"application/pdf",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"text/plain",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
]
|
||||
|
||||
if (!allowedTypes.includes(blob.type) && blob.type !== "") {
|
||||
useMessage().error("不支持的文件类型")
|
||||
return
|
||||
}
|
||||
|
||||
// 5. 安全的文件下载
|
||||
const link = document.createElement("a")
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = fileName.replace(/[<>:"/\\|?*]/g, "_").substring(0, 255) // 文件名清理,移除危险字符
|
||||
link.style.display = "none" // 隐藏链接
|
||||
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
window.setTimeout(function () {
|
||||
// @ts-ignore
|
||||
URL.revokeObjectURL(blob)
|
||||
document.body.removeChild(link)
|
||||
}, 0)
|
||||
|
||||
// 6. 安全的清理操作
|
||||
setTimeout(() => {
|
||||
try {
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
document.body.removeChild(link)
|
||||
} catch (error) {
|
||||
// 静默处理清理错误
|
||||
}
|
||||
}, 10)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -133,117 +133,117 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="wx-material">
|
||||
import {fetchAccountList} from '/@/api/mp/wx-account';
|
||||
import {useMessage, useMessageBox} from '/@/hooks/message';
|
||||
import {BasicTableProps, useTable} from '/@/hooks/table';
|
||||
import {delObj, getMaterialOther, getMaterialVideo, getPage} from '/@/api/mp/wx-material';
|
||||
import { fetchAccountList } from "/@/api/mp/wx-account"
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||
import { delObj, getMaterialOther, getMaterialVideo, getPage } from "/@/api/mp/wx-material"
|
||||
|
||||
const QueryTree = defineAsyncComponent(() => import('/@/components/QueryTree/index.vue'));
|
||||
const NewsForm = defineAsyncComponent(() => import('./components/news-form.vue'));
|
||||
const WxFileUpload = defineAsyncComponent(() => import('/@/components/Wechat/fileUpload/index.vue'));
|
||||
const WxNews = defineAsyncComponent(() => import('/@/components/Wechat/wx-news/index.vue'));
|
||||
const QueryTree = defineAsyncComponent(() => import("/@/components/QueryTree/index.vue"))
|
||||
const NewsForm = defineAsyncComponent(() => import("./components/news-form.vue"))
|
||||
const WxFileUpload = defineAsyncComponent(() => import("/@/components/Wechat/fileUpload/index.vue"))
|
||||
const WxNews = defineAsyncComponent(() => import("/@/components/Wechat/wx-news/index.vue"))
|
||||
|
||||
const deptData = reactive({
|
||||
queryList: (name?: string) => {
|
||||
return fetchAccountList({
|
||||
name: name,
|
||||
});
|
||||
})
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const checkAppId = ref();
|
||||
const checkAppId = ref()
|
||||
|
||||
const uploadData = ref({
|
||||
appId: '',
|
||||
mediaType: 'image',
|
||||
title: '',
|
||||
introduction: '',
|
||||
});
|
||||
appId: "",
|
||||
mediaType: "image",
|
||||
title: "",
|
||||
introduction: "",
|
||||
})
|
||||
|
||||
const materialType = ref('image');
|
||||
const materialType = ref("image")
|
||||
|
||||
// 点击树
|
||||
const handleNodeClick = (data: any) => {
|
||||
checkAppId.value = data.appid;
|
||||
uploadData.value.appId = data.appid;
|
||||
state.queryForm.appId = data.appid;
|
||||
state.queryForm.type = materialType.value;
|
||||
getDataList();
|
||||
};
|
||||
checkAppId.value = data.appid
|
||||
uploadData.value.appId = data.appid
|
||||
state.queryForm.appId = data.appid
|
||||
state.queryForm.type = materialType.value
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const handleClick = (tab) => {
|
||||
if (checkAppId.value) {
|
||||
// getPage(this.page)
|
||||
} else {
|
||||
useMessage().error('请选择公众号');
|
||||
useMessage().error("请选择公众号")
|
||||
}
|
||||
materialType.value = tab.paneName;
|
||||
uploadData.value.mediaType = tab.paneName;
|
||||
state.queryForm.type = materialType.value;
|
||||
getDataList();
|
||||
};
|
||||
materialType.value = tab.paneName
|
||||
uploadData.value.mediaType = tab.paneName
|
||||
state.queryForm.type = materialType.value
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {
|
||||
appId: '',
|
||||
type: '',
|
||||
appId: "",
|
||||
type: "",
|
||||
},
|
||||
pageList: getPage,
|
||||
createdIsNeed: false,
|
||||
props: {
|
||||
item: 'items',
|
||||
totalCount: 'totalCount',
|
||||
item: "items",
|
||||
totalCount: "totalCount",
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
|
||||
|
||||
const delMaterial = (item: any) => {
|
||||
useMessageBox()
|
||||
.confirm('此操作将永久删除该文件, 是否继续?')
|
||||
.confirm("此操作将永久删除该文件, 是否继续?")
|
||||
.then(() => {
|
||||
delObj({
|
||||
id: item.mediaId,
|
||||
appId: checkAppId.value,
|
||||
})
|
||||
.then(() => {
|
||||
getDataList();
|
||||
getDataList()
|
||||
})
|
||||
.catch((err) => {
|
||||
useMessage().error(err.msg);
|
||||
});
|
||||
});
|
||||
};
|
||||
useMessage().error(err.msg)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 视频
|
||||
|
||||
const dialogVideoVisible = ref(false);
|
||||
const dialogVideoVisible = ref(false)
|
||||
|
||||
const addMaterialLoading = ref(false);
|
||||
const addMaterialLoading = ref(false)
|
||||
|
||||
const handleAddVideo = () => {
|
||||
dialogVideoVisible.value = true;
|
||||
};
|
||||
dialogVideoVisible.value = true
|
||||
}
|
||||
|
||||
const uploadRules = reactive({
|
||||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
||||
introduction: [{ required: true, message: '请输入描述', trigger: 'blur' }],
|
||||
});
|
||||
title: [{ required: true, message: "请输入标题", trigger: "blur" }],
|
||||
introduction: [{ required: true, message: "请输入描述", trigger: "blur" }],
|
||||
})
|
||||
|
||||
const uploadForm = ref();
|
||||
const uploadForm = ref()
|
||||
|
||||
const uploadFileVideo = ref();
|
||||
const uploadFileVideo = ref()
|
||||
|
||||
const subVideo = () => {
|
||||
uploadForm.value.validate((valid: boolean) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
uploadFileVideo.value.submit().then(() => {
|
||||
dialogVideoVisible.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
dialogVideoVisible.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const handleDown = (row: any) => {
|
||||
getMaterialOther({
|
||||
@@ -251,25 +251,25 @@ const handleDown = (row: any) => {
|
||||
fileName: row.name,
|
||||
appId: checkAppId.value,
|
||||
}).then((response) => {
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.style.display = 'none';
|
||||
link.href = url;
|
||||
link.setAttribute('download', row.name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
});
|
||||
};
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]))
|
||||
const link = document.createElement("a")
|
||||
link.style.display = "none"
|
||||
link.href = url
|
||||
link.setAttribute("download", row.name)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
})
|
||||
}
|
||||
|
||||
// 图文
|
||||
|
||||
const dialogNewsRef = ref();
|
||||
const dialogNewsRef = ref()
|
||||
|
||||
const handleAddNews = () => {
|
||||
dialogNewsRef.value.openDialog({
|
||||
accountId: checkAppId.value,
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
const handleEditNews = (item) => {
|
||||
dialogNewsRef.value.openDialog(
|
||||
@@ -278,9 +278,9 @@ const handleEditNews = (item) => {
|
||||
},
|
||||
JSON.parse(JSON.stringify(item.content.newsItem)),
|
||||
item.mediaId,
|
||||
'edit'
|
||||
);
|
||||
};
|
||||
"edit",
|
||||
)
|
||||
}
|
||||
|
||||
const handleInfo = (row) => {
|
||||
getMaterialVideo({
|
||||
@@ -288,21 +288,21 @@ const handleInfo = (row) => {
|
||||
appId: checkAppId.value,
|
||||
})
|
||||
.then((response) => {
|
||||
const downUrl = response.data.downUrl;
|
||||
window.open(downUrl, '_blank');
|
||||
// const downUrl = response.data.downUrl
|
||||
// window.open(downUrl, '_blank');
|
||||
})
|
||||
.catch((err) => {
|
||||
useMessage().error(err.msg);
|
||||
});
|
||||
};
|
||||
useMessage().error(err.msg)
|
||||
})
|
||||
}
|
||||
|
||||
// 默认选择第一个公众号
|
||||
onMounted(async () => {
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
});
|
||||
const { data } = await deptData.queryList()
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0])
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in new issue
Block a user