明树Git Lab

Commit d6846709 authored by zfp1's avatar zfp1

update

parent 1d6ed170
WECHAT_TOKEN=deepseektest
DEEPSEEK_API_KEY=sk-14f0cf16bad245169cd2563e0f9b678e
PORT=3001
\ No newline at end of file
node_modules/
.git
package-lock.json
.vscode
test/
test.js
public/avatar
\ No newline at end of file
registry=https://registry.npmmirror.com
\ No newline at end of file
# 文件结构
| 目录 | 注释 |
| --- | --- |
| config | 配置 |
| controller | 控制器 |
| cron | 定时任务 |
| db | 数据库初始化 |
| middlerware | 中间件 |
| module | 数据操作 |
| public | 公共文件 |
| router | 路由 |
| utils | 工具方法 |
# 命名
| 简称 | 解释 |
| --- | --- |
| IPS | 虫情 |
| SMC | 土壤墒情 |
| WS | 气象 |
| ACMS | 农事综合管理系统 |
| IET | 环境检测 |
| IQI | 质量信息 |
# 记录
项目启动之初,项目结构定位简单易懂,各个路由及方法跳转均可直接点击,方便驻场人员参与
```
1. 待完成excel导出 -- 这个要看前端做管理端菜单管理,需要知道在那个菜单 对应哪个表
2. 农业投入品表的增删改查 已完成
硬件入场:
1. 需要确认每一个设备的设备信息:名称、设备编号、设备类型
2. 需要确认每一个设备 对应的 每一个地块的位置信息
3. 需要确认每一个种类设备 上传的信息 接口调试
4.
--近期更新
1. 简单的流程结构flowDef,不暴露给前端,等用户给定流程审批信息,接口创建流程模板
2. 从入库逻辑开始 入库单增删改查、入库单开启流程......
1. 收获周期管理,按名称与导入对应
2. 农事预警,脚本每日扫描一次,到对应周期则提示周期信息
```
{
"tokenEx": 86400000000,
"dbURI": "mongodb://127.0.0.1:27017/letian?authSource=admin"
}
\ No newline at end of file
const config = require(`./${process.env.NODE_ENV}.json`);
global.sysConfig = config;
\ No newline at end of file
{
"tokenEx": 86400,
"dbURI": "mongodb://root:letian2024.@119.29.111.186:27017/letian?authSource=admin"
}
\ No newline at end of file
{
"tokenEx": 86400,
"dbURI": "mongodb://root:letian2024.@127.0.0.1:27017/letian?authSource=admin",
"file": {
"storagePath": "/mnt/vdb1/uploadfiles"
}
}
\ No newline at end of file
async function createQuestion(params) {
try {
let body = req.body;
let ret = await DB.Question.create(body);
res.sendData(ret)
} catch (error) {
res.sendError({
code: 5000,
message: "创建问题失败"
})
}
}
async function getQuesList(params) {
try {
let search = {
openid: req.body.openid
}
let page = req.body.page || 1;
let pageSize = req.body.pageSize || 10;
let skip = (page - 1) * pageSize;
let count = await DB.Question.countDocuments({search});
let list = await DB.Question.find(search).skip(skip).limit(pageSize);
res.sendData({list, count});
} catch (error) {
res.sendError({
code: 5000,
message: "获取消息失败"
})
}
}
module.exports = {
createQuestion,
getQuesList
}
\ No newline at end of file
const userModule = require('../module/userModule')
// 配置参数(需替换)
const config = {
appId: '你的公众号APPID',
appSecret: '你的公众号APPSECRET',
redirectUri: encodeURIComponent('http://前端域名/wechat-auth') // 需与公众号配置一致
}
// 1. 生成授权链接
async function genAuthUrl(req, res, next) {
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?
appid=${config.appId}&
redirect_uri=${config.redirectUri}&
response_type=code&
scope=snsapi_userinfo&
state=STATE#wechat_redirect`.replace(/\s+/g, '')
res.sendData(authUrl)
}
// 2. 获取用户信息
async function getUserInfo(params) {
try {
const { code } = req.query || req.body;
// 第一步:用code换取access_token
const tokenRes = await axios.get(
`https://api.weixin.qq.com/sns/oauth2/access_token?
appid=${config.appId}&
secret=${config.appSecret}&
code=${code}&
grant_type=authorization_code`.replace(/\s+/g, '')
)
// 第二步:获取用户信息
const { access_token, openid } = tokenRes.data
const userRes = await axios.get(
`https://api.weixin.qq.com/sns/userinfo?
access_token=${access_token}&
openid=${openid}&
lang=zh_CN`.replace(/\s+/g, '')
)
// 第三步 存起来
await userModule.createUser(userRes.data);
res.sendData(userRes.data)
} catch (error) {
console.error(' 微信接口错误:', error.response?.data)
res.sendError({
code: 5000,
message: "微信授权失败"
})
}
}
module.exports = {
genAuthUrl,
getUserInfo
}
\ No newline at end of file
const mongoose = require('mongoose');
// 连接字符串,格式为 mongodb://用户名:密码@地址:端口/数据库名
const dbURI = sysConfig.dbURI || 'mongodb://localhost:27017/wechat';
// 连接数据库
console.log(dbURI, "000-0-0-0-0-0-0")
mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
// 连接断开时的监听
mongoose.connection.on('disconnected', () => {
console.log('MongoDB Disconnected');
});
const User = require('./models/systemUser');
const RequestLog = require('./models/systemRequestLog');
const Question = require('./models/question');
global.DB = {
User,
Question,
RequestLog,
}
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const moment = require('moment');
/**
* 用户
*/
const questionSchema = new Schema({
openid: { type: String, required: true }, // 微信用户唯一标识
question: String, // 用户昵称
answer: String,
createdAt: {
type: Date,
default: Date.now,
get: v => moment(v).format("YYYY-MM-DD HH:mm:ss"),
},
updatedAt: {
type: Date,
default: Date.now,
get: v => moment(v).format("YYYY-MM-DD HH:mm:ss"),
},
del: {
type: Number,
default: 0,
comment: '默认0 , 1:表示删除,若有其他隐藏业务 不要混用此字段。'
}
}, {
id: false,
toJSON: {
getters: true,
}
});
const Question = mongoose.model('Question', questionSchema, 'Question');
module.exports = Question;
\ No newline at end of file
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const moment = require('moment');
/**
* 系统接口访问日志
*/
const requestLogSchema = new Schema({
reqId: {
type: String,
comment: "给每一个请求分配一个id"
},
user: {
type: String,
},
url: {
type: String,
},
params: {
type: String,
comment: "请求参数"
},
headers: {
type: String,
comment: "请求头"
},
method: {
type: String,
comment: "请求方法"
},
result: {
type: String,
comment: "返回结果"
},
status: {
type: String,
comment: "http请求状态"
},
msg: {
type: String,
comment: "http请求错误信息"
},
type: {
type: String,
comment: "日志类型 调用外部硬件接口日志:device, 系统内部请求日志:system",
default: "system"
},
createdAt: {
type: Date,
default: Date.now,
get: v => moment(v).format("YYYY-MM-DD HH:mm:ss"),
},
updatedAt: {
type: Date,
default: Date.now,
get: v => moment(v).format("YYYY-MM-DD HH:mm:ss"),
}
}, {
toJSON: {
getters: true
}
});
const RequestLog = mongoose.model('RequestLog', requestLogSchema, 'systemRequestLog');
module.exports = RequestLog;
\ No newline at end of file
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const moment = require('moment');
/**
* 用户
*/
const userSchema = new Schema({
openid: { type: String, required: true }, // 微信用户唯一标识
nickname: String, // 用户昵称
headimgurl: String, // 微信头像URL
city: String,
createdAt: {
type: Date,
default: Date.now,
get: v => moment(v).format("YYYY-MM-DD HH:mm:ss"),
},
updatedAt: {
type: Date,
default: Date.now,
get: v => moment(v).format("YYYY-MM-DD HH:mm:ss"),
},
del: {
type: Number,
default: 0,
comment: '默认0 , 1:表示删除,若有其他隐藏业务 不要混用此字段。'
}
}, {
id: false,
toJSON: {
getters: true,
}
});
const User = mongoose.model('User', userSchema, 'systemUser');
module.exports = User;
\ No newline at end of file
const Redis = require('ioredis');
const redis = new Redis({
port: 6379,
host: "127.0.0.1",
password: "Mingshu20170706",
db: 0,
});
module.exports = redis;
\ No newline at end of file
let curDate = new Date();
let curDateStr = curDate.getFullYear() + "" + String(curDate.getMonth() + 1).padStart(2, '0') + "" + curDate.getDate();
module.exports = {
apps: [{
name: "letian",
script: 'server.js',
watch: true,
ignore_watch: ['node_modules', 'logs'],
env_dev: {
NODE_ENV: "dev",
},
env_production: {
NODE_ENV: "production",
PORT:3000
},
log_date_format: "YYYY-MM-DD HH:mm:ss",
out_file: `/srv/letian/logs/${curDateStr}.log`,
error_file: `/srv/letian/logs/${curDateStr}.log`,
}]
};
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const { parseString, Builder } = require('xml2js');
const axios = require('axios');
const app = express();
const port = process.env.PORT || 3000;
console.log(process.env)
// 中间件配置
app.use(bodyParser.text({ type: 'text/xml' }));
app.use(express.json());
// 微信公众号签名验证
const validateWechatSignature = (req) => {
const { signature, timestamp, nonce } = req.query;
if (!signature || !timestamp || !nonce) return false;
const token = process.env.WECHAT_TOKEN;
const sortedStr = [token, timestamp, nonce].sort().join('');
const sha1 = crypto.createHash('sha1').update(sortedStr).digest('hex');
return sha1 === signature;
};
// 处理微信服务器验证
app.get('/wechat', (req, res) => {
if (!validateWechatSignature(req)) {
console.error('Signature validation failed');
return res.status(403).send('Invalid signature');
}
res.send(req.query.echostr);
});
const msgIdCache = new Set();
// 处理微信消息
app.post('/wechat', async (req, res) => {
// try {
// 1. 验证签名
if (!validateWechatSignature(req)) {
console.error('Invalid signature in POST');
return res.status(403).send('Forbidden');
}
// 2. 解析XML消息
const xmlData = await new Promise((resolve, reject) => {
parseString(req.body, (err, result) => {
err ? reject(err) : resolve(result.xml);
});
});
const MsgId = xmlData.MsgId[0];
if (msgIdCache.has(MsgId)) {
return res.send(''); // 拦截重复请求
}
// 3. 提取消息内容
const message = {
toUser: xmlData.ToUserName[0],
fromUser: xmlData.FromUserName[0],
content: xmlData.Content?.[0] || '',
msgType: xmlData.MsgType[0]
};
console.log('Received message:', message);
// 4. 只处理文本消息
if (message.msgType !== 'text') {
return res.send(buildTextResponse(message, '暂不支持此类型消息'));
}
// 5. 调用DeepSeek API
const deepseekResponse = await callDeepSeekAPI(message.content);
if (deepseekResponse.length > 100) {
deepseekResponse = deepseekResponse.substring(0, 100) + '... (Answer truncated)';
}
deepseekResponse= escapeXml(deepseekResponse);
// 6. 构建响应XML
const responseXml =`
<xml>
<ToUserName><![CDATA[${xmlData.xml.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${xmlData.xml.ToUserName}]]></FromUserName>
<CreateTime>${Date.now()}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${deepseekResponse}]]></Content>
</xml>
`;
res.set('Content-Type', 'text/xml');
console.log("responseXml:::" ,responseXml);
return res.send(responseXml);
// } catch (error) {
// console.error('Error processing message:', error);
// res.status(500).send('Server Error');
// }
});
// 调用DeepSeek API
async function callDeepSeekAPI(prompt) {
// try {
const response = await axios.post(
'https://api.deepseek.com/v1/chat/completions',
{
model: "deepseek-chat",
messages: [{ role: "user", content: prompt }],
temperature: 0.7
},
{
headers: {
'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`,
'Content-Type': 'application/json'
},
timeout: 50000 // 5秒超时
}
);
console.log(JSON.stringify(response.data.choices), "================================")
return response.data.choices[0].message.content;
// } catch (error) {
// console.error('DeepSeek API Error:', error.response?.data || error.message);
// return '服务暂时不可用,请稍后再试';
// }
}
// 构建文本响应XML
function buildTextResponse(message, content) {
console.log("content: ", content)
const builder = new Builder({
xmldec: { version: '1.0', encoding: 'UTF-8' },
cdata: true
});
return builder.buildObject({
xml: {
ToUserName: { _: message.fromUser },
FromUserName: { _: message.toUser },
CreateTime: Math.floor(Date.now() / 1000),
MsgType: 'text',
Content: String(content)
}
});
}
// 特殊字符转义(XML 转义)
function escapeXml(str) {
return str.replace(/[&<>'"]/g, function (char) {
switch (char) {
case '&': return '&amp;';
case '<': return '&lt;';
case '>': return '&gt;';
case "'": return '&apos;';
case '"': return '&quot;';
}
});
}
// 启动服务
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/wechat`);
});
\ No newline at end of file
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const { parseString, Builder } = require('xml2js');
const OpenAI = require('openai');
const app = express();
const port = process.env.PORT || 3000;
// 初始化 OpenAI 客户端(使用 DeepSeek API)
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com', // DeepSeek API 地址
apiKey: process.env.DEEPSEEK_API_KEY, // 从环境变量中读取 API Key
});
// 中间件配置
app.use(bodyParser.text({ type: 'text/xml' }));
app.use(express.json());
// 微信公众号签名验证
const validateWechatSignature = (req) => {
const { signature, timestamp, nonce } = req.query;
if (!signature || !timestamp || !nonce) return false;
const token = process.env.WECHAT_TOKEN;
const sortedStr = [token, timestamp, nonce].sort().join('');
const sha1 = crypto.createHash('sha1').update(sortedStr).digest('hex');
return sha1 === signature;
};
// 处理微信服务器验证
app.get('/wechat', (req, res) => {
if (!validateWechatSignature(req)) {
console.error('Signature validation failed');
return res.status(403).send('Invalid signature');
}
res.send(req.query.echostr);
});
// 处理微信消息
app.post('/wechat', async (req, res) => {
try {
// 1. 验证签名
if (!validateWechatSignature(req)) {
console.error('Invalid signature in POST');
return res.status(403).send('Forbidden');
}
// 2. 解析XML消息
const xmlData = await new Promise((resolve, reject) => {
parseString(req.body, (err, result) => {
err ? reject(err) : resolve(result.xml);
});
});
// 3. 提取消息内容
const message = {
toUser: xmlData.ToUserName[0],
fromUser: xmlData.FromUserName[0],
content: xmlData.Content?.[0] || '',
msgType: xmlData.MsgType[0]
};
console.log('Received message:', message);
// 4. 只处理文本消息
if (message.msgType !== 'text') {
return res.send(buildTextResponse(message, '暂不支持此类型消息'));
}
// 5. 调用DeepSeek API生成回复
const deepseekResponse = await callDeepSeekAPI(message.content);
console.log(deepseekResponse, "===")
// 6. 构建响应XML
const responseXml = buildTextResponse(message, deepseekResponse);
res.set('Content-Type', 'text/xml');
res.send(responseXml);
} catch (error) {
console.error('Error processing message:', error);
res.status(500).send('Server Error');
}
});
// 调用DeepSeek API
async function callDeepSeekAPI(prompt) {
try {
const completion = await openai.chat.completions.create({
messages: [
{ role: "system", content: "你是一个智能助手。" }, // 系统角色设置
{ role: "user", content: prompt } // 用户输入
],
model: "deepseek-chat", // DeepSeek 模型
});
return completion.choices[0].message.content.trim();
} catch (error) {
console.error('DeepSeek API Error:', error);
return '服务暂时不可用,请稍后再试';
}
}
// 构建文本响应XML
function buildTextResponse(message, content) {
const builder = new Builder({
xmldec: { version: '1.0', encoding: 'UTF-8' },
cdata: true
});
return builder.buildObject({
xml: {
ToUserName: { _: message.fromUser },
FromUserName: { _: message.toUser },
CreateTime: Math.floor(Date.now() / 1000),
MsgType: 'text',
Content: content
}
});
}
// 启动服务
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/wechat`);
});
\ No newline at end of file
const express = require('express');
const crypto = require('crypto');
const { OpenAI } = require('openai');
const xml2js = require('xml2js');
const app = express();
app.use(express.text({ type: 'text/xml' }));
// 配置参数 [5]()
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com/v1',
apiKey: 'sk-14f0cf16bad245169cd2563e0f9b678e'
});
// 微信服务号验证
app.get('/wechat', (req, res) => {
const { signature, timestamp, nonce, echostr } = req.query;
const token = 'deepseektest';
const sorted = [token, timestamp, nonce].sort().join('');
const sha1 = crypto.createHash('sha1').update(sorted).digest('hex');
sha1 === signature ? res.send(echostr) : res.status(403).send(' 验证失败');
});
const msgIdCache = new Set();
// 消息处理流程
app.post('/wechat', async (req, res) => {
// try {
// XML解析
const result = await xml2js.parseStringPromise(req.body);
const message = result.xml.Content[0];
const fromUser = result.xml.FromUserName[0];
const MsgId = result.xml.MsgId[0];
if (msgIdCache.has(MsgId)) {
return res.send(''); // 拦截重复请求
}
msgIdCache.add(MsgId);
console.log(message, "------------------")
// API调用 [5]()
const completion = await openai.chat.completions.create({
model: "deepseek-chat",
messages: [{
role: "user",
content: `${message} , 你是一个微信服务号智能助手,你输出的字符要低于2048个字节`
}],
stream: false
});
console.log("completion:::", completion);
const xmlEntities = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&apos;'
};
function escapeWechatContent(text) {
// 处理换行符[1]()[2]()
// let escaped = text.replace(/\n/g, '&#10;');
// 转义XML特殊字符[3]()[5]()
text = text.replace(/[&<>"']/g, (char) => xmlEntities[char]);
return text;
}
let fullContent = escapeWechatContent(completion.choices[0].message.content);
// 响应构造
const responseXML = `
<xml>
<ToUserName><![CDATA[${fromUser}]]></ToUserName>
<FromUserName><![CDATA[${result.xml.ToUserName[0]}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${fullContent}]]></Content>
</xml>
`;
console.log(xml2js.parseString(responseXML))
res.set('Content-Type', 'text/xml');
console.log(responseXML)
return res.send(responseXML);
// } catch (error) {
// console.error(error);
// res.status(500).send(' 服务异常');
// }
});
app.listen(3001, () => console.log(' 服务运行在3001端口'));
\ No newline at end of file
const express = require('express');
const axios = require('axios');
const xml2js = require('xml2js');
const crypto = require('crypto');
const app = express();
app.use(express.text({ type: 'text/xml' }));
const port = 3001;
// 微信服务号配置
const WECHAT_TOKEN = 'deepseektest';
const DEEPSEEK_API_URL = 'https://api.deepseek.com/v1'; // 请替换为 DeepSeek 的具体 API 地址
const DEEPSEEK_API_KEY = 'sk-14f0cf16bad245169cd2563e0f9b678e'; // 请替换为你的 DeepSeek API 密钥
// 最大消息长度(微信最大支持2048字节)
const MAX_TEXT_LENGTH = 2000;
// 微信验证
app.get('/wechat', (req, res) => {
const { signature, timestamp, nonce, echostr } = req.query;
const token = WECHAT_TOKEN;
// 排序并生成加密字符串
const arr = [timestamp, nonce, token].sort();
const str = arr.join('');
const hash = crypto.createHash('sha1').update(str).digest('hex');
// 验证签名
if (hash === signature) {
res.send(echostr);
} else {
res.send('Invalid signature');
}
});
// 特殊字符转义(XML 转义)
function escapeXml(str) {
return str.replace(/[&<>'"]/g, function (char) {
switch (char) {
case '&': return '&amp;';
case '<': return '&lt;';
case '>': return '&gt;';
case "'": return '&apos;';
case '"': return '&quot;';
}
});
}
// 处理微信消息
app.post('/wechat', async (req, res) => {
try {
// 解析微信发来的 XML 数据
const xmlData = await xml2js.parseStringPromise(req.body);
// 获取用户提问的内容
const userMessage = xmlData.xml.Content;
console.log(userMessage, "===============")
if (!userMessage) {
return res.send('No content');
}
// 调用 DeepSeek API 获取答案
const deepSeekResponse = await axios.post(DEEPSEEK_API_URL, {
apiKey: DEEPSEEK_API_KEY,
question: userMessage,
});
console.log(deepSeekResponse, "============")
// 获取 DeepSeek API 返回的答案
let answer = deepSeekResponse.choices[0].message.content || 'Sorry, I could not find an answer.';
// 如果回答超长,截取并添加提示
if (answer.length > MAX_TEXT_LENGTH) {
answer = answer.substring(0, MAX_TEXT_LENGTH) + '... (Answer truncated)';
}
// 转义特殊字符
answer = escapeXml(answer);
// 构建微信返回消息格式
const responseMessage = `
<xml>
<ToUserName><![CDATA[${xmlData.xml.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${xmlData.xml.ToUserName}]]></FromUserName>
<CreateTime>${Date.now()}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${answer}]]></Content>
</xml>
`;
// 返回消息到微信服务号
res.set('Content-Type', 'text/xml');
res.send(responseMessage);
} catch (error) {
console.error('Error calling DeepSeek API:', error);
const errorMessage = `
<xml>
<ToUserName><![CDATA[${xmlData.xml.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${xmlData.xml.ToUserName}]]></FromUserName>
<CreateTime>${Date.now()}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[Sorry, I couldn't fetch the answer right now. Please try again later.]]></Content>
</xml>
`;
res.set('Content-Type', 'text/xml');
res.send(errorMessage);
}
});
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
const Joi = require('joi');
/**
* 参数校验 https://joi.dev/api/?v=17.13.0
* @param {*} req
* @param {*} res
* @param {*} next
* @returns
*/
module.exports = (req, res, next) => {
console.log(req.headers, req.url, req.method, req.path, req.baseUrl, req.originalUrl);
// const schema = schemas[req.originalUrl];
// if (schema) {
// const { error } = schema.validate({
// ...req.body,
// ...req.query
// });
// console.log(error); //eslint-disable-line
// if (error) {
// return res.status(400).send({
// code: 402,
// message: error.details[0].message,
// success: false
// });
// }
// }
next();
}
const schemas = {
//用户
'/api/user/register': Joi.object({
phone: Joi.string().regex(/^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$/).required(),
password: Joi.string().regex(/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,}$/).required(),
full_name: Joi.string(),
department: Joi.string(),
position: Joi.string()
}),
}
const createError = require('http-errors');
const requestLogModule = require("../module/requestLogModule");
const mongoose = require('mongoose');
//
module.exports = async (req, res, next) => {
req.reqId = new mongoose.Types.ObjectId();
// /* 1. 处理token */
// if (!checkPath(req.path)) {
// if (!(req.headers.authorization || req.headers.Authorization)) {
// next(createError(401));
// }
// req.headers.authorization = req.headers.authorization || req.headers.Authorization;
// const userStr = await ioRedis.get(`token:${req.headers.authorization}`);
// // console.log(userStr)
// if (userStr) {
// try {
// req.user = JSON.parse(userStr);
// // 刷新token时间
// await ioRedis.expire(`token:${req.headers.authorization}`, sysConfig.tokenEx)
// } catch (error) {
// //解析有误
// next(createError(401));
// }
// } else {
// //过期
// next(createError(401));
// }
// }
/* --------------3. 记录所有进来的日志,是否记录响应的值有待 */
requestLogModule.createRequestLog({
url: req.baseUrl + req.path,
params: JSON.stringify({
...req.body,
...req.query,
...req.params,
}),
reqId: req.reqId,
user: req.user,
method: req.method,
headers: JSON.stringify(req.headers),
});
next();
}
function checkPath(path) {
if (['/user/login', '/user/regist', '/plant/product/trace/info'].includes(path)) {
return true;
} else {
return false;
}
}
\ No newline at end of file
const requestLogModule = require("../module/requestLogModule");
module.exports = (req, res, next) => {
res['sendData'] = (data) => {
res.status(200).send({
code: 0,
data: data,
message: 'success',
});
requestLogModule.updateRequestLog({
reqId: req.reqId,
result: JSON.stringify(data),
msg: "success",
status: 200,
});
};
res['sendError'] = (error) => {
// 除404 500以外 其他均归类为业务错误 以http 200返回,具体错误在返回内容里面根据code来区分。
res.status(200).send({
code: error.code,
message: error.message,
});
requestLogModule.updateRequestLog({
reqId: req.reqId,
result: JSON.stringify(error.message),
msg: "error",
status: 200,
});
};
next();
}
\ No newline at end of file
// class Log {
// constructor(moduleName) {
// this.module = DB[`${moduleName}`]
// }
// createLog() {
// return this.module.create(data);
// }
// }
async function createRequestLog(data) {
return DB.RequestLog.create(data);
}
async function updateRequestLog(data) {
return DB.RequestLog.findOneAndUpdate({reqId: data.reqId}, data);
}
module.exports = {
createRequestLog,
updateRequestLog,
}
\ No newline at end of file
async function createUser(obj) {
const ret = await DB.User.create(obj);
return ret;
}
module.exports = {createUser}
{ {
"name": "wechat_ds", "name": "letian",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "production": "cross-env NODE_ENV=production node server.js",
"dev": "cross-env NODE_ENV=dev nodemon server.js",
"local": "cross-env NODE_ENV=local nodemon server.js"
}, },
"keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"axios": "^1.7.9", "axios": "1.7.4",
"body-parser": "^1.20.3", "compression": "1.7.4",
"crypto": "^1.0.1", "cors": "2.8.5",
"dotenv": "^16.4.7", "crypto": "1.0.1",
"express": "^4.21.2", "crypto-js": "^4.2.0",
"xml2js": "^0.6.2" "eslint": "9.4.0",
"exceljs": "4.4.0",
"express": "4.19.2",
"form-data": "4.0.0",
"ioredis": "5.4.1",
"joi": "17.13.1",
"lodash": "4.17.21",
"moment": "2.30.1",
"mongoose": "8.5.3",
"morgan": "1.10.0",
"multer": "1.4.5-lts.1",
"node-cron": "3.0.3"
} }
} }
const express = require('express');
const router = express.Router();
const wechatRouter = require('./wechatRouter');
const questionRouter = require('./questionRouter');
router.post('/wechat', wechatRouter);
router.post('/question', questionRouter);
module.exports = router;
\ No newline at end of file
const express = require('express');
const router = express.Router();
const questionController = require('../controller/questionController');
router.post('/question/createQuestion', questionController.createQuestion);
router.post('/question/getQuesList', questionController.getQuesList);
module.exports = router;
\ No newline at end of file
const express = require('express');
const router = express.Router();
const questionController = require('../controller/questionController.js');
module.exports = router;
\ No newline at end of file
const express = require('express');
const createError = require('http-errors');
const compress = require('compression');
const router = require('./router');
const path = require('path');
const logger = require('morgan');
const cors = require('cors');
//中间件
const parameter = require('./middleware/parameter');
const request = require('./middleware/request');
const response = require('./middleware/response');
const requestLogModule = require("./module/requestLogModule");
//系统数据库
require('./config');
require('./db');
require('./cron')();
global.utils = require('./utils');
// global.ioRedis = require('./db/redis');
const app = express();
app.use(cors());
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With, Range");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
next();
});
app.use(compress());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(`/${sysConfig.file.storagePath}`, express.static(sysConfig.file.storagePath)); //保证 local:3000 + path
app.use(express.static('public'));
app.use(logger('dev'));
app.use('/api', request, response, router);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.log(err.code, err.status)
// 记录下错误日志
requestLogModule.createRequestLog({
url: req.path,
params: JSON.stringify({
...req.body,
...req.query,
...req.params,
}),
user: req.user,
status: err.status || err.code || 500,
msg: err.message || 'server error'
});
if(err.code && err.message) {
return res.sendError(err);
}
return res.status(err.status || 500).send({code: err.status ||500, msg: err.message || 'server error'});
});
const server = require('http').createServer(app);
server.listen(process.env.PORT || 3000, function () {
console.log(`****** server is listening : ${process.env.PORT} || 3000`);
});
module.exports = {
loginError: {
code: 40001,
message: "登录失败"
},
resourceNotFound: {
code: 40002,
message: "资源不存在"
},
nameDuplicated: {
code: 40003,
message: "名称重复"
},
agrMatDuplicated: {
code: 40004,
message: "入库物品种类重复,请检查!"
},
agrMatHaveFlow: {
code: 40005,
message: "入库物品种类重复,请检查!"
},
databaseQueryError: {
code: 50001,
message: "数据库操作错误"
}
}
\ No newline at end of file
const axios = require('axios');
const requestLogModule = require("../module/requestLogModule");
async function httpRequest ({url, method, data, params, headers = {}, responseType}) {
try {
let opt = {
url,
method,
params: params || {},
data: data || {},
headers,
}
if(responseType) {
opt.responseType = responseType;
}
const ret = await axios(opt);
requestLogModule.createRequestLog({
url,
method,
params: JSON.stringify(params) + JSON.stringify((headers["Content-Type"] == "mutipart/form-data" ? "" : data)),
headers: JSON.stringify(headers),
type: "device",
status: ret && ret.status,
result: responseType == 'stream' ? "" : JSON.stringify(ret.data)
}).catch(error => {
console.log(error);
});
if(ret && ret.status == 200) {
return {data: ret.data, status: true};
} else {
return {data: null, status: false};
}
} catch (error) {
console.log(error);
requestLogModule.createRequestLog({
url,
method,
params: JSON.stringify(params) + JSON.stringify((headers["Content-Type"] == "mutipart/form-data" ? "" : data)),
headers: JSON.stringify(headers),
type: "device",
msg: error.message,
}).catch(error => {
console.log(error);
});
return {data: null, status: false};
}
}
module.exports = httpRequest;
\ No newline at end of file
const crypto = require('crypto');
const _ = require('lodash');
function genRandomString(length) {
return crypto.randomBytes(Math.ceil(length / 2))
.toString('hex')
.slice(0, length);
}
function saltHashPassword(password) {
const salt = genRandomString(16);
const passwordHash = crypto.createHmac('sha256', salt).update(password).digest('hex');
return {
salt,
passwordHash
}
}
function checkUserPassword({ reqPw, salt, userPw }) {
const passwordHash = crypto.createHmac('sha256', salt).update(reqPw).digest('hex');
if (userPw == passwordHash) {
return true;
} else {
return false;
}
}
function buildTree(nodes) {
// 创建一个映射,将节点ID映射到节点对象
const nodeMap = new Map(nodes.map(node => [String(node._id), { ...node, children: [] }]));
// 遍历所有节点,并将它们添加到对应父节点的children数组中
nodes.forEach(node => {
const parentId = String(node.parentId);
if (parentId !== null) {
// 确保父节点在映射中存在
if (nodeMap.has(parentId)) {
// 将当前节点添加到父节点的children数组中
nodeMap.get(parentId).children.push(nodeMap.get(String(node._id)));
nodeMap.get(parentId).children = _.orderBy(nodeMap.get(parentId).children, 'order')
}
}
});
// 从映射中提取顶级节点(parentId为null)
return _.orderBy(Array.from(nodeMap.values()).filter(node => node.parentId === null), 'order');
}
function disTree(tree) {
let parallel = [];
function addToParallel(nodes) {
nodes.forEach(node => {
parallel.push({
...node,
children: undefined
});
if (node.children && node.children.length) {
addToParallel(node.children);
}
});
}
addToParallel(tree)
return parallel
}
function genTracSourceCode({EnterpriseCode, type, date, batchNum, logisticsNum}) {
// 企业代码(9) MA4W271Y8 + 产品代码【种植、初加工、深加工】(6)+ 生产/出厂日期(8)) + 批次号(8)+ 物流码 + 校验码(8)
//MA4W271Y8
date = date && moment().format('YYYYMMDD');
return `${EnterpriseCode}${type}${date}${batchNum}${logisticsNum}`;
}
module.exports = {
saltHashPassword,
checkUserPassword,
buildTree,
disTree,
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment