提交 d4e70689 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 新增日志上送

上级 06d958fd
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.0.6", "@element-plus/icons-vue": "^2.0.6",
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"@types/ua-parser-js": "^0.7.36",
"@vueuse/core": "^9.0.2", "@vueuse/core": "^9.0.2",
"axios": "^0.27.2", "axios": "^0.27.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
"pinia": "^2.0.17", "pinia": "^2.0.17",
"qs": "^6.11.0", "qs": "^6.11.0",
"swiper": "^8.3.2", "swiper": "^8.3.2",
"ua-parser-js": "^1.0.2",
"video.js": "^7.20.1", "video.js": "^7.20.1",
"vue": "^3.2.37", "vue": "^3.2.37",
"vue-router": "^4.1.3" "vue-router": "^4.1.3"
...@@ -272,6 +274,11 @@ ...@@ -272,6 +274,11 @@
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true "dev": true
}, },
"node_modules/@types/ua-parser-js": {
"version": "0.7.36",
"resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz",
"integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ=="
},
"node_modules/@types/video.js": { "node_modules/@types/video.js": {
"version": "7.3.42", "version": "7.3.42",
"resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.42.tgz", "resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.42.tgz",
...@@ -4302,6 +4309,24 @@ ...@@ -4302,6 +4309,24 @@
"node": ">=4.2.0" "node": ">=4.2.0"
} }
}, },
"node_modules/ua-parser-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz",
"integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/ua-parser-js"
},
{
"type": "paypal",
"url": "https://paypal.me/faisalman"
}
],
"engines": {
"node": "*"
}
},
"node_modules/unescape": { "node_modules/unescape": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz", "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz",
...@@ -5011,6 +5036,11 @@ ...@@ -5011,6 +5036,11 @@
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true "dev": true
}, },
"@types/ua-parser-js": {
"version": "0.7.36",
"resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz",
"integrity": "sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ=="
},
"@types/video.js": { "@types/video.js": {
"version": "7.3.42", "version": "7.3.42",
"resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.42.tgz", "resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.42.tgz",
...@@ -7917,6 +7947,11 @@ ...@@ -7917,6 +7947,11 @@
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"devOptional": true "devOptional": true
}, },
"ua-parser-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz",
"integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg=="
},
"unescape": { "unescape": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz", "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz",
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.0.6", "@element-plus/icons-vue": "^2.0.6",
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"@types/ua-parser-js": "^0.7.36",
"@vueuse/core": "^9.0.2", "@vueuse/core": "^9.0.2",
"axios": "^0.27.2", "axios": "^0.27.2",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
"pinia": "^2.0.17", "pinia": "^2.0.17",
"qs": "^6.11.0", "qs": "^6.11.0",
"swiper": "^8.3.2", "swiper": "^8.3.2",
"ua-parser-js": "^1.0.2",
"video.js": "^7.20.1", "video.js": "^7.20.1",
"vue": "^3.2.37", "vue": "^3.2.37",
"vue-router": "^4.1.3" "vue-router": "^4.1.3"
......
import httpRequest from '@/utils/axios'
// https://gitlab.ezijing.com/root/api-documents/-/tree/master/%E6%95%B0%E6%8D%AE%E5%9F%8B%E7%82%B9%E6%9C%8D%E5%8A%A1/api
// 获取Key
export function getPageKey() {
return httpRequest.get('/api/log/api/v1/client/page-key')
}
/**
*
* @param event video_event | courseware_event | lesson_plan_event | file_event | suggestion_event | paper_event
* @param action stu_watch_action | stu_watch_courseware_action | stu_watch_lesson_plan_action | stu_download_file_action | stu_suggestion_action | stu_submit_paper_action
* @param data
*/
export function setMetaInfo(data: { event: string; action: string; data: string }) {
return httpRequest.post('/api/log/api/v1/client/set-meta-info', data)
}
import parser from 'ua-parser-js'
import { useUserStore } from '@/stores/user'
import { getPageKey, setMetaInfo } from '@/api/log'
const userStore = useUserStore()
export function useLog(options?: { hasKey?: boolean }) {
let key = ''
// UA
const userAgent = window.navigator.userAgent
// 解析后的UA
const parsedUserAgent = parser(userAgent)
// 调用时间,一般是页面加载时间
const startTime = Math.floor(Date.now() / 1000)
// 获取Key
const getKey = async () => {
const res = await getPageKey()
key = res.data.key
return key
}
// 上送日志
const upload = async (data: { event: string; action: string; data: Record<string, any> }) => {
if (options?.hasKey && !key) {
await getKey()
}
const OSName = parsedUserAgent.os.name || ''
const defaultData = {
key,
sso_id: userStore.user?.id,
open_browser_time: startTime,
close_browser_time: Math.floor(Date.now() / 1000),
device: ['iOS', 'Android'].includes(OSName) ? OSName : 'PC'
}
return setMetaInfo(Object.assign({}, data, { data: JSON.stringify(Object.assign(defaultData, data.data)) }))
}
return { userAgent, parsedUserAgent, key, upload, getKey }
}
...@@ -7,6 +7,9 @@ import { cachePaper, submitPaper } from '../api' ...@@ -7,6 +7,9 @@ import { cachePaper, submitPaper } from '../api'
import CourseExamQuestion from './CourseExamQuestion.vue' import CourseExamQuestion from './CourseExamQuestion.vue'
import CourseExamQuestionNumbers from './CourseExamQuestionNumbers.vue' import CourseExamQuestionNumbers from './CourseExamQuestionNumbers.vue'
import { useLog } from '@/composables/useLog'
const log = useLog()
interface Props { interface Props {
status: number status: number
title?: string title?: string
...@@ -106,6 +109,12 @@ function handleSubmitPaper() { ...@@ -106,6 +109,12 @@ function handleSubmitPaper() {
.catch(() => { .catch(() => {
submitLoading = false submitLoading = false
}) })
// 日志上送
log.upload({
event: 'paper_event',
action: 'stu_submit_paper_action',
data: { course_id: courseId, paper_id: paperId, section_id: 0, commit_time: Math.floor(Date.now() / 1000) }
})
} }
// 提交缓存试卷 // 提交缓存试卷
function handleSubmitCachePaper() { function handleSubmitCachePaper() {
......
...@@ -7,6 +7,9 @@ import { Download } from '@element-plus/icons-vue' ...@@ -7,6 +7,9 @@ import { Download } from '@element-plus/icons-vue'
import { saveAs } from 'file-saver' import { saveAs } from 'file-saver'
import { collectionResource } from '../api' import { collectionResource } from '../api'
import { useLog } from '@/composables/useLog'
const log = useLog()
const { query } = useRoute() const { query } = useRoute()
const courseId = $ref(query.course_id as string) const courseId = $ref(query.course_id as string)
const chapterId = $ref(query.chapter_id as string) const chapterId = $ref(query.chapter_id as string)
...@@ -25,10 +28,8 @@ const targetUrl = computed(() => { ...@@ -25,10 +28,8 @@ const targetUrl = computed(() => {
return `/course/exam?course_id=${courseId}&semester_id=${semesterId}&paper_id=${props.data.resource_id}&type=2&paper_title=${props.data.name}` return `/course/exam?course_id=${courseId}&semester_id=${semesterId}&paper_id=${props.data.resource_id}&type=2&paper_title=${props.data.name}`
} else if (props.data.resource_type === 6) { } else if (props.data.resource_type === 6) {
return info.join_url return info.join_url
} else if (['pptx', 'doc', 'docx', 'xls', 'xlsx'].includes(info.type)) {
return `https://view.officeapps.live.com/op/view.aspx?src=${info.url}`
} else { } else {
return info.url return `/preview?course_id=${courseId}&semester_id=${semesterId}&resource_id=${props.data.resource_id}&resource_type=${props.data.resource_type}&url=${info.url}`
} }
}) })
// 是否可以收藏 // 是否可以收藏
...@@ -64,6 +65,20 @@ function downloadFile(data: CourseResourceType) { ...@@ -64,6 +65,20 @@ function downloadFile(data: CourseResourceType) {
const nameExtensionName = name?.split('.').pop() const nameExtensionName = name?.split('.').pop()
const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}` const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}`
url && saveAs(url, filename) url && saveAs(url, filename)
// 日志上送
log.upload({
event: 'file_event',
action: 'stu_download_file_action',
data: {
course_id: courseId,
resource_id: data.info.id,
resource_type: data.resource_type,
download_time: Math.floor(Date.now() / 1000),
download_name: name,
download_size: data.info.size
}
})
} }
</script> </script>
......
...@@ -7,6 +7,8 @@ import { Swiper, SwiperSlide } from 'swiper/vue' ...@@ -7,6 +7,8 @@ import { Swiper, SwiperSlide } from 'swiper/vue'
import 'swiper/css' import 'swiper/css'
import AppVideoPlayer from '@/components/base/AppVideoPlayer.vue' import AppVideoPlayer from '@/components/base/AppVideoPlayer.vue'
import { getCoursePlayInfo, getVideoRecords, uploadVideoRecords } from '../api' import { getCoursePlayInfo, getVideoRecords, uploadVideoRecords } from '../api'
import { useLog } from '@/composables/useLog'
const log = useLog({ hasKey: true })
interface Props { interface Props {
chapterList: CourseChapterType[] chapterList: CourseChapterType[]
...@@ -137,6 +139,9 @@ async function fetchVideoRecords() { ...@@ -137,6 +139,9 @@ async function fetchVideoRecords() {
progress.valid_playing_time = detail.valid_playing_time ? parseFloat(detail.valid_playing_time) : 0 progress.valid_playing_time = detail.valid_playing_time ? parseFloat(detail.valid_playing_time) : 0
progress.watchedTimePoint = [] progress.watchedTimePoint = []
console.log('info', progress.current_playing_time) console.log('info', progress.current_playing_time)
// 日志相关
pageLoadedTime = Math.floor(Date.now() / 1000)
log.getKey()
} }
watchEffect(async () => { watchEffect(async () => {
if (!resource) return if (!resource) return
...@@ -185,10 +190,31 @@ const throttledFn = throttle( ...@@ -185,10 +190,31 @@ const throttledFn = throttle(
}) })
// 清空已经上传过的观看时间点 // 清空已经上传过的观看时间点
progress.watchedTimePoint = [] progress.watchedTimePoint = []
// 日志上送
logUpload()
}, },
5000 5000
// { leading: false } // { leading: false }
) )
// 页面初始化完成的时间
let pageLoadedTime = Math.floor(Date.now() / 1000)
// 日志上送
function logUpload() {
if (!videoJsPlayer) return
// 日志上送
log.upload({
event: 'video_event',
action: 'stu_watch_action',
data: {
course_id: courseId,
resource_id: resourceId,
page_dwell_time: Math.floor(Date.now() / 1000) - pageLoadedTime,
resource_progress: Math.min(Math.floor((progress.valid_playing_time / videoJsPlayer?.duration()) * 100), 100)
}
})
}
// 视频加载完成 // 视频加载完成
function onLoadedData() { function onLoadedData() {
console.log('onLoadedData') console.log('onLoadedData')
...@@ -215,15 +241,19 @@ function onTimeUpdate() { ...@@ -215,15 +241,19 @@ function onTimeUpdate() {
throttledFn() throttledFn()
} }
let nextTimer = 0
// 播放结束 // 播放结束
function onEnded() { function onEnded() {
console.log('onEnd') console.log('onEnd')
throttledFn && throttledFn.flush() throttledFn && throttledFn.flush()
// 自动播放下一个视频 // 3秒后自动播放下一个视频
if (isAutoPlayNext) { if (isAutoPlayNext) {
const currentIndex = sectionVideoList.findIndex(item => item.resource_id === resourceId) nextTimer && window.clearTimeout(nextTimer)
const next = sectionVideoList[currentIndex + 1] nextTimer = window.setTimeout(() => {
next && changeResource(next) const currentIndex = sectionVideoList.findIndex(item => item.resource_id === resourceId)
const next = sectionVideoList[currentIndex + 1]
next && changeResource(next)
}, 1000 * 3)
} }
} }
function onSeeked() { function onSeeked() {
......
...@@ -9,6 +9,9 @@ import { formatLiveDate, formatLiveStatus } from '@/utils/index' ...@@ -9,6 +9,9 @@ import { formatLiveDate, formatLiveStatus } from '@/utils/index'
import { getChapterTreeList, collectionResource } from '../api' import { getChapterTreeList, collectionResource } from '../api'
import { useLog } from '@/composables/useLog'
const log = useLog()
let chapterList = $ref<CourseChapterType[]>([]) let chapterList = $ref<CourseChapterType[]>([])
const { query } = useRoute() const { query } = useRoute()
const courseId = $ref(query.course_id as string) const courseId = $ref(query.course_id as string)
...@@ -75,9 +78,7 @@ function toggleCollection(resource: CourseResourceType, section: CourseSectionTy ...@@ -75,9 +78,7 @@ function toggleCollection(resource: CourseResourceType, section: CourseSectionTy
} }
// 是否可以下载 // 是否可以下载
function canDownload(type: number) { function canDownload(type: number) {
// 没有url return [4, 10, 11].includes(type)
// return [4, 10, 11].includes(type)
return [99999].includes(type)
} }
// 下载资源 // 下载资源
function downloadFile(data: CourseResourceType) { function downloadFile(data: CourseResourceType) {
...@@ -86,6 +87,20 @@ function downloadFile(data: CourseResourceType) { ...@@ -86,6 +87,20 @@ function downloadFile(data: CourseResourceType) {
const nameExtensionName = name?.split('.').pop() const nameExtensionName = name?.split('.').pop()
const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}` const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}`
url && saveAs(url, filename) url && saveAs(url, filename)
// 日志上送
log.upload({
event: 'file_event',
action: 'stu_download_file_action',
data: {
course_id: courseId,
resource_id: data.info.id,
resource_type: data.resource_type,
download_time: Math.floor(Date.now() / 1000),
download_name: name,
download_size: data.info.size
}
})
} }
// 跳转链接 // 跳转链接
function targetUrl(resource: CourseResourceType, section: CourseSectionType, chapter: CourseChapterType) { function targetUrl(resource: CourseResourceType, section: CourseSectionType, chapter: CourseChapterType) {
...@@ -174,7 +189,7 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha ...@@ -174,7 +189,7 @@ function targetUrl(resource: CourseResourceType, section: CourseSectionType, cha
min-width: 60px; min-width: 60px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: space-between;
line-height: 1; line-height: 1;
&:empty { &:empty {
min-width: auto; min-width: auto;
......
...@@ -4,9 +4,11 @@ import ResourceIcon from '@/components/ResourceIcon.vue' ...@@ -4,9 +4,11 @@ import ResourceIcon from '@/components/ResourceIcon.vue'
import { Download } from '@element-plus/icons-vue' import { Download } from '@element-plus/icons-vue'
import { saveAs } from 'file-saver' import { saveAs } from 'file-saver'
import format from 'format-duration' import format from 'format-duration'
import { getCollectionList, getCourseList, collectionResource } from '../api' import { getCollectionList, getCourseList, collectionResource } from '../api'
import { useLog } from '@/composables/useLog'
const log = useLog()
const tabs = $ref([ const tabs = $ref([
{ label: '全部', value: '' }, { label: '全部', value: '' },
{ label: '视频', value: '2' }, { label: '视频', value: '2' },
...@@ -82,6 +84,20 @@ function downloadFile(data: CollectionType) { ...@@ -82,6 +84,20 @@ function downloadFile(data: CollectionType) {
const nameExtensionName = name?.split('.').pop() const nameExtensionName = name?.split('.').pop()
const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}` const filename = nameExtensionName === urlExtensionName ? name : `${name}.${urlExtensionName}`
url && saveAs(url, filename) url && saveAs(url, filename)
// 日志上送
log.upload({
event: 'file_event',
action: 'stu_download_file_action',
data: {
course_id: data.course_id,
resource_id: data.info.id,
resource_type: data.resource_type,
download_time: Math.floor(Date.now() / 1000),
download_name: name,
download_size: data.info.size
}
})
} }
function targetUrl(item: CollectionType) { function targetUrl(item: CollectionType) {
if (item.type === 5) { if (item.type === 5) {
......
import type { RouteRecordRaw } from 'vue-router'
export const routes: Array<RouteRecordRaw> = [
{
path: '/preview',
component: () => import('./views/Index.vue')
}
]
<script setup lang="ts">
import { useLog } from '@/composables/useLog'
const log = useLog({ hasKey: true })
const route = useRoute()
const courseId = $ref(route.query.course_id as string)
const resourceId = $ref(route.query.resource_id as string)
const resourceType = $ref(route.query.resource_type as string)
const url = $ref(route.query.url as string)
// 文件扩展名
const fileExtensionName = $computed(() => {
return url?.split('.').pop() || ''
})
const officeUrl = $computed(() => {
if (['pptx', 'doc', 'docx', 'xls', 'xlsx'].includes(fileExtensionName)) {
return `https://view.officeapps.live.com/op/view.aspx?src=${url}`
} else {
return ''
}
})
// 日志事件
const logEvent = $computed(() => {
// 其他资料
if (resourceType === '4') {
return { event: 'other_infos', action: 'stu_watch_other_infos' }
}
// 课件
if (resourceType === '10') {
return { event: 'courseware_event', action: 'stu_watch_courseware_action' }
}
// 教案
if (resourceType === '11') {
return { event: 'lesson_plan_event', action: 'stu_watch_lesson_plan_action' }
}
})
// 页面初始化完成的时间
const pageLoadedTime = Math.floor(Date.now() / 1000)
// 日志上送
function logUpload() {
if (!logEvent) return
console.log('logUpload')
log.upload({
event: logEvent.event,
action: logEvent.action,
data: {
course_id: courseId,
resource_id: resourceId,
page_dwell_time: Math.floor(Date.now() / 1000) - pageLoadedTime,
resource_progress: 100
}
})
}
let logTimer = 0
onMounted(() => {
// 日志上送
logUpload()
// 10秒上送一次
logTimer = window.setInterval(() => {
logUpload()
}, 1000 * 10)
})
onUnmounted(() => {
logTimer && window.clearInterval(logTimer)
})
</script>
<template>
<div style="width: 100%; height: 100vh; overflow: hidden">
<iframe :src="officeUrl" frameborder="0" style="width: 100%; height: 100vh" v-if="officeUrl"></iframe>
<object :data="url" style="width: 100%; height: 100vh; object-fit: none" v-else></object>
</div>
</template>
...@@ -4,6 +4,8 @@ import AppUpload from '@/components/base/AppUpload.vue' ...@@ -4,6 +4,8 @@ import AppUpload from '@/components/base/AppUpload.vue'
import AppEditor from '@/components/base/AppEditor.vue' import AppEditor from '@/components/base/AppEditor.vue'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import { submitSuggestion } from '../api' import { submitSuggestion } from '../api'
import { useLog } from '@/composables/useLog'
const log = useLog()
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update'): void
...@@ -31,6 +33,12 @@ const update = () => { ...@@ -31,6 +33,12 @@ const update = () => {
emit('update') emit('update')
formRef?.resetFields() formRef?.resetFields()
}) })
// 日志上送
log.upload({
event: 'suggestion_event',
action: 'stu_suggestion_action',
data: { commit_time: Math.floor(Date.now() / 1000) }
})
} }
</script> </script>
......
...@@ -15,7 +15,7 @@ httpRequest.interceptors.request.use( ...@@ -15,7 +15,7 @@ httpRequest.interceptors.request.use(
function (config) { function (config) {
// 权限接口单独签名 // 权限接口单独签名
// https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md // https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md
if (config.url && /^\/api\/learn/.test(config.url)) { if (config.url && /^\/api\/learn|^\/api\/log/.test(config.url)) {
// 默认参数 // 默认参数
const defaultHeaders = { const defaultHeaders = {
timestamp: Date.now(), timestamp: Date.now(),
......
...@@ -30,6 +30,11 @@ export default defineConfig(({ mode }) => ({ ...@@ -30,6 +30,11 @@ export default defineConfig(({ mode }) => ({
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem')) cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
}, },
proxy: { proxy: {
'/api/log': {
target: 'http://api.ezijing.com:9501',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\/log/, '')
},
'/api': 'https://saas-learn.ezijing.com' '/api': 'https://saas-learn.ezijing.com'
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论