卫星通信服务平台
This commit is contained in:
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
coverage
|
||||||
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
logs/
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
node_modules/
|
||||||
|
*-lock.json
|
||||||
|
*-lock.yaml
|
||||||
|
yarn.lock
|
||||||
|
coverage/
|
||||||
|
.idea/
|
||||||
|
run/
|
||||||
|
.DS_Store
|
||||||
|
*.sw*
|
||||||
|
*.un~
|
||||||
|
typings/
|
||||||
|
.nyc_output/
|
||||||
31
README.md
Normal file
31
README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# tqxz-sn-message-platform
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## QuickStart
|
||||||
|
|
||||||
|
<!-- add docs here for user -->
|
||||||
|
|
||||||
|
see [egg docs][egg] for more detail.
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i
|
||||||
|
npm run dev
|
||||||
|
open http://localhost:7001/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
npm stop
|
||||||
|
```
|
||||||
|
|
||||||
|
### npm scripts
|
||||||
|
|
||||||
|
- Use `npm run lint` to check code style.
|
||||||
|
- Use `npm test` to run unit test.
|
||||||
|
|
||||||
|
[egg]: https://eggjs.org
|
||||||
464
app/controller/home.js
Normal file
464
app/controller/home.js
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
const { Controller } = require('egg');
|
||||||
|
|
||||||
|
const GBK = require("gbk.js");
|
||||||
|
|
||||||
|
const decode = (data) => {
|
||||||
|
let arr = [];
|
||||||
|
data.match(/..?/g).forEach((element) => {
|
||||||
|
arr.push(parseInt(element, 16));
|
||||||
|
});
|
||||||
|
return GBK.decode(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CryptoJS = require("crypto-js");
|
||||||
|
|
||||||
|
const KEY = CryptoJS.enc.Utf8.parse('BDQH');
|
||||||
|
|
||||||
|
const decryptRequest = (body) => {
|
||||||
|
return CryptoJS.AES.decrypt(body, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString(CryptoJS.enc.Utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkUid = async (ctx) => {
|
||||||
|
const uid = ctx.request.body.uid;
|
||||||
|
const token = ctx.request.header.authorization;
|
||||||
|
const redis = ctx.app.redis;
|
||||||
|
let rdmcode;
|
||||||
|
if (!uid) {
|
||||||
|
const [buser, cuser, tuser] = await Promise.all([
|
||||||
|
redis.get('db0').get(token),
|
||||||
|
redis.get('db1').get(token),
|
||||||
|
redis.get('db5').get(token),
|
||||||
|
]);
|
||||||
|
rdmcode = buser || cuser || tuser;
|
||||||
|
} else {
|
||||||
|
let decryptUid = decryptRequest(uid).split('?')[0];
|
||||||
|
const redisType = {
|
||||||
|
"B": "db0",
|
||||||
|
"C": "db1",
|
||||||
|
"T": "db5",
|
||||||
|
};
|
||||||
|
const lastCode = decryptUid[decryptUid.length - 1];
|
||||||
|
rdmcode = await redis.get(redisType[lastCode]).get(token);
|
||||||
|
}
|
||||||
|
if (!rdmcode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return rdmcode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileName = "home";
|
||||||
|
|
||||||
|
const setResponse = (ctx, code, msg, model, data = {}) => {
|
||||||
|
const modelType = {
|
||||||
|
"none": { code, msg },
|
||||||
|
"deconstruction": { code, msg, ...data },
|
||||||
|
"polymerization": { code, msg, data }
|
||||||
|
}
|
||||||
|
ctx.body = modelType[model];
|
||||||
|
}
|
||||||
|
|
||||||
|
class HomeController extends Controller {
|
||||||
|
// 获取SN号
|
||||||
|
async getSN() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const result = await ctx.service.home.getSN(uid);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
const data = { snNumber: result.dataValues.sn_number };
|
||||||
|
setResponse(ctx, 200, '获取SN号成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '获取SN号失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "getSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索SN号
|
||||||
|
async searchSN() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const { snNumber } = ctx.request.body;
|
||||||
|
const result = await ctx.service.home.searchSN(snNumber);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
if (result.dataValues.cuser == null) {
|
||||||
|
setResponse(ctx, 201, '此SN号未绑定', "deconstruction", result);
|
||||||
|
} else if (result.dataValues.cuser == uid) {
|
||||||
|
setResponse(ctx, 202, '此SN号已与当前账号绑定', "none");
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 203, '此SN号已绑定', "none");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '此SN号未注册', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "searchSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索可绑定的SN号
|
||||||
|
async searchBindSN() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const result = await ctx.service.home.searchBindSN(uid);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
const data = {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
setResponse(ctx, 200, '获取可绑定的SN号成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '获取可绑定的SN号失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "searchBindSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索可绑定的单位用户
|
||||||
|
async searchBindUser() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const result = await ctx.service.home.searchBindUser(uid);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
const data = {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
setResponse(ctx, 200, '获取可绑定的单位用户成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '获取可绑定的单位用户失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "searchBindUser";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定SN号
|
||||||
|
async bindSN() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const result = await ctx.service.home.bindSN(uid, body);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
setResponse(ctx, 200, '绑卡成功', "none");
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '绑卡失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "bindSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解绑SN号
|
||||||
|
async unBindingSN() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const result = await ctx.service.home.unBindingSN(uid, body);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
setResponse(ctx, 200, '解绑成功', "none");
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '解绑失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "unBindingSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取绑定记录
|
||||||
|
async getRecord() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const result = await ctx.service.home.getRecord(uid, body);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
let recordMsg = [];
|
||||||
|
result.rows.forEach(element => {
|
||||||
|
recordMsg.push(element.dataValues);
|
||||||
|
});
|
||||||
|
const data = {
|
||||||
|
recordMsg: recordMsg,
|
||||||
|
count: result.count
|
||||||
|
};
|
||||||
|
setResponse(ctx, 200, '绑定记录查询成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '绑定记录查询失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "getRecord";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储消息记录
|
||||||
|
async shortMsg() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
const body = ctx.request.body;
|
||||||
|
console.log(body)
|
||||||
|
const { sn_number, original_msg, msg_data, created_at } = body;
|
||||||
|
const form = {
|
||||||
|
sn_number: sn_number,
|
||||||
|
original_msg: original_msg,
|
||||||
|
msg_data: msg_data,
|
||||||
|
created_at: created_at
|
||||||
|
};
|
||||||
|
const result = await ctx.service.home.shortMsg(form);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
setResponse(ctx, 200, '消息记录存储成功', "none");
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '消息记录存储失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "shortMsg";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取历史消息
|
||||||
|
async getHistoryMsg() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const result = await ctx.service.home.getHistoryMsg(uid, body);
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
let historyMsg = [];
|
||||||
|
result.rows.forEach(element => {
|
||||||
|
historyMsg.push(element.dataValues);
|
||||||
|
});
|
||||||
|
const data = {
|
||||||
|
historyMsg: historyMsg,
|
||||||
|
count: result.count
|
||||||
|
};
|
||||||
|
setResponse(ctx, 200, '历史消息查找成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '历史消息查找失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "getHistoryMsg";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除历史消息
|
||||||
|
async delHistoryMsg() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const model = decryptRequest(body.model);
|
||||||
|
const password = decryptRequest(body.password);
|
||||||
|
const requestMsg = body.userMsg;
|
||||||
|
const resetList = await ctx.service.home.delHistoryMsg(uid, model, password, requestMsg);
|
||||||
|
if(resetList == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resetList) {
|
||||||
|
setResponse(ctx, 200, '删除历史消息成功', "none");
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '删除历史消息失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "delHistoryMsg";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将sequelize查询结果转换为普通对象数组
|
||||||
|
* @param {Array} rows - sequelize查询结果行
|
||||||
|
* @returns {Array} 转换后的普通对象数组
|
||||||
|
*/
|
||||||
|
transformBsideUsers(rows) {
|
||||||
|
let bsideUsers = [];
|
||||||
|
rows.forEach(element => {
|
||||||
|
bsideUsers.push(element.dataValues);
|
||||||
|
});
|
||||||
|
return bsideUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取单位用户
|
||||||
|
async bsideUserManager() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
let result;
|
||||||
|
if(uid[uid.length - 1] == 'B') {
|
||||||
|
const body = ctx.request.body;
|
||||||
|
result = await ctx.service.home.bsideUserManager(uid, body);
|
||||||
|
}
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
const bsideUsers = this.transformBsideUsers(result.rows);
|
||||||
|
const data = {
|
||||||
|
bsideUsers: bsideUsers,
|
||||||
|
count: result.count
|
||||||
|
};
|
||||||
|
setResponse(ctx, 200, '获取单位用户成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '获取单位用户失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "bsideUserManager";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取可管理的SN号
|
||||||
|
async bsideSNManager() {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
try {
|
||||||
|
let rdmcode = await checkUid(ctx);
|
||||||
|
if (!rdmcode) {
|
||||||
|
setResponse(ctx, 401, 'token过期或错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uid = JSON.parse(rdmcode).uid;
|
||||||
|
let result;
|
||||||
|
if(uid[uid.length - 1] == 'B') {
|
||||||
|
const body = ctx.request.body;
|
||||||
|
result = await ctx.service.home.bsideSNManager(uid, body);
|
||||||
|
}
|
||||||
|
if(result == "error") {
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
let snArr = [];
|
||||||
|
result.forEach(element => {
|
||||||
|
snArr.push(element.dataValues);
|
||||||
|
});
|
||||||
|
const data = {
|
||||||
|
count: result.length,
|
||||||
|
bsideSN: snArr,
|
||||||
|
};
|
||||||
|
setResponse(ctx, 200, '获取可管理的SN号成功', "deconstruction", data);
|
||||||
|
} else {
|
||||||
|
setResponse(ctx, 404, '获取可管理的SN号失败', "none");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "bsideSNManager";
|
||||||
|
ctx.app.middleware.utils.log('../../../controllerLog', blockName + ">>>>" + error);
|
||||||
|
setResponse(ctx, 500, '服务器错误', "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = HomeController;
|
||||||
50
app/core/base_service.js
Normal file
50
app/core/base_service.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
const { Service } = require('egg');
|
||||||
|
|
||||||
|
const sha256 = require("crypto-js/sha256");
|
||||||
|
|
||||||
|
const CryptoJS = require("crypto-js");
|
||||||
|
|
||||||
|
const KEY = CryptoJS.enc.Utf8.parse('BDQH');
|
||||||
|
|
||||||
|
class BaseService extends Service {
|
||||||
|
shaForm = (body, salt) => {
|
||||||
|
return sha256(sha256(body).toString() + salt).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptRequest = (body) => {
|
||||||
|
return CryptoJS.AES.encrypt(body, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptRequest = (body) => {
|
||||||
|
return CryptoJS.AES.decrypt(body, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString(CryptoJS.enc.Utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
opOptions = (attributes, searchOptions, substring, key, between, sortOptions) => {
|
||||||
|
let where = {}, order = [];
|
||||||
|
attributes.forEach(element => {
|
||||||
|
if (searchOptions[element]) {
|
||||||
|
if (substring.includes(element)) {
|
||||||
|
where[element] = { [Op.substring]: searchOptions[element] };
|
||||||
|
} else if (key.includes(element)) {
|
||||||
|
where[element] = searchOptions[element];
|
||||||
|
} else if (between.includes(element)) {
|
||||||
|
where[element] = { [Op.between]: [searchOptions[element][0], searchOptions[element][1]] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sortOptions[element]) {
|
||||||
|
order.push([element, 'DESC']);
|
||||||
|
} else if (sortOptions[element]) {
|
||||||
|
order.push([element, 'ASC']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { where, order }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BaseService;
|
||||||
8
app/middleware/shunt/socketEmitter.js
Normal file
8
app/middleware/shunt/socketEmitter.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// socket事件监听器
|
||||||
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
|
const socketEmitter = new EventEmitter();
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return socketEmitter;
|
||||||
|
};
|
||||||
68
app/middleware/socket/socketServer.js
Normal file
68
app/middleware/socket/socketServer.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
const net = require('net');
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { middleware } = app;
|
||||||
|
const shunt = middleware.shunt;
|
||||||
|
|
||||||
|
net.createServer(function (socket) {
|
||||||
|
socket.on('lookup', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('lookup')
|
||||||
|
});
|
||||||
|
socket.on('connection', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('socket客户端已连接');
|
||||||
|
});
|
||||||
|
socket.on('data', async function (data) {
|
||||||
|
let value = data.toString('hex');
|
||||||
|
console.log(value);
|
||||||
|
let response = "000000068100";
|
||||||
|
socket.write(Buffer.from(response, 'hex'));
|
||||||
|
// 00000043010000000000000000000000000000000000000000 18 31353037365f32303236303330333135313835315f323832 00 0f 0102030405060708090a0b0c0d0e0f
|
||||||
|
let sn_value = value.slice(52, 100),
|
||||||
|
snBuffer = Buffer.from(sn_value, 'hex'),
|
||||||
|
snNumber = snBuffer.toString('ascii').split("_")[0],
|
||||||
|
msg_value = value.slice(104, value.length),
|
||||||
|
msgBuffer = Buffer.from(msg_value, 'hex'),
|
||||||
|
msgData = msgBuffer.toString('ascii');
|
||||||
|
console.log(msgData)
|
||||||
|
// socket接收消息后触发事件监听器,将消息发送给websocket客户端并存储在数据库中
|
||||||
|
shunt.socketEmitter().emit(snNumber, { msg_data: msgData, created_at: new Date() });
|
||||||
|
await app.curl('http://127.0.0.1:' + app.server.address().port + '/shortMsg', {
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/x-www-form-urlencoded',
|
||||||
|
method: 'POST',
|
||||||
|
timeout: 3000,
|
||||||
|
data: {
|
||||||
|
sn_number: snNumber,
|
||||||
|
original_msg: value,
|
||||||
|
msg_data: msgData,
|
||||||
|
created_at: new Date()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
socket.on('end', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('end');
|
||||||
|
});
|
||||||
|
socket.on('timeout', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('空闲超时');
|
||||||
|
});
|
||||||
|
socket.on('drain', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('写缓存为空');
|
||||||
|
});
|
||||||
|
socket.on('error', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('发生错误');
|
||||||
|
});
|
||||||
|
socket.on('close', function (data) {
|
||||||
|
console.log(data);
|
||||||
|
console.log('socket客户端已断开连接');
|
||||||
|
});
|
||||||
|
socket.pipe(socket);
|
||||||
|
}).listen(8100, function () {
|
||||||
|
console.log('socket服务器已启动,监听端口:8100');
|
||||||
|
});
|
||||||
|
}
|
||||||
72
app/middleware/utils/log.js
Normal file
72
app/middleware/utils/log.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// 错误日志
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const dirCheck = (dirPath) => {
|
||||||
|
// 检查文件夹是否存在
|
||||||
|
fs.access(dirPath, fs.constants.F_OK, (err) => {
|
||||||
|
if (err) {
|
||||||
|
// 文件夹不存在
|
||||||
|
console.log('文件夹不存在,正在创建...');
|
||||||
|
fs.mkdir(dirPath, { recursive: true }, (err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
console.log('文件夹已创建');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 文件夹存在
|
||||||
|
console.log('文件夹已存在');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (filePath, msg) => {
|
||||||
|
// 获取时间
|
||||||
|
let now = new Date(),
|
||||||
|
times = {
|
||||||
|
year: now.getFullYear(),
|
||||||
|
month: now.getMonth() + 1,
|
||||||
|
day: now.getDate(),
|
||||||
|
hour: now.getHours(),
|
||||||
|
minute: now.getMinutes(),
|
||||||
|
second: now.getSeconds()
|
||||||
|
};
|
||||||
|
// 获取操作系统类型
|
||||||
|
const type = os.type();
|
||||||
|
console.log(`操作系统类型: ${type}`);
|
||||||
|
filePath = path.join(__dirname, filePath);
|
||||||
|
dirCheck(filePath);
|
||||||
|
const yearPath = filePath + '/' + times.year;
|
||||||
|
dirCheck(yearPath);
|
||||||
|
const monthPath = yearPath + '/' + times.month;
|
||||||
|
dirCheck(monthPath);
|
||||||
|
const dayPath = monthPath + '/' + times.day + '.txt';
|
||||||
|
const logTime = '[' + times.year + '-' + times.month + '-' + times.day + '>>>' + times.hour + ':' + times.minute + ':' + times.second + ']' + '>>>';
|
||||||
|
let crlf;
|
||||||
|
// 判断操作系统类型,设置换行符
|
||||||
|
if (type === 'Windows_NT') {
|
||||||
|
crlf = '\n';
|
||||||
|
} else {
|
||||||
|
crlf = '\r\n';
|
||||||
|
}
|
||||||
|
// 读取文件内容
|
||||||
|
fs.readFile(dayPath, 'utf8', (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
// 文件不存在,直接写入新内容(这里实际上还是使用了覆盖的方式)
|
||||||
|
fs.writeFile(dayPath, logTime + msg + crlf, (err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
console.log('文件已创建并写入新内容');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 文件存在,追加新内容
|
||||||
|
fs.appendFile(dayPath, logTime + msg + crlf, (err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
console.log('新内容已追加到文件');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
47
app/middleware/webSocket/webSocketServer.js
Normal file
47
app/middleware/webSocket/webSocketServer.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// webSocket服务端
|
||||||
|
const http = require('http');
|
||||||
|
const { Server } = require('socket.io');
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
// 创建HTTP服务器并监听8110端口
|
||||||
|
const server = http.createServer(function (req, res) {
|
||||||
|
if (req.url === '/') {
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||||
|
res.end('Hello World!');
|
||||||
|
}
|
||||||
|
}).listen(app.config.webSocketServer.port);
|
||||||
|
|
||||||
|
let io = new Server(server, {
|
||||||
|
cors: {
|
||||||
|
origin: app.config.webSocketServer.allowedOrigins, // 生产环境应指定具体域名
|
||||||
|
methods: ["GET", "POST"]
|
||||||
|
},
|
||||||
|
// path: app.config.webSocketServer.path,
|
||||||
|
transports: ['websocket', 'polling'],
|
||||||
|
connectionStateRecovery: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`websocket: ${ app.config.webSocketServer.ip }服务器已启动,监听端口:${ app.config.webSocketServer.port }`);
|
||||||
|
|
||||||
|
const socketEmitter = app.middleware.shunt.socketEmitter();
|
||||||
|
const utils = app.middleware.utils;
|
||||||
|
|
||||||
|
io.on('connection', (socket) => {
|
||||||
|
socket.on('message', (snNumber) => {
|
||||||
|
if(socketEmitter.listeners(snNumber).length !== 0) {
|
||||||
|
socketEmitter.removeAllListeners(snNumber);
|
||||||
|
};
|
||||||
|
socketEmitter.on(snNumber, (msg) => {
|
||||||
|
socket.emit(snNumber, msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
io.on('error', (err) => {
|
||||||
|
utils.log('../../webSocketLog', err);
|
||||||
|
io = new Server(app.config.webSocketServer.port, {
|
||||||
|
cors: true,
|
||||||
|
connectionStateRecovery: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
21
app/model/BSNMsg.js
Normal file
21
app/model/BSNMsg.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, TEXT, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const BSNMsg = app.model.define('bsn-msg', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
original_msg: TEXT,
|
||||||
|
msg_data: TEXT,
|
||||||
|
created_at: DATE
|
||||||
|
}, {
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return BSNMsg;
|
||||||
|
};
|
||||||
30
app/model/BSide.js
Normal file
30
app/model/BSide.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const BSide = app.model.define('b-side', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
uid: CHAR(15),
|
||||||
|
salt: CHAR(24),
|
||||||
|
status: INTEGER(3),
|
||||||
|
role: INTEGER(3),
|
||||||
|
account_name: STRING(20),
|
||||||
|
password: CHAR(64),
|
||||||
|
organization: CHAR(16),
|
||||||
|
user_name: STRING(20),
|
||||||
|
phone: CHAR(11),
|
||||||
|
msg: STRING(300),
|
||||||
|
created_at: DATE,
|
||||||
|
updated_at: DATE,
|
||||||
|
login_at: DATE,
|
||||||
|
login_status: INTEGER(3)
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return BSide;
|
||||||
|
};
|
||||||
20
app/model/BindBSNrecord.js
Normal file
20
app/model/BindBSNrecord.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const BindBSNrecord = app.model.define('bind-bsnrecord', {
|
||||||
|
id: { type: INTEGER(11), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
type: INTEGER(1),
|
||||||
|
created_at: DATE,
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return BindBSNrecord;
|
||||||
|
};
|
||||||
19
app/model/BuserSNAdmin.js
Normal file
19
app/model/BuserSNAdmin.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, TEXT } = app.Sequelize;
|
||||||
|
|
||||||
|
const BuserSNAdmin = app.model.define('buser-snadmin', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
length: INTEGER(3),
|
||||||
|
sn_set: TEXT,
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: false,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return BuserSNAdmin;
|
||||||
|
};
|
||||||
18
app/model/BuserSNBind.js
Normal file
18
app/model/BuserSNBind.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING } = app.Sequelize;
|
||||||
|
|
||||||
|
const BuserSNBind = app.model.define('buser-snbind', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: false,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return BuserSNBind;
|
||||||
|
};
|
||||||
20
app/model2/BindCSNrecord.js
Normal file
20
app/model2/BindCSNrecord.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const BindCSNrecord = app.model.define('bind-csnrecord', {
|
||||||
|
id: { type: INTEGER(11), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
type: INTEGER(1),
|
||||||
|
created_at: DATE,
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return BindCSNrecord;
|
||||||
|
};
|
||||||
21
app/model2/CSNMsg.js
Normal file
21
app/model2/CSNMsg.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, TEXT, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const CSNMsg = app.model2.define('csn-msg', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
original_msg: TEXT,
|
||||||
|
msg_data: TEXT,
|
||||||
|
created_at: DATE,
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return CSNMsg;
|
||||||
|
};
|
||||||
34
app/model2/CSide.js
Normal file
34
app/model2/CSide.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const CSide = app.model2.define('c-side', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
uid: CHAR(15),
|
||||||
|
salt: CHAR(24),
|
||||||
|
status: INTEGER(3),
|
||||||
|
role: INTEGER(3),
|
||||||
|
avatar: CHAR(15),
|
||||||
|
account_name: STRING(20),
|
||||||
|
password: CHAR(64),
|
||||||
|
user_name: STRING(20),
|
||||||
|
phone: CHAR(11),
|
||||||
|
gender: INTEGER(1),
|
||||||
|
age: INTEGER(3),
|
||||||
|
email: STRING(254),
|
||||||
|
address: STRING(300),
|
||||||
|
post_code: CHAR(6),
|
||||||
|
created_at: DATE,
|
||||||
|
updated_at: DATE,
|
||||||
|
login_at: DATE,
|
||||||
|
login_status: INTEGER(3)
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return CSide;
|
||||||
|
};
|
||||||
18
app/model2/CuserSNBind.js
Normal file
18
app/model2/CuserSNBind.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING } = app.Sequelize;
|
||||||
|
|
||||||
|
const CuserSNBind = app.model2.define('cuser-snbind', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: false,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return CuserSNBind;
|
||||||
|
};
|
||||||
20
app/model3/SNNumber.js
Normal file
20
app/model3/SNNumber.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, STRING, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const SNNumber = app.model3.define('sn-number', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
sn_number: STRING(8),
|
||||||
|
status: INTEGER(3),
|
||||||
|
created_at: DATE,
|
||||||
|
updated_at: DATE,
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return SNNumber;
|
||||||
|
};
|
||||||
24
app/model4/Account.js
Normal file
24
app/model4/Account.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const Account = app.model4.define('account', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
uid: CHAR(15),
|
||||||
|
salt: CHAR(24),
|
||||||
|
contest_uid: CHAR(15),
|
||||||
|
account_name: STRING(20),
|
||||||
|
password: CHAR(64),
|
||||||
|
status: INTEGER(3),
|
||||||
|
created_at: DATE,
|
||||||
|
login_status: INTEGER(3)
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return Account;
|
||||||
|
};
|
||||||
21
app/model4/TSNMsg.js
Normal file
21
app/model4/TSNMsg.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING, TEXT, DATE } = app.Sequelize;
|
||||||
|
|
||||||
|
const TSNMsg = app.model4.define('tsn-msg', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
original_msg: TEXT,
|
||||||
|
msg_data: TEXT,
|
||||||
|
created_at: DATE,
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return TSNMsg;
|
||||||
|
};
|
||||||
18
app/model4/TuserSNBind.js
Normal file
18
app/model4/TuserSNBind.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (app) => {
|
||||||
|
const { INTEGER, CHAR, STRING } = app.Sequelize;
|
||||||
|
|
||||||
|
const TuserSNBind = app.model4.define('tuser-snbind', {
|
||||||
|
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
|
||||||
|
user_uid: CHAR(15),
|
||||||
|
sn_number: STRING(8),
|
||||||
|
},{
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamp: true,
|
||||||
|
createdAt: false,
|
||||||
|
updatedAt: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return TuserSNBind;
|
||||||
|
};
|
||||||
41
app/router.js
Normal file
41
app/router.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* @param {Egg.Application} app - egg application
|
||||||
|
*/
|
||||||
|
module.exports = app => {
|
||||||
|
const { router, controller, middleware } = app;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// 启动socket服务端
|
||||||
|
middleware.socket.socketServer(app);
|
||||||
|
}, 8000);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// 启动webSocket服务端
|
||||||
|
middleware.webSocket.webSocketServer(app);
|
||||||
|
}, 16000);
|
||||||
|
|
||||||
|
// 获取SN号
|
||||||
|
router.post('/getSN', controller.home.getSN);
|
||||||
|
// 搜索SN号
|
||||||
|
router.post('/searchSN', controller.home.searchSN);
|
||||||
|
// 搜索可绑定的SN号
|
||||||
|
router.get('/searchBindSN', controller.home.searchBindSN);
|
||||||
|
// 搜索可绑定的单位用户
|
||||||
|
router.get('/searchBindUser', controller.home.searchBindUser);
|
||||||
|
// 绑定SN号
|
||||||
|
router.post('/bindSN', controller.home.bindSN);
|
||||||
|
// 解绑SN号
|
||||||
|
router.post('/unBindingSN', controller.home.unBindingSN);
|
||||||
|
// 获取绑定记录
|
||||||
|
router.post('/getRecord', controller.home.getRecord);
|
||||||
|
// 存储消息记录
|
||||||
|
router.post('/shortMsg', controller.home.shortMsg);
|
||||||
|
// 获取历史消息
|
||||||
|
router.post('/getHistoryMsg', controller.home.getHistoryMsg);
|
||||||
|
// 删除历史消息
|
||||||
|
router.post('/delHistoryMsg', controller.home.delHistoryMsg);
|
||||||
|
// 获取单位用户
|
||||||
|
router.post('/bsideUserManager', controller.home.bsideUserManager);
|
||||||
|
// 获取可管理的SN号
|
||||||
|
router.post('/bsideSNManager', controller.home.bsideSNManager);
|
||||||
|
};
|
||||||
442
app/service/home.js
Normal file
442
app/service/home.js
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Service = require('../core/base_service');
|
||||||
|
|
||||||
|
const { Op } = require('sequelize');
|
||||||
|
|
||||||
|
const shunt = (uid) => {
|
||||||
|
return uid[uid.length - 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileName = 'home';
|
||||||
|
|
||||||
|
class HomeService extends Service {
|
||||||
|
// 获取SN号
|
||||||
|
async getSN(uid) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const where = { user_uid: uid };
|
||||||
|
const uidLastCode = shunt(uid);
|
||||||
|
const model = {
|
||||||
|
"B": ctx.model.BuserSNBind,
|
||||||
|
"C": ctx.model2.CuserSNBind,
|
||||||
|
"T": ctx.model4.TuserSNBind,
|
||||||
|
};
|
||||||
|
const result = await model[uidLastCode].findOne({ where });
|
||||||
|
return result || false;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "getSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索SN号
|
||||||
|
async searchSN(snNumber) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const where = { sn_number: snNumber };
|
||||||
|
const result = await ctx.model3.SNNumber.findOne({ where });
|
||||||
|
return result || false;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "searchSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索可绑定的SN号
|
||||||
|
async searchBindSN(uid) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const result = await ctx.model.BSide.findOne({ where: { uid, status: { [Op.not]: 2 }, role: 1 } });
|
||||||
|
if (!result || result.organization == null) return false;
|
||||||
|
const resultAdminSN = await ctx.model.BuserSNAdmin.findOne({ attributes: ['sn_set'], where: { user_uid: uid } });
|
||||||
|
if (!resultAdminSN) return false;
|
||||||
|
const adminSN = [];
|
||||||
|
resultAdminSN.sn_set.split(',').forEach(element => {
|
||||||
|
adminSN.push(element);
|
||||||
|
});
|
||||||
|
const where = { sn_number: { [Op.in]: adminSN }, status: 4 };
|
||||||
|
const resultBindSN = await ctx.model3.SNNumber.findAll({ attributes: ['sn_number'], where });
|
||||||
|
if (resultBindSN.length == 0) return false;
|
||||||
|
const bindSN = [];
|
||||||
|
resultBindSN.forEach(element => {
|
||||||
|
bindSN.push(element.dataValues.sn_number);
|
||||||
|
});
|
||||||
|
const resultData = adminSN.filter(item => bindSN.includes(item));
|
||||||
|
return resultData;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "searchBindSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索可绑定的单位用户
|
||||||
|
async searchBindUser(uid) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const result = await ctx.model.BSide.findOne({ where: { uid, status: { [Op.not]: 2 }, role: 1 } });
|
||||||
|
if (!result || result.organization == null) return false;
|
||||||
|
const resultAdminUser = await ctx.model.BSide.findAll({ attributes: ['uid', 'account_name'], where: { status: { [Op.not]: 2 }, organization: result.organization } });
|
||||||
|
const uidArr = [];
|
||||||
|
resultAdminUser.forEach(element => {
|
||||||
|
uidArr.push(element.dataValues.uid);
|
||||||
|
});
|
||||||
|
const where = { user_uid: { [Op.in]: uidArr } };
|
||||||
|
const resultBindUser = await ctx.model.BuserSNBind.findAll({ attributes: ['user_uid'], where });
|
||||||
|
if (resultBindUser.length == 0) return resultAdminUser;
|
||||||
|
const adminUser = [];
|
||||||
|
resultAdminUser.forEach(element => {
|
||||||
|
adminUser.push(element.dataValues);
|
||||||
|
});
|
||||||
|
const bindUser = [];
|
||||||
|
resultBindUser.forEach(element => {
|
||||||
|
bindUser.push(element.dataValues);
|
||||||
|
});
|
||||||
|
const resultData = [];
|
||||||
|
resultAdminUser.forEach(item => {
|
||||||
|
resultBindUser.forEach(element => {
|
||||||
|
if (item.dataValues.uid !== element.dataValues.user_uid) {
|
||||||
|
resultData.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return resultData;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "searchBindUser";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定SN号
|
||||||
|
async bindSN(uid, body) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const result = await ctx.model.BSide.findOne({ where: { uid, status: { [Op.not]: 2 }, role: 1 } });
|
||||||
|
if (!result || result.organization == null) return false;
|
||||||
|
const { snNumber, userUid } = body;
|
||||||
|
const where = { sn_number: snNumber };
|
||||||
|
const sn = await ctx.model3.SNNumber.findOne({ where });
|
||||||
|
if (!sn) return false;
|
||||||
|
const model = {
|
||||||
|
"B": ctx.model.BuserSNBind,
|
||||||
|
"C": ctx.model2.CuserSNBind,
|
||||||
|
"T": ctx.model2.TuserSNBind
|
||||||
|
};
|
||||||
|
const uidLastCode = shunt(userUid);
|
||||||
|
const bindCheck = await model[uidLastCode].findOne({ where: { user_uid: userUid } });
|
||||||
|
if (bindCheck) return false;
|
||||||
|
if (shunt(userUid) == 'B' && sn.status !== 4 || shunt(userUid) !== 'B' && sn.status !== 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
const status = shunt(userUid) == 'B' ? 1 : shunt(userUid) == 'C' ? 2 : 3;
|
||||||
|
const snResult = await ctx.model3.SNNumber.update({ status }, { where });
|
||||||
|
const bindForm = {
|
||||||
|
user_uid: userUid,
|
||||||
|
sn_number: snNumber
|
||||||
|
};
|
||||||
|
const resultForm = {
|
||||||
|
user_uid: userUid,
|
||||||
|
sn_number: snNumber,
|
||||||
|
type: 1,
|
||||||
|
created_at: new Date()
|
||||||
|
};
|
||||||
|
const modelName = {
|
||||||
|
"B": ctx.model.BindBSNrecord,
|
||||||
|
"C": ctx.model2.BindCSNrecord
|
||||||
|
};
|
||||||
|
const bindResult = await model[uidLastCode].create(bindForm);
|
||||||
|
const recordResult = await modelName[uidLastCode].create(resultForm);
|
||||||
|
return snResult[0] && bindResult && recordResult ? true : false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "bindSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解绑SN号
|
||||||
|
async unBindingSN(uid, body) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const result = await ctx.model.BSide.findOne({ where: { uid, status: { [Op.not]: 2 }, role: 1 } });
|
||||||
|
if (!result || result.organization == null) return false;
|
||||||
|
const { snNumber, userUid } = body;
|
||||||
|
const snWhere = { sn_number: snNumber };
|
||||||
|
const snResult = await ctx.model3.SNNumber.update({ status: 0 }, { where: snWhere });
|
||||||
|
if (snResult[0] !== 0) {
|
||||||
|
const where = {
|
||||||
|
user_uid: userUid,
|
||||||
|
sn_number: snNumber
|
||||||
|
};
|
||||||
|
const form = {
|
||||||
|
user_uid: userUid,
|
||||||
|
sn_number: snNumber,
|
||||||
|
type: 0,
|
||||||
|
created_at: new Date()
|
||||||
|
};
|
||||||
|
const uidLastCode = shunt(userUid);
|
||||||
|
const model = {
|
||||||
|
"B": ctx.model.BuserSNBind,
|
||||||
|
"C": ctx.model2.CuserSNBind,
|
||||||
|
"T": ctx.model2.TuserSNBind,
|
||||||
|
};
|
||||||
|
const modelName = {
|
||||||
|
"B": ctx.model.BindBSNrecord,
|
||||||
|
"C": ctx.model2.BindCSNrecord
|
||||||
|
};
|
||||||
|
const bindResult = await model[uidLastCode].destroy({ where });
|
||||||
|
const recordResult = await modelName[uidLastCode].create(form);
|
||||||
|
return bindResult && recordResult ? true : false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "unBindingSN";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取绑定记录
|
||||||
|
async getRecord(uid, body) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
let { offset, limit, searchOptions, sortOptions } = body;
|
||||||
|
offset = (offset - 1) * limit;
|
||||||
|
let attributes = ['user_uid', 'sn_number', 'type', 'created_at'],
|
||||||
|
where = { user_uid: uid }, order = [], dbOptions, joinSubstring = [],
|
||||||
|
substring = ['user_uid', 'sn_number'], key = ['type'], between = ['created_at'];
|
||||||
|
const uidLastCode = shunt(uid);
|
||||||
|
attributes.forEach(element => {
|
||||||
|
if (searchOptions[element]) {
|
||||||
|
if(searchOptions[element] == '*空') {
|
||||||
|
if(joinSubstring.includes(element)) {
|
||||||
|
where[element] = null;
|
||||||
|
} else {
|
||||||
|
where[element] = [null, ''];
|
||||||
|
}
|
||||||
|
} else if(substring.includes(element)) {
|
||||||
|
where[element] = { [Op.substring]: searchOptions[element] };
|
||||||
|
} else if (key.includes(element)) {
|
||||||
|
where[element] = searchOptions[element] == "1" ? uidLastCode === 'B' ? 1 : 2 : 0;
|
||||||
|
} else if (between.includes(element)) {
|
||||||
|
where[element] = { [Op.between]: [searchOptions[element][0], searchOptions[element][1]] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortOptions[element] == true) {
|
||||||
|
order.push([element, 'ASC']);
|
||||||
|
} else if (sortOptions[element] == false) {
|
||||||
|
order.push([element, 'DESC']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dbOptions = { attributes, offset, limit, where, order };
|
||||||
|
const model = {
|
||||||
|
"B": ctx.model.BSide,
|
||||||
|
"C": ctx.model2.CSide,
|
||||||
|
};
|
||||||
|
const modelName = {
|
||||||
|
"B": ctx.model.BindBSNrecord,
|
||||||
|
"C": ctx.model2.BindCSNrecord,
|
||||||
|
};
|
||||||
|
const user = await model[uidLastCode].findAll({ attributes: ['uid', 'account_name'] });
|
||||||
|
const result = await modelName[uidLastCode].findAndCountAll(dbOptions);
|
||||||
|
result.rows.forEach(element => {
|
||||||
|
element.dataValues.account_name = '';
|
||||||
|
user.filter(item => {
|
||||||
|
if (item.dataValues.uid == element.dataValues.user_uid) {
|
||||||
|
element.dataValues.account_name = item.dataValues.account_name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return result.rows.length == 0 ? false : result;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "getRecord";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储消息记录
|
||||||
|
async shortMsg(form) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const where = { sn_number: form.sn_number };
|
||||||
|
const SN = await ctx.model3.SNNumber.findOne({ where });
|
||||||
|
if (!SN) {
|
||||||
|
ctx.app.middleware.utils.log('../../../unknownSNLog', form);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const model = {
|
||||||
|
1: ctx.model.BuserSNBind,
|
||||||
|
2: ctx.model2.CuserSNBind,
|
||||||
|
3: ctx.model4.TuserSNBind,
|
||||||
|
};
|
||||||
|
const bind = await model[SN.dataValues.status].findOne({ where });
|
||||||
|
if (!bind) return false;
|
||||||
|
form.user_uid = bind.dataValues.user_uid;
|
||||||
|
const uidLastCode = shunt(form.user_uid);
|
||||||
|
const modelName = {
|
||||||
|
"B": ctx.model.BSNMsg,
|
||||||
|
"C": ctx.model2.CSNMsg,
|
||||||
|
"T": ctx.model4.TSNMsg,
|
||||||
|
};
|
||||||
|
const result = await modelName[uidLastCode].create(form);
|
||||||
|
return result || false;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "shortMsg";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取历史消息
|
||||||
|
async getHistoryMsg(uid, body) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
let { offset, limit, searchOptions, sortOptions } = body;
|
||||||
|
offset = (offset - 1) * limit;
|
||||||
|
let attributes = ['original_msg', 'sn_number', 'msg_data', 'created_at'],
|
||||||
|
where = { user_uid: uid }, order = [], dbOptions, joinSubstring = [],
|
||||||
|
substring = ['original_msg', 'sn_number', 'msg_data'], key = [], between = ['created_at'];
|
||||||
|
attributes.forEach(element => {
|
||||||
|
if (searchOptions[element]) {
|
||||||
|
if(searchOptions[element] == '*空') {
|
||||||
|
if(joinSubstring.includes(element)) {
|
||||||
|
where[element] = null;
|
||||||
|
} else {
|
||||||
|
where[element] = [null, ''];
|
||||||
|
}
|
||||||
|
} else if (substring.includes(element)) {
|
||||||
|
where[element] = { [Op.substring]: searchOptions[element] };
|
||||||
|
} else if (key.includes(element)) {
|
||||||
|
where[element] = searchOptions[element] == "1" ? true : false;
|
||||||
|
} else if (between.includes(element)) {
|
||||||
|
where[element] = { [Op.between]: [searchOptions[element][0], searchOptions[element][1]] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortOptions[element] == true) {
|
||||||
|
order.push([element, 'ASC']);
|
||||||
|
} else if (sortOptions[element] == false) {
|
||||||
|
order.push([element, 'DESC']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dbOptions = { attributes, offset, limit, where, order };
|
||||||
|
const uidLastCode = shunt(uid);
|
||||||
|
const model = {
|
||||||
|
"B": ctx.model.BSNMsg,
|
||||||
|
"C": ctx.model2.CSNMsg,
|
||||||
|
"T": ctx.model4.TSNMsg,
|
||||||
|
};
|
||||||
|
const result = await model[uidLastCode].findAndCountAll(dbOptions);
|
||||||
|
return result.rows.length == 0 ? false : result;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "getHistoryMsg";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除历史消息
|
||||||
|
async delHistoryMsg(uid, modelType, password, requestMsg) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const uidLastCode = shunt(uid);
|
||||||
|
const model = {
|
||||||
|
"B": ctx.model.BSide,
|
||||||
|
"C": ctx.model2.CSide,
|
||||||
|
"T": ctx.model4.Account,
|
||||||
|
};
|
||||||
|
const result = await model[uidLastCode].findOne({ where: { uid } });
|
||||||
|
if (!result || result.dataValues.password !== this.shaForm(password, this.decryptRequest(result.dataValues.salt))) return false;
|
||||||
|
let where = {};
|
||||||
|
if (modelType == "single") {
|
||||||
|
const { sn_number, msg_data, origin_time } = requestMsg;
|
||||||
|
where = { user_uid: uid, sn_number, msg_data, created_at: origin_time };
|
||||||
|
} else if (modelType == "multiple") {
|
||||||
|
let sn_number = [], msg_data = [], created_at = [];
|
||||||
|
for (const key in requestMsg) {
|
||||||
|
requestMsg[key].forEach(element => {
|
||||||
|
sn_number.push(element.sn_number),
|
||||||
|
msg_data.push(element.msg_data),
|
||||||
|
created_at.push(element.origin_time)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
where = { user_uid: uid, sn_number, msg_data, created_at };
|
||||||
|
} else if (modelType == "all") {
|
||||||
|
where = { user_uid: uid };
|
||||||
|
}
|
||||||
|
const modelName = {
|
||||||
|
"B": ctx.model.BSNMsg,
|
||||||
|
"C": ctx.model2.CSNMsg,
|
||||||
|
"T": ctx.model4.TSNMsg,
|
||||||
|
};
|
||||||
|
const resetList = await modelName[uidLastCode].destroy({ where });
|
||||||
|
return resetList.length == 0 ? false : resetList;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "delHistoryMsg";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取单位用户
|
||||||
|
async bsideUserManager(uid, body) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const result = await ctx.model.BSide.findOne({ where: { uid, status: { [Op.not]: 2 }, role: 1 } });
|
||||||
|
if (!result || result.organization == null) return false;
|
||||||
|
let { offset, limit, searchOptions } = body;
|
||||||
|
offset = (offset - 1) * limit;
|
||||||
|
let attributes = ['account_name', 'user_name', 'phone'],
|
||||||
|
where = { organization: result.organization, role: { [Op.not]: 1 } }, dbOptions, joinSubstring = [];
|
||||||
|
attributes.forEach(element => {
|
||||||
|
if (searchOptions[element]) {
|
||||||
|
if(searchOptions[element] == '*空') {
|
||||||
|
if(joinSubstring.includes(element)) {
|
||||||
|
where[element] = null;
|
||||||
|
} else {
|
||||||
|
where[element] = [null, ''];
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
where[element] = { [Op.substring]: searchOptions[element] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dbOptions = { attributes, offset, limit, where };
|
||||||
|
const userList = await ctx.model.BSide.findAndCountAll(dbOptions);
|
||||||
|
return userList.rows.length == 0 ? false : userList;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "bsideUserManager";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取可管理的SN号
|
||||||
|
async bsideSNManager(uid) {
|
||||||
|
const { ctx } = this;
|
||||||
|
try {
|
||||||
|
const result = await ctx.model.BSide.findOne({ where: { uid, status: { [Op.not]: 2 }, role: 1 } });
|
||||||
|
if (!result || result.organization == null) return false;
|
||||||
|
let attributes = ['length', 'sn_set'],
|
||||||
|
where = { user_uid: uid }, dbOptions;
|
||||||
|
dbOptions = { attributes, where };
|
||||||
|
const snMsg = await ctx.model.BuserSNAdmin.findOne(dbOptions);
|
||||||
|
if (!snMsg) return false;
|
||||||
|
const snList = snMsg.dataValues.sn_set.split(',');
|
||||||
|
const snResult = await ctx.model3.SNNumber.findAll({ attributes: ['sn_number', 'status', 'updated_at'], where: { sn_number: { [Op.in]: snList } } });
|
||||||
|
return snResult.length == 0 ? false : snResult;
|
||||||
|
} catch (error) {
|
||||||
|
const blockName = fileName + "--" + "bsideSNManager";
|
||||||
|
ctx.app.middleware.utils.log('../../../serviceLog', blockName + ">>>>" + error);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = HomeService;
|
||||||
230
config/config.default.js
Normal file
230
config/config.default.js
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
/* eslint valid-jsdoc: "off" */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Egg.EggAppInfo} appInfo app info
|
||||||
|
*/
|
||||||
|
|
||||||
|
const process = require('process'),
|
||||||
|
path = require('path');
|
||||||
|
|
||||||
|
module.exports = appInfo => {
|
||||||
|
/**
|
||||||
|
* built-in config
|
||||||
|
* @type {Egg.EggAppConfig}
|
||||||
|
**/
|
||||||
|
const config = exports = {};
|
||||||
|
|
||||||
|
// use for cookie sign key, should change to your own and keep security
|
||||||
|
config.keys = appInfo.name + '_1772613754664_3442';
|
||||||
|
|
||||||
|
// add your middleware config here
|
||||||
|
// config.middleware = [];
|
||||||
|
|
||||||
|
// 修改Egg.js的public路径配置到运行路径下
|
||||||
|
config.static = {
|
||||||
|
prefix: '/',
|
||||||
|
dir: process.cwd() + '/public',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 配置执行时临时文件的路径到运行路径
|
||||||
|
config.rundir = process.cwd() + '/run';
|
||||||
|
|
||||||
|
// 配置普通日志文件地址
|
||||||
|
config.logger = {
|
||||||
|
dir: path.join(process.cwd(), 'logs'),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 配置定时任务日志文件地址
|
||||||
|
config.customLogger = {
|
||||||
|
scheduleLogger: {
|
||||||
|
file: path.join(process.cwd(), 'logs', 'egg-schedule.log'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
config.security = {
|
||||||
|
csrf: {
|
||||||
|
enable: false
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// socket服务端配置
|
||||||
|
config.socketServer = {
|
||||||
|
ip: '127.0.0.1',
|
||||||
|
port: 8100
|
||||||
|
};
|
||||||
|
|
||||||
|
// webSocket服务端配置
|
||||||
|
config.webSocketServer = {
|
||||||
|
ip: '127.0.0.1',
|
||||||
|
port: 8110,
|
||||||
|
// path: '/snShortMessage/'
|
||||||
|
// path: '/snWebSocket/'
|
||||||
|
path: '/socket.io/',
|
||||||
|
allowedOrigins: "http://127.0.0.1"
|
||||||
|
};
|
||||||
|
|
||||||
|
config.redis = {
|
||||||
|
// 开发/测试环境
|
||||||
|
clients: {
|
||||||
|
db0: {
|
||||||
|
port: 6379,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
password: '74191221',
|
||||||
|
db: 0,
|
||||||
|
},
|
||||||
|
db1: {
|
||||||
|
port: 6379,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
password: '74191221',
|
||||||
|
db: 1,
|
||||||
|
},
|
||||||
|
db2: {
|
||||||
|
port: 6379,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
password: '74191221',
|
||||||
|
db: 2,
|
||||||
|
},
|
||||||
|
db3: {
|
||||||
|
port: 6379,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
password: '74191221',
|
||||||
|
db: 3,
|
||||||
|
},
|
||||||
|
db5: {
|
||||||
|
port: 6379,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
password: '74191221',
|
||||||
|
db: 5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// 生产环境
|
||||||
|
// clients: {
|
||||||
|
// db0: {
|
||||||
|
// port: 6379,
|
||||||
|
// host: '127.0.0.1',
|
||||||
|
// password: 'bd3@htcc2023',
|
||||||
|
// db: 2,
|
||||||
|
// },
|
||||||
|
// db1: {
|
||||||
|
// port: 6379,
|
||||||
|
// host: '127.0.0.1',
|
||||||
|
// password: 'bd3@htcc2023',
|
||||||
|
// db: 3,
|
||||||
|
// },
|
||||||
|
// db2: {
|
||||||
|
// port: 6379,
|
||||||
|
// host: '127.0.0.1',
|
||||||
|
// password: 'bd3@htcc2023',
|
||||||
|
// db: 4,
|
||||||
|
// },
|
||||||
|
// db3: {
|
||||||
|
// port: 6379,
|
||||||
|
// host: '127.0.0.1',
|
||||||
|
// password: 'bd3@htcc2023',
|
||||||
|
// db: 5,
|
||||||
|
// },
|
||||||
|
// db5: {
|
||||||
|
// port: 6379,
|
||||||
|
// host: '127.0.0.1',
|
||||||
|
// password: 'bd3@htcc2023',
|
||||||
|
// db: 7,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
config.sequelize = {
|
||||||
|
// 开发/测试环境
|
||||||
|
datasources: [
|
||||||
|
{
|
||||||
|
dialect: 'mariadb',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3306,
|
||||||
|
username: 'root',
|
||||||
|
password: '74191221',
|
||||||
|
database: 'bside',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialect: 'mariadb',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3306,
|
||||||
|
username: 'root',
|
||||||
|
password: '74191221',
|
||||||
|
database: 'cside',
|
||||||
|
delegate: 'model2',
|
||||||
|
baseDir: 'model2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialect: 'mariadb',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3306,
|
||||||
|
username: 'root',
|
||||||
|
password: '74191221',
|
||||||
|
database: 'insiders',
|
||||||
|
delegate: 'model3',
|
||||||
|
baseDir: 'model3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dialect: 'mariadb',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3306,
|
||||||
|
username: 'root',
|
||||||
|
password: '74191221',
|
||||||
|
database: 'bdContest',
|
||||||
|
delegate: 'model4',
|
||||||
|
baseDir: 'model4',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
// 生产环境
|
||||||
|
// datasources: [
|
||||||
|
// {
|
||||||
|
// dialect: 'mariadb',
|
||||||
|
// host: 'localhost',
|
||||||
|
// port: 3306,
|
||||||
|
// username: 'bdqh_platform',
|
||||||
|
// password: '124689@XXxx',
|
||||||
|
// database: 'bside',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// dialect: 'mariadb',
|
||||||
|
// host: 'localhost',
|
||||||
|
// port: 3306,
|
||||||
|
// username: 'bdqh_platform',
|
||||||
|
// password: '124689@XXxx',
|
||||||
|
// database: 'cside',
|
||||||
|
// delegate: 'model2',
|
||||||
|
// baseDir: 'model2',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// dialect: 'mariadb',
|
||||||
|
// host: 'localhost',
|
||||||
|
// port: 3306,
|
||||||
|
// username: 'bdqh_platform',
|
||||||
|
// password: '124689@XXxx',
|
||||||
|
// database: 'insiders',
|
||||||
|
// delegate: 'model3',
|
||||||
|
// baseDir: 'model3',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// dialect: 'mariadb',
|
||||||
|
// host: 'localhost',
|
||||||
|
// port: 3306,
|
||||||
|
// username: 'bdqh_platform',
|
||||||
|
// password: '124689@XXxx',
|
||||||
|
// database: 'bdContest',
|
||||||
|
// delegate: 'model4',
|
||||||
|
// baseDir: 'model4',
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
};
|
||||||
|
|
||||||
|
// add your user config here
|
||||||
|
const userConfig = {
|
||||||
|
// myAppName: 'egg',
|
||||||
|
salt: 'shortMessage'
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...config,
|
||||||
|
...userConfig,
|
||||||
|
};
|
||||||
|
};
|
||||||
27
config/plugin.js
Normal file
27
config/plugin.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/** @type Egg.EggPlugin */
|
||||||
|
module.exports = {
|
||||||
|
// had enabled by egg
|
||||||
|
// static: {
|
||||||
|
// enable: true,
|
||||||
|
// }
|
||||||
|
|
||||||
|
CryptoJS : {
|
||||||
|
enable: true,
|
||||||
|
package: 'crypto-js',
|
||||||
|
},
|
||||||
|
|
||||||
|
redis : {
|
||||||
|
enable: true,
|
||||||
|
package: 'egg-redis',
|
||||||
|
},
|
||||||
|
|
||||||
|
sequelize : {
|
||||||
|
enable: true,
|
||||||
|
package: 'egg-sequelize',
|
||||||
|
},
|
||||||
|
|
||||||
|
validate : {
|
||||||
|
enable: true,
|
||||||
|
package: 'egg-validate',
|
||||||
|
},
|
||||||
|
};
|
||||||
8
controllerLog/2026/3/16.txt
Normal file
8
controllerLog/2026/3/16.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[2026-3-16>>>17:27:28]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:27:28]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:27:28]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:27:28]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:29:44]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:29:44]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:29:44]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:29:45]>>>home--bsideSNManager>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
5
jsconfig.json
Normal file
5
jsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
50
package.json
Normal file
50
package.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "tqxz-sn-message-platform",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"private": true,
|
||||||
|
"egg": {
|
||||||
|
"declarations": true
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"egg": "^3.17.5",
|
||||||
|
"egg-redis": "^2.6.0",
|
||||||
|
"egg-scripts": "^3.0.1",
|
||||||
|
"egg-sequelize": "^6.0.0",
|
||||||
|
"egg-validate": "^2.0.2",
|
||||||
|
"gbk.js": "^0.3.0",
|
||||||
|
"ioredis": "^5.4.1",
|
||||||
|
"mariadb": "^3.5.2",
|
||||||
|
"mysql2": "^3.19.0",
|
||||||
|
"sequelize": "^6.37.8",
|
||||||
|
"socket.io": "^4.7.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"egg-bin": "6",
|
||||||
|
"egg-mock": "5",
|
||||||
|
"eslint": "8",
|
||||||
|
"eslint-config-egg": "13",
|
||||||
|
"sequelize-cli": "^6.6.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"reload": "egg-scripts stop --title=egg-server-tqxz-sn-message-platform && egg-scripts start --port=8120 --workers=1 --daemon --title=egg-server-tqxz-sn-message-platform --ignore-stderr",
|
||||||
|
"start": "egg-scripts start --port=8120 --workers=1 --daemon --title=egg-server-tqxz-sn-message-platform --ignore-stderr",
|
||||||
|
"stop": "egg-scripts stop --title=egg-server-tqxz-sn-message-platform",
|
||||||
|
"dev": "egg-bin dev --port=8120",
|
||||||
|
"test": "npm run lint -- --fix && npm run test:local",
|
||||||
|
"test:local": "egg-bin test",
|
||||||
|
"cov": "egg-bin cov",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"ci": "npm run lint && npm run cov"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
3
serviceLog/2026/3/16.txt
Normal file
3
serviceLog/2026/3/16.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[2026-3-16>>>17:46:6]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:51:52]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-16>>>17:51:52]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
35
serviceLog/2026/3/17.txt
Normal file
35
serviceLog/2026/3/17.txt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
[2026-3-17>>>9:23:42]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:43:23]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:43:23]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:51:38]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:51:38]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:51:47]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:51:47]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:51:54]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:51:54]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:52:52]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:52:52]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:53:18]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>9:53:18]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:59:15]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>9:59:15]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>10:11:11]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>10:11:11]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:3:21]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:3:21]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>11:16:39]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:16:39]>>>home--searchBindSN>>>>Error: Invalid value { status: 4 }
|
||||||
|
[2026-3-17>>>11:30:56]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:31:48]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:33:49]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:36:3]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:36:34]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:37:34]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:40:36]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:41:19]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>11:43:23]>>>home--searchBindUser>>>>TypeError: Cannot read properties of undefined (reading 'length')
|
||||||
|
[2026-3-17>>>12:4:12]>>>home--bindSN>>>>TypeError: Cannot read properties of null (reading 'value')
|
||||||
|
[2026-3-17>>>12:4:36]>>>home--bindSN>>>>TypeError: Cannot read properties of null (reading 'value')
|
||||||
|
[2026-3-17>>>15:4:17]>>>home--bindSN>>>>TypeError: Cannot read properties of null (reading 'value')
|
||||||
|
[2026-3-17>>>15:17:51]>>>home--searchBindUser>>>>ReferenceError: item is not defined
|
||||||
2
serviceLog/2026/3/27.txt
Normal file
2
serviceLog/2026/3/27.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[2026-3-27>>>9:49:20]>>>home--getHistoryMsg>>>>SequelizeDatabaseError: (conn:78, no: 1267, SQLState: HY000) Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation 'like'
|
||||||
|
sql: SELECT count(*) AS `count` FROM `bsn-msg` AS `bsn-msg` WHERE `bsn-msg`.`user_uid` = '20240613698218B' AND `bsn-msg`.`original_msg` LIKE '%测试%'; - parameters:[]
|
||||||
23
test/app/controller/home.test.js
Normal file
23
test/app/controller/home.test.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
const { strict: assert } = require('node:assert');
|
||||||
|
const path = require('node:path');
|
||||||
|
const { statSync } = require('node:fs');
|
||||||
|
const { app } = require('egg-mock/bootstrap');
|
||||||
|
|
||||||
|
describe('test/app/controller/home.test.js', () => {
|
||||||
|
it('should assert', async () => {
|
||||||
|
const pkg = require('../../../package.json');
|
||||||
|
assert(app.config.keys.startsWith(pkg.name));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should typings exists', async () => {
|
||||||
|
const typings = path.join(__dirname, '../../../typings');
|
||||||
|
assert(statSync(typings));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should GET /', async () => {
|
||||||
|
return app.httpRequest()
|
||||||
|
.get('/')
|
||||||
|
.expect('hi, egg')
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
5
unknownSNLog/2026/3/17.txt
Normal file
5
unknownSNLog/2026/3/17.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[2026-3-17>>>16:12:0]>>>[object Object]
|
||||||
|
[2026-3-17>>>16:12:20]>>>[object Object]
|
||||||
|
[2026-3-17>>>16:14:3]>>>[object Object]
|
||||||
|
[2026-3-17>>>16:26:36]>>>[object Object]
|
||||||
|
[2026-3-17>>>17:31:20]>>>[object Object]
|
||||||
Reference in New Issue
Block a user