Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
new-socketemulator
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李远洪
new-socketemulator
Commits
3edd93c9
Commit
3edd93c9
authored
Mar 05, 2020
by
liyuanhong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
并发线程脚本开发完成
parent
634a7493
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
191 additions
and
46 deletions
+191
-46
README.md
README.md
+22
-1
doc/img/m500_1.png
doc/img/m500_1.png
+0
-0
doc/img/new_hard_1.png
doc/img/new_hard_1.png
+0
-0
doc/lib_details.md
doc/lib_details.md
+2
-0
lib/multiThread/SendMultMsgThread_m500.py
lib/multiThread/SendMultMsgThread_m500.py
+153
-33
lib/protocol/ProtocolBase.py
lib/protocol/ProtocolBase.py
+6
-4
lib/util/dataUtil.py
lib/util/dataUtil.py
+6
-6
templates/base.html
templates/base.html
+2
-2
No files found.
README.md
View file @
3edd93c9
# 模拟程序说明文档
# 模拟程序说明文档
#### (一)、框架结构说明
#### (一)、框架结构说明
config:存放项目配置文件
dada:存放项目需要的数据和产生的数据
doc:项目帮助文档,markdown格式编写
img:存放项目需要的图片资源
lib:车机协议实现的类,以及各种业务逻辑
log:项目运行日志文件
static:存放网页端图形操作界面的静态文件,包含:js,css,图片等
templates:存放网页模板文件 html
views:存放网页端操作的后台处理逻辑,以及页面的展示逻辑
run.py:启动项目图形操作界面主程序,访问:127.0.0.1:5000 即可
requirements.txt:设置项目需要的依赖库
### (二)、文档目录
[
1、lib使用库说明
](
doc/lib_details.md
)
[
2、如何使用web图形操作界面
](
https://www.baidu.com/
)
### (三)、图形界面展示
#### m500操作界面:
![
alt text
](
doc/img/m500_1.png
"Title Text"
)
#### 车安优操作界面:
![
alt text
](
doc/img/new_hard_1.png
"Title Text"
)
\ No newline at end of file
doc/img/m500_1.png
0 → 100644
View file @
3edd93c9
84.9 KB
doc/img/new_hard_1.png
0 → 100644
View file @
3edd93c9
113 KB
doc/lib_details.md
0 → 100644
View file @
3edd93c9
# lib库使用说明
### (一)、lib库目录结构
lib/multiThread/SendMultMsgThread_m500.py
View file @
3edd93c9
#coding:utf-8
#coding:utf-8
import
binascii
import
binascii
import
json
import
json
import
random
import
socket
import
socket
import
threading
import
threading
import
time
import
time
from
random
import
random
from
lib.multiThread.ThreadBase
import
ThreadBase
from
lib.multiThread.ThreadBase
import
ThreadBase
from
lib.protocol.message.Location_msg
import
Location_msg
from
lib.protocol.message.Location_msg
import
Location_msg
...
@@ -16,12 +16,18 @@ class SendMultMsgThread():
...
@@ -16,12 +16,18 @@ class SendMultMsgThread():
self
.
host
=
host
self
.
host
=
host
self
.
port
=
port
self
.
port
=
port
self
.
msg
=
msg
self
.
msg
=
msg
self
.
timeOut
=
1
#socket超时时间
self
.
timeOut
=
60
#socket超时时间
self
.
BUF_SIZE
=
1024
#接收消息缓存
self
.
BUF_SIZE
=
1024
#接收消息缓存
self
.
threadCount
=
1
0
#并发线程数
self
.
threadCount
=
500
0
#并发线程数
self
.
totalTime
=
0
#所有线程的运行总和
self
.
totalTime
=
0
#所有线程的运行总和
self
.
threadArr
=
{}
#保存每个线程的信息
self
.
threadArr
=
{}
#保存每个线程的信息
self
.
failThreadCount
=
0
#失败线程数
self
.
failThreadCount
=
0
#失败线程数
self
.
durThreads
=
[]
#持续发送线程数组,当数组为空,表示所有线程已经结束
self
.
durTime
=
60
#线程持续时间
self
.
connectTimeoutNum
=
0
#连接超时线程数
self
.
sendTimeoutNum
=
0
#发送超时线程数
self
.
reviceTimeoutNum
=
0
#接收超时线程数
self
.
sucessNum
=
0
#成功线程数
pass
pass
############################################
############################################
...
@@ -82,9 +88,66 @@ class SendMultMsgThread():
...
@@ -82,9 +88,66 @@ class SendMultMsgThread():
############################################
############################################
# 持续发送消息
# 持续发送消息
# dur: 持续发送时间,如果为0一直发送, 设置了事件为持续发送多少秒,默认为一分钟
############################################
############################################
def
sendMsgContinuous
(
self
):
def
sendMsgContinuous
(
self
,
carId
,
threadName
=
"thread0"
):
pass
client
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
client
.
setsockopt
(
socket
.
SOL_SOCKET
,
socket
.
SO_KEEPALIVE
,
1
)
# 在客户端开启心跳
client
.
settimeout
(
self
.
timeOut
)
startTime
=
int
(
time
.
time
())
endTime
=
int
(
time
.
time
())
self
.
durThreads
.
append
(
threadName
)
try
:
client
.
connect
((
self
.
host
,
self
.
port
))
except
BaseException
as
e
:
client
.
close
()
self
.
durThreads
.
remove
(
threadName
)
self
.
threadArr
[
threadName
][
"status"
]
=
1
self
.
failThreadCount
=
self
.
failThreadCount
+
1
endTime
=
int
(
time
.
time
())
timeExpend
=
endTime
-
startTime
self
.
threadArr
[
threadName
][
"timeExp"
]
=
timeExpend
self
.
connectTimeoutNum
=
self
.
connectTimeoutNum
+
1
print
(
threadName
+
":"
+
"连接超时,socket断开"
)
return
while
(
endTime
-
startTime
)
<
self
.
durTime
:
msg
=
self
.
getRandomMsg
(
carId
)
try
:
client
.
send
(
binascii
.
a2b_hex
(
msg
))
except
BaseException
as
e
:
client
.
close
()
self
.
durThreads
.
remove
(
threadName
)
self
.
threadArr
[
threadName
][
"status"
]
=
1
self
.
failThreadCount
=
self
.
failThreadCount
+
1
endTime
=
int
(
time
.
time
())
timeExpend
=
endTime
-
startTime
self
.
threadArr
[
threadName
][
"timeExp"
]
=
timeExpend
self
.
sendTimeoutNum
=
self
.
sendTimeoutNum
+
1
print
(
threadName
+
":"
+
"发送超时,socket断开"
)
return
try
:
data
=
client
.
recv
(
self
.
BUF_SIZE
)
except
BaseException
as
e
:
client
.
close
()
self
.
durThreads
.
remove
(
threadName
)
self
.
threadArr
[
threadName
][
"status"
]
=
1
self
.
failThreadCount
=
self
.
failThreadCount
+
1
self
.
reviceTimeoutNum
=
self
.
connectTimeoutNum
+
1
print
(
threadName
+
":"
+
'socket 接收消息超时!'
)
endTime
=
int
(
time
.
time
())
timeExpend
=
endTime
-
startTime
self
.
threadArr
[
threadName
][
"timeExp"
]
=
timeExpend
return
endTime
=
int
(
time
.
time
())
sleepTime
=
random
.
randint
(
1
,
5
)
time
.
sleep
(
sleepTime
)
endTime
=
int
(
time
.
time
())
timeExpend
=
endTime
-
startTime
self
.
threadArr
[
threadName
][
"timeExp"
]
=
timeExpend
client
.
close
()
self
.
sucessNum
=
self
.
sucessNum
+
1
self
.
durThreads
.
remove
(
threadName
)
############################################
############################################
# 启动并发线程
# 启动并发线程
...
@@ -92,8 +155,7 @@ class SendMultMsgThread():
...
@@ -92,8 +155,7 @@ class SendMultMsgThread():
def
startThread
(
self
):
def
startThread
(
self
):
timeStart
=
int
(
time
.
time
()
*
1000
)
timeStart
=
int
(
time
.
time
()
*
1000
)
for
i
in
range
(
0
,
self
.
threadCount
):
for
i
in
range
(
0
,
self
.
threadCount
):
threadName
=
"thread"
+
str
(
i
)
threadName
=
"thread-"
+
str
(
i
)
carid
=
201912000000
+
i
theThread
=
threading
.
Thread
(
target
=
self
.
sendMsg
,
args
=
(
"7e0002000001314620111800065b7e"
,
threadName
,))
# 数据写死,心跳
theThread
=
threading
.
Thread
(
target
=
self
.
sendMsg
,
args
=
(
"7e0002000001314620111800065b7e"
,
threadName
,))
# 数据写死,心跳
threadInfo
=
{}
threadInfo
=
{}
threadInfo
[
"name"
]
=
threadName
threadInfo
[
"name"
]
=
threadName
...
@@ -102,7 +164,7 @@ class SendMultMsgThread():
...
@@ -102,7 +164,7 @@ class SendMultMsgThread():
theThread
.
start
()
theThread
.
start
()
timeEnd
=
int
(
time
.
time
()
*
1000
)
timeEnd
=
int
(
time
.
time
()
*
1000
)
timeExpend
=
timeEnd
-
timeStart
timeExpend
=
timeEnd
-
timeStart
time
.
sleep
(
20
)
time
.
sleep
(
3
)
print
(
"耗时:"
+
str
(
timeExpend
)
+
" 毫秒"
)
print
(
"耗时:"
+
str
(
timeExpend
)
+
" 毫秒"
)
print
(
"并发数据每秒发送:"
+
str
(
int
(
self
.
threadCount
/
(
timeExpend
/
1000
))))
print
(
"并发数据每秒发送:"
+
str
(
int
(
self
.
threadCount
/
(
timeExpend
/
1000
))))
print
(
"平均响应时间:"
+
str
(
self
.
totalTime
/
self
.
threadCount
)
+
"毫秒"
)
print
(
"平均响应时间:"
+
str
(
self
.
totalTime
/
self
.
threadCount
)
+
"毫秒"
)
...
@@ -110,6 +172,38 @@ class SendMultMsgThread():
...
@@ -110,6 +172,38 @@ class SendMultMsgThread():
print
(
"响应失败数:"
+
str
(
self
.
failThreadCount
))
print
(
"响应失败数:"
+
str
(
self
.
failThreadCount
))
self
.
writeToFile
(
"../../data/threadDetails.json"
,
self
.
threadArr
)
self
.
writeToFile
(
"../../data/threadDetails.json"
,
self
.
threadArr
)
############################################
# 启动持续并发线程
############################################
def
startThreadContinuous
(
self
):
timeStart
=
int
(
time
.
time
()
*
1000
)
for
i
in
range
(
0
,
self
.
threadCount
):
threadName
=
"thread-"
+
str
(
i
)
print
(
threadName
)
carid
=
201912000000
+
i
theThread
=
threading
.
Thread
(
target
=
self
.
sendMsgContinuous
,
args
=
(
carid
,
threadName
,))
# 数据写死,心跳
threadInfo
=
{}
threadInfo
[
"name"
]
=
threadName
threadInfo
[
"status"
]
=
0
self
.
threadArr
[
threadName
]
=
threadInfo
theThread
.
start
()
timeEnd
=
int
(
time
.
time
()
*
1000
)
timeExpend
=
timeEnd
-
timeStart
print
(
"耗时:"
+
str
(
timeExpend
)
+
" 毫秒产生了"
+
str
(
self
.
threadCount
)
+
"线程"
)
while
len
(
self
.
durThreads
)
!=
0
:
print
(
"剩余线程数:"
+
str
(
len
(
self
.
durThreads
)))
time
.
sleep
(
5
)
print
(
"-------------------------- 统计信息 --------------------------"
)
print
(
"耗时:"
+
str
(
timeExpend
)
+
" 毫秒产生了"
+
str
(
self
.
threadCount
)
+
"线程"
)
print
(
"设置socket超时时间:"
+
str
(
self
.
timeOut
))
print
(
"设置线程持续时间:"
+
str
(
self
.
durTime
))
print
(
"成功线程数:"
+
str
(
self
.
sucessNum
))
print
(
"连接失败:"
+
str
(
self
.
connectTimeoutNum
))
print
(
"发送失败:"
+
str
(
self
.
sendTimeoutNum
))
print
(
"接收失败:"
+
str
(
self
.
reviceTimeoutNum
))
self
.
writeToFile
(
"../../data/threadDetailsContinuous.json"
,
self
.
threadArr
)
def
writeToFile
(
self
,
path
,
data
):
def
writeToFile
(
self
,
path
,
data
):
with
open
(
path
,
"w"
,
encoding
=
'utf-8'
)
as
fi
:
with
open
(
path
,
"w"
,
encoding
=
'utf-8'
)
as
fi
:
json
.
dump
(
data
,
fi
)
json
.
dump
(
data
,
fi
)
...
@@ -117,39 +211,65 @@ class SendMultMsgThread():
...
@@ -117,39 +211,65 @@ class SendMultMsgThread():
#获取随机消息数据
#获取随机消息数据
def
getRandomMsg
(
self
,
carId
):
def
getRandomMsg
(
self
,
carId
):
#
cari
d = 201912010002
#
carI
d = 201912010002
wh
=
random
.
randint
(
0
,
3
)
wh
=
random
.
randint
(
0
,
2
)
msg
=
""
msg
=
""
if
wh
==
0
:
if
wh
==
0
:
hearbeat_msg
=
"4040000b000c4d"
+
carId
+
"0003b59f"
hearbeat_msg
=
"4040000e00044d"
+
str
(
carId
)
+
"8000000300cf91"
hearbeat_msg
=
hearbeat_msg
[:
-
4
]
+
self
.
crc16
(
hearbeat_msg
[:
-
4
])
msg
=
hearbeat_msg
msg
=
hearbeat_msg
elif
wh
==
1
:
elif
wh
==
1
:
GPS_msg
=
"4040003d000e4d"
+
carId
+
"0010011403040a0e0501c329ed0659dec501f402e8000000b4050a0b0c9305050258001400000fa0000000005e5f68e75e5f7f6d9ec9"
GPS_msg
=
"4040003d00054d"
+
str
(
carId
)
+
"001001140305031e0301c329ed0659dec501f402e8000000b4050a0b0c9305050258001400000fa0000000005e606f115e60723be44b"
GPS_msg
=
GPS_msg
[:
-
4
]
+
self
.
crc16
(
GPS_msg
[:
-
4
])
msg
=
GPS_msg
msg
=
GPS_msg
elif
wh
==
2
:
elif
wh
==
2
:
OBD_msg
=
"4040007000034d"
+
carId
+
"0012011403040a101b26d7fffff0000000000505000000143c00000bb80100000fa00000000a000000000000000003e803e839331e100055320000001312001007d0001e0000000000000096000000280096ffff3e0001f40000003e00000000000000000000006487"
OBD_msg
=
"4040007000064d"
+
str
(
carId
)
+
"00120114030503202d26d7fffff0000000000505000000143c00000bb80100000fa00000000a0000000000005e60723b723b39331e100055320000001312001007d0001e0000000000000096000000280096ffff3e0001f40000003e00000000000000000000007213"
OBD_msg
=
OBD_msg
[:
-
4
]
+
self
.
crc16
(
OBD_msg
[:
-
4
])
msg
=
OBD_msg
msg
=
OBD_msg
return
msg
return
msg
if
__name__
==
"__main__"
:
####################################################
t
=
SendMultMsgThread
()
# 定义生成校验字段的函数
# t.setMsg("7e0002000001314620111800065b7e")
# inputStr:需要传入一个已经转换为16进制的字符串
# t.setMsg("7e020001020131462011190001fffc7fff001c010401c0a6380659ad7a02090042003b200204185704310102EA6600010400000000000204001e7c1f0003050A0001f400000405020001d4c000050400057d0240000604000119400007040007530000100c0004006403f203f203f203f2001114ffffffffffffffffffff00200000000000000000001202002400130106001D0101EB7960C0020bb860D0013c62f00203216050014c60F0015860B001146330011c646001416490012060A00201146014010160100102610002022661100201f561F0020e746210040000119c6040012c60700200e660E00203206701010067020100670301016704024e20670502000067060200416707040000017d02097e")
#####################################################
t
.
startThread
()
# add crc 16 check at the end of the string
def
crc16
(
self
,
inputStr
):
inputStrByte
=
bytes
.
fromhex
(
inputStr
)
crc
=
0xFFFF
for
i
in
range
(
0
,
len
(
inputStrByte
)):
for
j
in
range
(
0
,
8
):
c15
=
(
crc
>>
15
)
==
1
bit
=
((
inputStrByte
[
i
]
>>
(
7
-
j
))
&
1
)
==
1
crc
<<=
1
crc
&=
0xFFFF
if
c15
^
bit
:
crc
^=
0x1021
crc
=
str
(
hex
(
crc
))
crc
=
self
.
leftPad
(
crc
[
2
:],
4
)
# outputStr = inputStr + crc
outputStr
=
crc
return
outputStr
# pad zero to the left of the string if not long enough
def
leftPad
(
self
,
inputStr
,
strLen
):
if
(
strLen
>
len
(
inputStr
)):
outputStr
=
"0000000000000000000000000000000000000000"
+
inputStr
outputStr
=
outputStr
[
len
(
outputStr
)
-
strLen
:]
return
outputStr
else
:
return
inputStr
# pad zero to the right of the string if not long enough
def
rightPad
(
self
,
inputStr
,
strLen
):
if
(
strLen
>
len
(
inputStr
)):
outputStr
=
inputStr
+
"0000000000000000000000000000000000000000"
outputStr
=
outputStr
[:
strLen
]
return
outputStr
else
:
return
inputStr
if
__name__
==
"__main__"
:
t
=
SendMultMsgThread
()
t
.
setHost
(
"10.100.12.32"
)
t
.
setPort
(
9008
)
# t.startThread()
t
.
startThreadContinuous
()
\ No newline at end of file
lib/protocol/ProtocolBase.py
View file @
3edd93c9
...
@@ -88,7 +88,7 @@ class ProtocolBase(Base):
...
@@ -88,7 +88,7 @@ class ProtocolBase(Base):
#####################################################
#####################################################
# 将字符串转换为对应的ascii值数组
# 将字符串转换为对应的ascii值数组
#####################################################
#####################################################
def
str2Ascsii
(
s
):
def
str2Ascsii
(
s
elf
,
s
):
asciiArr
=
[]
asciiArr
=
[]
for
i
in
range
(
0
,
len
(
s
)):
for
i
in
range
(
0
,
len
(
s
)):
asciiValue
=
ord
(
s
[
i
])
asciiValue
=
ord
(
s
[
i
])
...
@@ -194,6 +194,8 @@ if __name__ == "__main__":
...
@@ -194,6 +194,8 @@ if __name__ == "__main__":
# print(ProtocolBase().str2Hex("a"))
# print(ProtocolBase().str2Hex("a"))
# print(ProtocolBase().int2hexStringByBytes(1,6))
# print(ProtocolBase().int2hexStringByBytes(1,6))
# print(ProtocolBase().num2signedNum(-5))
# print(ProtocolBase().num2signedNum(-5))
print
(
ProtocolBase
()
.
getUTCTimeHex
(
"2020-01-03 13:05:13"
))
# print(ProtocolBase().getUTCTimeHex("2020-01-03 13:05:13"))
print
(
ProtocolBase
()
.
hex2UTCTime
(
"1401030d050d"
))
# print(ProtocolBase().hex2UTCTime("1401030d050d"))
print
(
ProtocolBase
()
.
hex2UTCTime
(
"14020a07122b"
))
# print(ProtocolBase().hex2UTCTime("14020a07122b"))
print
(
ProtocolBase
()
.
crc16
(
"4040007000064d20191201000200120114030503202d26d7fffff0000000000505000000143c00000bb80100000fa00000000a0000000000005e60723b723b39331e100055320000001312001007d0001e0000000000000096000000280096ffff3e0001f40000003e0000000000000000000000"
))
print
(
ProtocolBase
()
.
myCrc16
(
"4040007000064d20191201000200120114030503202d26d7fffff0000000000505000000143c00000bb80100000fa00000000a0000000000005e60723b723b39331e100055320000001312001007d0001e0000000000000096000000280096ffff3e0001f40000003e0000000000000000000000"
))
lib/util/dataUtil.py
View file @
3edd93c9
...
@@ -100,9 +100,9 @@ def str2Ascsii(s):
...
@@ -100,9 +100,9 @@ def str2Ascsii(s):
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
print
(
crc16
(
str2Hex
(
"aa"
)))
#
print(crc16(str2Hex("aa")))
print
(
str2Hex
(
"aa"
))
#
print(str2Hex("aa"))
print
(
str2HexStrip
(
"aa"
))
#
print(str2HexStrip("aa"))
print
(
str2Ascsii
(
"aa"
))
#
print(str2Ascsii("aa"))
print
(
myCrc16
(
"
aa
"
))
print
(
myCrc16
(
"
4040007000064d20191201000200120114030503202d26d7fffff0000000000505000000143c00000bb80100000fa00000000a0000000000005e60723b723b39331e100055320000001312001007d0001e0000000000000096000000280096ffff3e0001f40000003e0000000000000000000000
"
))
print
(
crc16
(
str2HexStrip
(
"aa"
)))
#
print(crc16(str2HexStrip("aa")))
templates/base.html
View file @
3edd93c9
...
@@ -19,8 +19,8 @@
...
@@ -19,8 +19,8 @@
<div
style=
"background:#222222;height:50px;"
></div>
<div
style=
"background:#222222;height:50px;"
></div>
<div
style=
"width: 70%;margin: 0 auto"
>
<div
style=
"width: 70%;margin: 0 auto"
>
<ul
class=
"nav nav-tabs"
style=
"font-size:18px;"
>
<ul
class=
"nav nav-tabs"
style=
"font-size:18px;"
>
<li
role=
"presentation"
{%
if
arg.path[0]=
="protocolTools"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"protocolTools"
>
协议工具
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="protocolTools"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"protocolTools"
>
M500
协议工具
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="messageTools"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"messageTools"
>
消息工具
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="messageTools"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"messageTools"
>
新硬件
消息工具
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="tab1"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"tab1"
>
案例
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="tab1"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"tab1"
>
案例
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="tab2"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"tab2"
>
演示页面
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="tab2"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"tab2"
>
演示页面
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="other"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"otherTab"
>
其他
</a></li>
<li
role=
"presentation"
{%
if
arg.path[0]=
="other"
%}
class=
"active"
{%
endif
%}
><a
onclick=
"swichTap(this)"
id=
"otherTab"
>
其他
</a></li>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment