Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
谁人不识我千夜
NodeJS_598138
提交
ab6363c7
N
NodeJS_598138
项目概览
谁人不识我千夜
/
NodeJS_598138
与 Fork 源项目一致
Fork自
inscode / NodeJS
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
N
NodeJS_598138
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
ab6363c7
编写于
6月 06, 2024
作者:
W
weixin_46064585
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Thu Jun 6 10:44:00 CST 2024 inscode
上级
e01ddbd2
变更
5
展开全部
隐藏空白更改
内联
并排
Showing
5 changed file
with
3521 addition
and
352 deletion
+3521
-352
define.js
define.js
+64
-0
demo.js
demo.js
+406
-0
helper.js
helper.js
+103
-0
index.js
index.js
+2947
-352
package.json
package.json
+1
-0
未找到文件。
define.js
0 → 100644
浏览文件 @
ab6363c7
'
use strict
'
exports
.
wsEventType
=
[
'
log
'
,
'
cmdRet
'
,
'
userEvent
'
,
'
sysEvent
'
,
]
exports
.
userEvents
=
[
'
qrcode
'
,
// 登陆二维码
'
scan
'
,
// 扫码登陆状态
'
login
'
,
// 登陆完成
'
loaded
'
,
// 通讯录载入完毕
'
logout
'
,
// 注销登录(账户退出)
'
close
'
,
// 任务断线
'
warn
'
,
// 错误
'
sns
'
,
// 朋友圈事件(朋友圈小圆点)
'
notify
'
,
// 推送消息通知
'
autoLogin
'
,
// 自动重连成功通知
'
push
'
,
// 推送消息(系统、好友消息等)
]
exports
.
loginType
=
{
auto
:
'
auto
'
,
// 断线重连
request
:
'
request
'
,
// 二次登陆
qrcode
:
'
qrcode
'
,
// 扫码登陆
phone
:
'
phone
'
,
// 手机验证码登陆
user
:
'
user
'
,
// 账号密码登陆
}
exports
.
blacklist
=
[
'
appbrandcustomerservicemsg
'
,
'
blogapp
'
,
'
cardpackage
'
,
'
facebookapp
'
,
'
feedsapp
'
,
'
filehelper
'
,
'
floatbottle
'
,
'
floatbottle
'
,
// 漂流瓶
'
fmessage
'
,
// 朋友推荐
'
helper_entry
'
,
'
lbsapp
'
,
'
linkedinplugin
'
,
'
masssendapp
'
,
'
medianote
'
,
// 语音记事本
'
mphelper
'
,
// 公众平台安全助手
'
newsapp
'
,
// 腾讯新闻
'
notification_messages
'
,
'
notifymessage
'
,
'
officialaccounts
'
,
'
pc_share
'
,
'
qmessage
'
,
// qq离线消息
'
qqfriend
'
,
'
qqmail
'
,
'
qqsync
'
,
'
shakeapp
'
,
'
tmessage
'
,
'
voiceinputapp
'
,
'
voicevoipapp
'
,
'
voipapp
'
,
'
weibo
'
,
// 微博-未知
'
weixin
'
,
// 腾讯团队
]
\ No newline at end of file
demo.js
0 → 100644
浏览文件 @
ab6363c7
'
use strict
'
const
log4js
=
require
(
'
log4js
'
)
const
Padchat
=
require
(
'
./index
'
)
const
fs
=
require
(
'
fs
'
)
const
util
=
require
(
'
util
'
)
const
qrcode
=
require
(
'
qrcode-terminal
'
)
/**
* 创建日志目录
*/
try
{
require
(
'
fs
'
).
mkdirSync
(
'
./logs
'
)
}
catch
(
e
)
{
if
(
e
.
code
!==
'
EEXIST
'
)
{
console
.
error
(
'
Could not set up log directory, error:
'
,
e
)
process
.
exit
(
1
)
}
}
// try {
// log4js.configure('./log4js.json')
// } catch (e) {
// console.error('载入log4js日志输出配置错误: ', e)
// process.exit(1);
// }
const
logger
=
log4js
.
getLogger
(
'
app
'
)
const
dLog
=
log4js
.
getLogger
(
'
dev
'
)
logger
.
info
(
'
demo start!
'
)
const
autoData
=
{
wxData
:
''
,
token
:
''
,
}
let
server
=
''
server
=
'
ws://47.99.211.34:8181/
'
// 永久免费使用
try
{
const
tmpBuf
=
fs
.
readFileSync
(
'
./config.json
'
)
const
data
=
JSON
.
parse
(
String
(
tmpBuf
))
autoData
.
wxData
=
data
.
wxData
autoData
.
token
=
data
.
token
logger
.
info
(
'
载入设备参数与自动登陆数据:%o
'
,
autoData
)
}
catch
(
e
)
{
logger
.
warn
(
'
没有在本地发现设备登录参数或解析数据失败!如首次登录请忽略!
'
)
}
const
wx
=
new
Padchat
(
server
)
logger
.
info
(
'
当前连接接口服务器为:
'
,
server
)
let
disconnectCount
=
0
// 断开计数
let
connected
=
false
// 成功连接标志
wx
.
on
(
'
close
'
,
(
code
,
msg
)
=>
{
// 需要注意关闭代码为3201-3203的错误,重连也用,具体参考文档中`close`事件说明
if
(
code
>
3200
)
{
logger
.
warn
(
`Websocket已关闭!code:
${
code
}
-
${
msg
}
`
)
return
}
logger
.
info
(
`Websocket已关闭!code:
${
code
}
-
${
msg
}
`
)
// 根据是否成功连接过判断本次是未能连接成功还是与服务器连接中断
if
(
connected
)
{
connected
=
false
disconnectCount
++
logger
.
info
(
`第
${
disconnectCount
}
次与服务器连接断开!现在将重试连接服务器。`
)
}
else
{
logger
.
debug
(
`未能连接服务器!将重试连接服务器。`
)
}
// 重新启动websocket连接
wx
.
start
()
})
.
on
(
'
open
'
,
async
()
=>
{
let
ret
logger
.
info
(
'
连接成功!
'
)
connected
=
true
// 非首次登录时最好使用以前成功登录时使用的设备参数,
// 否则可能会被tx服务器怀疑账号被盗,导致手机端被登出
ret
=
await
wx
.
init
()
if
(
!
ret
.
success
)
{
logger
.
error
(
'
新建任务失败!
'
,
ret
)
return
}
logger
.
info
(
'
新建任务成功, json:
'
,
ret
)
//先尝试使用断线重连方式登陆
if
(
autoData
.
token
)
{
ret
=
await
wx
.
login
(
'
auto
'
,
autoData
)
if
(
ret
.
success
)
{
logger
.
info
(
'
断线重连请求成功!
'
,
ret
)
return
}
logger
.
warn
(
'
断线重连请求失败!
'
,
ret
)
ret
=
await
wx
.
login
(
'
request
'
,
autoData
)
if
(
ret
.
success
)
{
logger
.
info
(
'
自动登录请求成功!
'
,
ret
)
return
}
logger
.
warn
(
'
自动登录请求失败!
'
,
ret
)
}
ret
=
await
wx
.
login
(
'
qrcode
'
)
if
(
!
ret
.
success
)
{
logger
.
error
(
'
使用qrcode登录模式失败!
'
,
ret
)
return
}
logger
.
info
(
'
使用qrcode登录模式!
'
)
})
.
on
(
'
qrcode
'
,
data
=>
{
// 如果存在url,则直接在终端中生成二维码并显示
if
(
data
.
url
)
{
logger
.
info
(
`登陆二维码内容为: "
${
data
.
url
}
",请使用微信扫描下方二维码登陆!`
)
qrcode
.
generate
(
data
.
url
,
{
small
:
true
})
}
else
{
logger
.
error
(
`未能获得登陆二维码!`
)
}
})
.
on
(
'
scan
'
,
data
=>
{
switch
(
data
.
status
)
{
case
0
:
logger
.
info
(
'
等待扫码...
'
,
data
)
break
;
case
1
:
// {
// status : 1,
// expiredTime: 239,
// headUrl : 'http://wx.qlogo.cn/mmhead/ver_1/xxxxxxx/0', //头像url
// nickName : '复仇者联盟' //昵称
// }
logger
.
info
(
'
已扫码,请在手机端确认登陆...
'
,
data
)
break
;
case
2
:
// {
// password : '***hide***', // 可忽略
// status : 2,
// expiredTime: 238,
// headUrl : 'http://wx.qlogo.cn/mmhead/ver_1/xxxxxxx/0', //头像url
// subStatus : 0 // 登陆操作状态码
// 以下字段仅在登录成功时有效
// external : '1',
// email : '',
// uin : 149806460, // 微信账号uin,全局唯一
// deviceType : 'android', // 登陆的主设备类型
// nickName : '复仇者联盟' //昵称
// userName : 'wxid_xxxxxx', // 微信账号id,全局唯一
// phoneNumber: '18012345678', // 微信账号绑定的手机号
// }
switch
(
data
.
subStatus
)
{
case
0
:
logger
.
info
(
'
扫码成功!登陆成功!
'
,
data
)
break
;
case
1
:
logger
.
info
(
'
扫码成功!登陆失败!
'
,
data
)
break
;
default
:
logger
.
info
(
'
扫码成功!未知状态码!
'
,
data
)
break
;
}
break
;
// 如果等待登陆超时或手机上点击了取消登陆,需要重新调用登陆
case
3
:
logger
.
info
(
'
二维码已过期!请重新调用登陆接口!
'
,
data
)
break
;
case
4
:
logger
.
info
(
'
手机端已取消登陆!请重新调用登陆接口!
'
,
data
)
break
;
default
:
logger
.
warn
(
'
未知登陆状态!请重新调用登陆接口!
'
,
data
)
break
;
}
})
.
on
(
'
login
'
,
async
()
=>
{
logger
.
info
(
'
微信账号登陆成功!
'
)
let
ret
ret
=
await
wx
.
getMyInfo
()
logger
.
info
(
'
当前账号信息:
'
,
ret
.
data
)
// 如果不想同步通讯录信息,可关闭同步通讯录
// await wx.setSyncContact(false)
// 主动同步通讯录
await
wx
.
syncContact
()
await
saveAutoData
()
})
.
on
(
'
autoLogin
'
,
async
()
=>
{
// 自动重连后需要保存新的自动登陆数据
await
saveAutoData
()
})
.
on
(
'
logout
'
,
({
msg
})
=>
{
logger
.
info
(
'
微信账号已退出!
'
,
msg
)
})
.
on
(
'
over
'
,
({
msg
})
=>
{
logger
.
info
(
'
任务实例已关闭!
'
,
msg
)
})
.
on
(
'
loaded
'
,
async
()
=>
{
logger
.
info
(
'
通讯录同步完毕!
'
)
// 主动触发同步消息
await
wx
.
syncMsg
()
const
ret
=
await
wx
.
sendMsg
(
'
filehelper
'
,
'
你登录了!
'
)
logger
.
info
(
'
发送信息结果:
'
,
ret
)
})
.
on
(
'
sns
'
,
(
data
,
msg
)
=>
{
logger
.
info
(
'
收到朋友圈事件!请查看朋友圈新消息哦!
'
,
msg
)
})
.
on
(
'
contact
'
,
async
data
=>
{
logger
.
info
(
'
收到推送联系人:%s - %s
\n
'
,
data
.
userName
,
data
.
nickName
,
JSON
.
stringify
(
data
))
})
.
on
(
'
push
'
,
async
data
=>
{
// 消息类型 data.mType
// 1 文字消息
// 3 收到图片消息
// 34 语音消息
// 35 用户头像buf
// 37 收到好友请求消息
// 42 名片消息
// 43 视频消息
// 47 表情消息
// 48 定位消息
// 49 APP消息(文件 或者 链接 H5)
// 50 语音通话
// 51 状态通知(如打开与好友/群的聊天界面)
// 52 语音通话通知
// 53 语音通话邀请
// 62 小视频
// 2000 转账消息
// 2001 收到红包消息
// 3000 群邀请
// 9999 系统通知
// 10000 微信通知信息. 微信群信息变更通知,多为群名修改,进群,离群信息,不包含群内聊天信息
// 10002 撤回消息
// --------------------------------
// 注意,如果是来自微信群的消息,data.content字段中包含发言人的wxid及其发言内容,需要自行提取
// 各类复杂消息,data.content中是xml格式的文本内容,需要自行从中提取各类数据。(如好友请求)
let
rawFile
switch
(
data
.
mType
)
{
case
3
:
logger
.
info
(
'
收到来自 %s 的图片消息,包含图片数据:%s,xml内容:
\n
%s
'
,
data
.
fromUser
,
!!
data
.
data
,
data
.
content
)
rawFile
=
data
.
data
||
null
logger
.
info
(
'
图片缩略图数据base64尺寸:%d
'
,
rawFile
.
length
)
await
wx
.
getMsgImage
(
data
)
.
then
(
ret
=>
{
rawFile
=
ret
.
data
.
image
||
''
logger
.
info
(
'
获取消息原始图片结果:%s, 获得图片base64尺寸:%d
'
,
ret
.
success
,
rawFile
.
length
)
})
logger
.
info
(
'
图片数据base64尺寸:%d
'
,
rawFile
.
length
)
await
wx
.
sendImage
(
'
filehelper
'
,
rawFile
)
.
then
(
ret
=>
{
logger
.
info
(
'
转发图片信息给 %s 结果:
'
,
'
filehelper
'
,
ret
)
})
.
catch
(
e
=>
{
logger
.
warn
(
'
转发图片信息异常:
'
,
e
.
message
)
})
break
case
43
:
logger
.
info
(
'
收到来自 %s 的视频消息,包含视频数据:%s,xml内容:
\n
%s
'
,
data
.
fromUser
,
!!
data
.
data
,
data
.
content
)
rawFile
=
data
.
data
||
null
if
(
!
rawFile
)
{
await
wx
.
getMsgVideo
(
data
)
.
then
(
ret
=>
{
rawFile
=
ret
.
data
.
video
||
''
logger
.
info
(
'
获取消息原始视频结果:%s, 获得视频base64尺寸:%d
'
,
ret
.
success
,
rawFile
.
length
)
})
}
logger
.
info
(
'
视频数据base64尺寸:%d
'
,
rawFile
.
length
)
break
case
1
:
if
(
data
.
fromUser
===
'
newsapp
'
)
{
// 腾讯新闻发的信息太长
break
}
logger
.
info
(
'
收到来自 %s 的文本消息:
'
,
data
.
fromUser
,
data
.
description
||
data
.
content
)
if
(
/ding/
.
test
(
data
.
content
))
{
await
wx
.
sendMsg
(
data
.
fromUser
,
'
dong. receive:
'
+
data
.
content
)
.
then
(
ret
=>
{
logger
.
info
(
'
回复信息给%s 结果:
'
,
data
.
fromUser
,
ret
)
})
.
catch
(
e
=>
{
logger
.
warn
(
'
回复信息异常:
'
,
e
.
message
)
})
}
else
if
(
/^#.*/
.
test
(
data
.
content
)
||
/^
[\w]
*:
\n
#.*/
.
test
(
data
.
content
))
{
await
onMsg
(
data
)
.
catch
(
e
=>
{
logger
.
warn
(
'
处理信息异常:
'
,
e
)
})
}
break
case
34
:
logger
.
info
(
'
收到来自 %s 的语音消息,包含语音数据:%s,xml内容:
\n
%s
'
,
data
.
fromUser
,
!!
data
.
data
,
data
.
content
)
// 超过30Kb的语音数据不会包含在推送信息中,需要主动拉取
rawFile
=
data
.
data
||
null
if
(
!
rawFile
)
{
// BUG: 超过60Kb的语音数据,只能拉取到60Kb,也就是说大约36~40秒以上的语音会丢失后边部分语音内容
await
wx
.
getMsgVoice
(
data
)
.
then
(
ret
=>
{
rawFile
=
ret
.
data
.
voice
||
''
logger
.
info
(
'
获取消息原始语音结果:%s, 获得语音base64尺寸:%d,拉取到数据尺寸:%d
'
,
ret
.
success
,
rawFile
.
length
,
ret
.
data
.
size
)
})
}
logger
.
info
(
'
语音数据base64尺寸:%d
'
,
rawFile
.
length
)
if
(
rawFile
.
length
>
0
)
{
let
match
=
data
.
content
.
match
(
/length="
(\d
+
)
"/
)
||
[]
const
length
=
match
[
1
]
||
0
match
=
data
.
content
.
match
(
/voicelength="
(\d
+
)
"/
)
||
[]
const
ms
=
match
[
1
]
||
0
logger
.
info
(
'
语音数据语音长度:%d ms,xml内记录尺寸:%d
'
,
ms
,
length
)
await
wx
.
sendVoice
(
'
filehelper
'
,
rawFile
,
ms
)
.
then
(
ret
=>
{
logger
.
info
(
'
转发语音信息给 %s 结果:
'
,
'
filehelper
'
,
ret
)
})
.
catch
(
e
=>
{
logger
.
warn
(
'
转发语音信息异常:
'
,
e
.
message
)
})
}
break
case
49
:
logger
.
info
(
'
收到一条来自 %s 的appmsg富媒体消息:
'
,
data
.
fromUser
,
data
)
break
case
10002
:
if
(
data
.
fromUser
===
'
weixin
'
)
{
//每次登陆,会收到一条系统垃圾推送,过滤掉
break
}
logger
.
info
(
'
用户 %s 撤回了一条消息:
'
,
data
.
fromUser
,
data
)
break
default
:
logger
.
info
(
'
收到推送消息:
'
,
data
)
break
}
})
.
on
(
'
error
'
,
e
=>
{
logger
.
error
(
'
ws 错误:
'
,
e
.
message
)
})
.
on
(
'
warn
'
,
e
=>
{
logger
.
error
(
'
任务出现错误:
'
,
e
.
message
)
})
/**
* @description 保存自动登陆数据
*/
async
function
saveAutoData
()
{
let
ret
=
await
wx
.
getWxData
()
if
(
!
ret
.
success
)
{
logger
.
warn
(
'
获取设备参数未成功! json:
'
,
ret
)
return
}
logger
.
info
(
'
获取设备参数成功, json:
'
,
ret
)
Object
.
assign
(
autoData
,
{
wxData
:
ret
.
data
.
wxData
})
ret
=
await
wx
.
getLoginToken
()
if
(
!
ret
.
success
)
{
logger
.
warn
(
'
获取自动登陆数据未成功! json:
'
,
ret
)
return
}
logger
.
info
(
'
获取自动登陆数据成功, json:
'
,
ret
)
Object
.
assign
(
autoData
,
{
token
:
ret
.
data
.
token
})
// NOTE: 这里将设备参数保存到本地,以后再次登录此账号时提供相同参数
fs
.
writeFileSync
(
'
./config.json
'
,
JSON
.
stringify
(
autoData
,
null
,
2
))
logger
.
info
(
'
设备参数已写入到 ./config.json文件
'
)
}
async
function
onMsg
(
data
)
{
const
content
=
data
.
content
.
replace
(
/^
[\w
:
\n]
*#/m
,
''
)
let
[
cmd
,
...
args
]
=
content
.
split
(
'
\n
'
)
args
=
args
.
map
(
str
=>
{
try
{
str
=
JSON
.
parse
(
str
)
}
catch
(
e
)
{
}
return
str
})
if
(
cmd
&&
wx
[
cmd
]
&&
typeof
wx
[
cmd
]
===
'
function
'
)
{
logger
.
info
(
'
执行函数 %s,参数:
'
,
cmd
,
args
)
await
wx
[
cmd
](...
args
)
.
then
(
ret
=>
{
logger
.
info
(
'
执行函数 %s 结果:%o
'
,
cmd
,
ret
)
})
.
catch
(
e
=>
{
logger
.
warn
(
'
执行函数 %s 异常:
'
,
e
)
})
}
}
process
.
on
(
'
uncaughtException
'
,
e
=>
{
logger
.
error
(
'
Main
'
,
'
uncaughtException:
'
,
e
)
})
process
.
on
(
'
unhandledRejection
'
,
e
=>
{
logger
.
error
(
'
Main
'
,
'
unhandledRejection:
'
,
e
)
})
\ No newline at end of file
helper.js
0 → 100644
浏览文件 @
ab6363c7
'
use strict
'
// 将object中的属性名称转换为全驼峰格式
module
.
exports
=
{
toCamelCase
,
toUnderLine
,
structureXml
,
}
/**
* 将object中的属性名称从下划线转换为驼峰格式
* (包含子数据的属性名,会遍历转换)
*
* @param {any} obj 要转换的object
* @param {boolean} [big=true] 是否转换为大驼峰格式
* @returns {Object} 转换后的object
*/
function
toCamelCase
(
obj
,
big
=
false
)
{
if
(
obj
instanceof
Array
)
{
return
obj
.
map
(
item
=>
toCamelCase
(
item
))
}
if
(
!
(
obj
instanceof
Object
))
{
return
obj
}
for
(
const
key
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
key
))
{
let
newKey
=
key
.
replace
(
/_
(\w)
/g
,
(
match
,
val
,
offset
)
=>
{
return
val
.
toUpperCase
()
})
if
(
big
)
{
newKey
=
newKey
.
replace
(
/^
(\w)
/
,
(
match
,
val
,
offset
)
=>
{
return
val
.
toUpperCase
()
})
}
else
{
// 将首字母转换为小写(部分字段名称开头两个为大写,比如`PYInitial`/`MMBizMenu`)
// 跳过`X-WECHAT-KEY`和`X-WECHAT-UIN`这种字段
newKey
=
newKey
.
replace
(
/^
(\w{2})
/
,
(
match
,
val
,
offset
)
=>
{
return
val
.
toLowerCase
()
})
}
if
((
obj
[
key
]
instanceof
Array
)
||
(
obj
[
key
]
instanceof
Object
))
{
obj
[
key
]
=
toCamelCase
(
obj
[
key
])
}
if
(
newKey
!==
key
)
{
obj
[
newKey
]
=
obj
[
key
]
delete
obj
[
key
]
}
}
}
return
obj
}
/**
* 将object中的属性名称从驼峰转换为下划线格式
*
* @param {any} obj 要转换的object
* @returns {Object} 转换后的object
*/
function
toUnderLine
(
obj
)
{
const
newObj
=
{}
if
(
!
(
obj
instanceof
Object
))
{
return
obj
}
for
(
const
key
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
key
))
{
const
newKey
=
key
.
replace
(
/
([
A-Z
])
/g
,
(
match
,
val
,
offset
)
=>
{
return
(
offset
?
'
_
'
:
''
)
+
val
}).
toLowerCase
()
newObj
[
newKey
]
=
obj
[
key
]
}
}
return
newObj
}
/**
* 组装appmsg消息体
*
* @param {object} object 消息体参数
* @param {object} [object.appid] - appid,忽略即可
* @param {object} [object.sdkver] - sdk版本,忽略即可
* @param {object} [object.title] - 标题
* @param {object} [object.des] - 描述
* @param {object} [object.url] - 链接url
* @param {object} [object.thumburl] - 缩略图url
* ```
* {
* appid = '', //appid,忽略即可
* sdkver = '', //sdk版本,忽略即可
* title = '', //标题
* des = '', //描述
* url = '', //链接url
* thumburl = '', //缩略图url
* }
* ```
* @returns {String} 组装的消息体
*/
function
structureXml
(
object
)
{
const
{
appid
=
''
,
sdkver
=
''
,
title
=
''
,
des
=
''
,
url
=
''
,
thumburl
=
''
}
=
object
return
`<appmsg appid="
${
appid
}
" sdkver="
${
sdkver
}
">
<title>
${
title
}
</title>
<des>
${
des
}
</des>
<action>view</action>
<type>5</type>
<showtype>0</showtype>
<content></content>
<url>
${
url
}
</url>
<thumburl>
${
thumburl
}
</thumburl>
</appmsg>`
.
replace
(
/
\n
/g
,
''
)
}
\ No newline at end of file
index.js
浏览文件 @
ab6363c7
此差异已折叠。
点击以展开。
package.json
浏览文件 @
ab6363c7
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
"description"
:
"padchat开发包"
,
"description"
:
"padchat开发包"
,
"main"
:
"index.js"
,
"main"
:
"index.js"
,
"scripts"
:
{
"scripts"
:
{
"dev"
:
"node index.js"
,
"start"
:
"node demo"
,
"start"
:
"node demo"
,
"doc"
:
"node scripts/docVer.js >nul && jsdoc2md index.js >> docs/index.md"
,
"doc"
:
"node scripts/docVer.js >nul && jsdoc2md index.js >> docs/index.md"
,
"eslint"
:
"eslint {define,helper,index,demo}.js"
,
"eslint"
:
"eslint {define,helper,index,demo}.js"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录