Compare commits
216 Commits
master
...
456e55bb2e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
456e55bb2e | ||
|
|
8586b76ef2 | ||
|
|
3767f1938a | ||
|
|
99331d5b8d | ||
|
|
9fe354f832 | ||
|
|
9d7e2136cc | ||
|
|
eeb5c0a511 | ||
|
|
8c0a797dc8 | ||
|
|
c8f7c169cc | ||
|
|
cf6c8fdb45 | ||
|
|
51ab4b62bc | ||
|
|
58c24d705f | ||
|
|
bf0a0b4e6a | ||
|
|
a748c2575b | ||
|
|
8851f2703a | ||
|
|
c63a56d2c8 | ||
|
|
47af53443e | ||
|
|
3d5bce566e | ||
|
|
bd8c7ebecb | ||
|
|
c0a849cb9f | ||
|
|
cc34a5cdea | ||
|
|
e394e4d2ba | ||
|
|
6532b66240 | ||
|
|
91ca77ffa8 | ||
|
|
56021924ef | ||
|
|
89987aeea1 | ||
|
|
39de61cede | ||
|
|
6a782d4cda | ||
|
|
50e8e24e2c | ||
|
|
064ed0a1d7 | ||
|
|
30e58518fd | ||
|
|
d04491f17e | ||
|
|
3ea8420747 | ||
|
|
458710b856 | ||
|
|
158c474183 | ||
|
|
3578b3bf3b | ||
|
|
a27cb95188 | ||
|
|
76ed5c0028 | ||
|
|
cad79f917a | ||
|
|
f517b48ad4 | ||
|
|
ff1f5ce6fa | ||
|
|
857825af4a | ||
|
|
adc58b3e0d | ||
|
|
9b947b64dc | ||
|
|
0917405f1a | ||
|
|
664e909920 | ||
|
|
6b9a777653 | ||
|
|
c221ce8965 | ||
|
|
ebcfff03cc | ||
|
|
3e1991eaaa | ||
|
|
f192d85b1b | ||
|
|
2e30774aeb | ||
|
|
7c103f01a9 | ||
| dc33689db4 | |||
| 768982f6e3 | |||
|
|
ddbf988698 | ||
| 2e5a162292 | |||
| 7693e2fda1 | |||
| c168a1da0c | |||
| aef22a3b14 | |||
| 518efac58a | |||
|
|
1bc5e3b9c4 | ||
|
|
428fb054d5 | ||
|
|
cd7f0f7158 | ||
|
|
430d383b8d | ||
|
|
8b727839fa | ||
|
|
0a928d8231 | ||
|
|
46287ac2f5 | ||
|
|
4568fcd985 | ||
|
|
88e2a1f47a | ||
|
|
7acebbc35b | ||
|
|
d988440bca | ||
|
|
0dd870859e | ||
|
|
c9020de8ec | ||
|
|
0f58ea80fa | ||
|
|
e7fd86b1e2 | ||
|
|
7bcc5c3de8 | ||
|
|
8f374c1221 | ||
|
|
e8a065beac | ||
|
|
ae8bf19957 | ||
|
|
02001e78c2 | ||
|
|
766faee96e | ||
|
|
de3549d82e | ||
|
|
b5e1864c6a | ||
|
|
dd764d704a | ||
|
|
3639b88417 | ||
|
|
ce8a594870 | ||
|
|
4988586397 | ||
|
|
236ff91eaf | ||
|
|
c7596d08da | ||
|
|
7e5c1b91d5 | ||
|
|
efb85bc936 | ||
|
|
b0d28d6332 | ||
|
|
bb0d7334e6 | ||
|
|
26b6c7b1e6 | ||
|
|
0d6f3e522d | ||
|
|
dfc4b7a84b | ||
|
|
16b37d68c0 | ||
|
|
3facfeb1fa | ||
|
|
c48682825f | ||
| 6ae2164d52 | |||
|
|
1f1cac75f1 | ||
|
|
3acf79d55e | ||
|
|
588518b8be | ||
|
|
ce6cb52bbf | ||
|
|
b94455ed76 | ||
|
|
bf60b7f257 | ||
|
|
679857473a | ||
|
|
1302f1caa2 | ||
|
|
bfc3b49ce9 | ||
|
|
cd6af33167 | ||
|
|
e45c04f2da | ||
|
|
6de1b4daca | ||
|
|
3b68bc31a0 | ||
|
|
96854369a1 | ||
|
|
21102cdfe2 | ||
|
|
7a22c233fe | ||
|
|
f800b249ca | ||
|
|
6e18858abf | ||
|
|
1308471a68 | ||
|
|
f0d998c71a | ||
|
|
33e2c78d90 | ||
|
|
091deb59ef | ||
|
|
7dd22f51fe | ||
|
|
43c59ec34e | ||
|
|
d553307ea8 | ||
|
|
c60a7362e7 | ||
|
|
3334a68f06 | ||
|
|
5b437886eb | ||
|
|
716b80eedd | ||
|
|
e86b8b2f46 | ||
|
|
90ab258629 | ||
|
|
3ee1dae426 | ||
|
|
9b634abb44 | ||
|
|
211ab357e4 | ||
|
|
5e16f0ca9f | ||
|
|
6263a27aba | ||
|
|
00cc2d9e4f | ||
|
|
8b19051578 | ||
|
|
11fbc716a0 | ||
|
|
e07aef9832 | ||
|
|
569fdcabe7 | ||
|
|
eaaf373137 | ||
|
|
fdc3bb0393 | ||
|
|
4a0528991e | ||
|
|
a0585e0914 | ||
|
|
35019b0d0f | ||
|
|
8452180cfb | ||
|
|
9a2fac9e6f | ||
|
|
6a8fa6135a | ||
|
|
8bf02b4270 | ||
|
|
4885bd9c27 | ||
|
|
ce2503cad0 | ||
|
|
9c9e249f56 | ||
|
|
11e1a726ae | ||
|
|
bc76415d6f | ||
|
|
4fcdee39ed | ||
|
|
e7c01a176c | ||
|
|
c347c6706f | ||
|
|
f81e1abdfe | ||
|
|
00e1fc04de | ||
|
|
087d34071f | ||
|
|
18e4065487 | ||
|
|
50d0e9088c | ||
|
|
fc2dfa1d2d | ||
|
|
a57d6741ad | ||
|
|
29701488e0 | ||
|
|
d813628d61 | ||
|
|
c48436301f | ||
|
|
f48d8924da | ||
|
|
bf23769076 | ||
|
|
d39134a71e | ||
|
|
bc79fa48be | ||
|
|
95663704d1 | ||
|
|
b677a3fe9f | ||
|
|
ac883222ca | ||
|
|
7afb62b16a | ||
|
|
ef1e2a0089 | ||
|
|
d3faa0c037 | ||
|
|
dd329d6e60 | ||
|
|
785157a65a | ||
|
|
45c1a4f043 | ||
|
|
64f0cf5708 | ||
|
|
be0732bbd1 | ||
|
|
bc2062ec76 | ||
|
|
12e878b041 | ||
|
|
c33e62cdeb | ||
|
|
c45f0b6faf | ||
|
|
81be840647 | ||
|
|
06a9b238e7 | ||
|
|
54c631f208 | ||
|
|
9e9afb9c35 | ||
| 1123a84d3a | |||
|
|
585e6deb89 | ||
|
|
a68b911d39 | ||
|
|
1b887f6837 | ||
|
|
530eecaed7 | ||
|
|
704811e1d9 | ||
|
|
b0724affcc | ||
|
|
cbba345806 | ||
|
|
7c21a10862 | ||
|
|
bb94243ec5 | ||
|
|
93be499640 | ||
|
|
a49d799afe | ||
|
|
c7f56d7958 | ||
|
|
ec7adbbe71 | ||
|
|
d8ba3fbb83 | ||
|
|
d7b3b041bb | ||
|
|
1f0bf4cf73 | ||
|
|
948cc94338 | ||
|
|
94ce411071 | ||
|
|
82f09d89c8 | ||
|
|
5391d46b6f | ||
|
|
7a71fd963a | ||
|
|
f56c30780a | ||
|
|
d48be5b91f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
/node_modules/
|
||||
/package-lock.json
|
||||
/zips/
|
||||
/aicode/
|
||||
/logs/
|
||||
|
||||
12
Dockerfile
Normal file
12
Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM node:16-slim
|
||||
LABEL authors="kubbo"
|
||||
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
RUN npm i --registry=http://registry.npmmirror.com
|
||||
|
||||
EXPOSE 12525
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
CMD ["node", "index.js"]
|
||||
11
demo.js
11
demo.js
@@ -1,11 +0,0 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const port = 3000
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.send('Hello World!')
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
oms:
|
||||
build:
|
||||
context: .
|
||||
container_name: "oms-service"
|
||||
ports:
|
||||
- "12525:12525"
|
||||
environment:
|
||||
- NODE_ENV
|
||||
- TZ=Asia/Shanghai
|
||||
24
index.js
Normal file
24
index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const express = require('express')
|
||||
const xmlparser = require('express-xml-bodyparser');
|
||||
require("express-async-errors")
|
||||
const db = require('./src/utils/dbUitls')
|
||||
const rest = require('./src/rest')
|
||||
const ws = require('./src/websocket')
|
||||
const ews = require('express-ws')
|
||||
const chalk = require("chalk");
|
||||
const log = console.log
|
||||
const app = express();
|
||||
ews(app)
|
||||
const port = 12525
|
||||
chalk.level = 1
|
||||
app.listen(port, () => {
|
||||
db.init()
|
||||
app.use(express.json()) // for parsing application/json
|
||||
app.use(xmlparser()); // for parsing application/xml
|
||||
app.use(express.urlencoded({extended: true, limit: '50mb'})) // for parsing application/x-www-form-urlencoded
|
||||
//启动服务并监听
|
||||
Promise.all([rest.init(app)]).then(() => {
|
||||
log(`${chalk.bgGreen.black(" DONE ")} serve is listening on ${port}`)
|
||||
ws.init(app)
|
||||
})
|
||||
})
|
||||
27
package.json
27
package.json
@@ -4,7 +4,10 @@
|
||||
"description": "node服务端",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "node demo.js"
|
||||
"dev": "nodemon index.js",
|
||||
"pro": "pm2 restart pm2.config.js --only oms-node",
|
||||
"deploy": "pm2 deploy pm2.config.js production",
|
||||
"stop": "pm2 delete all"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,8 +17,28 @@
|
||||
"node",
|
||||
"js"
|
||||
],
|
||||
"engines": {
|
||||
"node": "16.13.1"
|
||||
},
|
||||
"author": "kubbo",
|
||||
"dependencies": {
|
||||
"express": "^4.17.3"
|
||||
"@wecom/crypto": "^1.0.1",
|
||||
"axios": "^1.2.1",
|
||||
"dayjs": "^1.11.0",
|
||||
"express": "^4.17.3",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-ws": "^5.0.2",
|
||||
"express-xml-bodyparser": "^0.3.0",
|
||||
"fast-csv": "^4.3.6",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.0.1",
|
||||
"helmet": "^5.0.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mysql": "^2.18.1",
|
||||
"uuid": "^8.3.2",
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "^4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
26
pm2.config.js
Normal file
26
pm2.config.js
Normal file
@@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'dev',
|
||||
script: "index.js",
|
||||
watch: ["src", "tpl"],
|
||||
ignore_watch: ["node_modules"],
|
||||
shutdown_with_message: true,
|
||||
},
|
||||
{
|
||||
name: 'oms-node',
|
||||
script: "index.js",
|
||||
watch: false
|
||||
}
|
||||
],
|
||||
deploy: {
|
||||
production: {
|
||||
user: 'root',
|
||||
host: '192.168.1.87',
|
||||
ref: 'origin/dev',
|
||||
repo: 'http://git.sinoecare.com/lab/dvcp-node-service.git',
|
||||
path: '/home/deploy',
|
||||
postDeploy: "npm run pro"
|
||||
}
|
||||
}
|
||||
}
|
||||
3
shell/fetch.sh
Executable file
3
shell/fetch.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
./shell/update.sh oms-node服务 .
|
||||
npm run pro
|
||||
22
shell/move.sh
Executable file
22
shell/move.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
Type=$1
|
||||
Prj=$2
|
||||
Deploy=$3
|
||||
|
||||
case "$Type" in
|
||||
web)
|
||||
cp -r $Prj/dist/* $Deploy
|
||||
;;
|
||||
wxwork)
|
||||
cp -r $Prj/dist/build/h5/* $Deploy
|
||||
;;
|
||||
mp)
|
||||
cp -r $Prj/dist/build/mp-weixin/* $Deploy
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 (web|wxwork|mp)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
||||
exit $RETVAL
|
||||
13
shell/update.sh
Executable file
13
shell/update.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/expect
|
||||
|
||||
set Name [lindex $argv 0]
|
||||
set Prj [lindex $argv 1]
|
||||
puts "更新$Name"
|
||||
cd $Prj
|
||||
spawn git pull
|
||||
expect "Username"
|
||||
send "aixianling\r"
|
||||
expect "Password"
|
||||
send "axl123.0\r"
|
||||
interact
|
||||
cd ..
|
||||
23
src/config/auth.js
Normal file
23
src/config/auth.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const auth = require("jsonwebtoken");
|
||||
module.exports = {
|
||||
//key wxtest token
|
||||
secret: "ddb64c99f29d310c",
|
||||
verifyToken(req, res, next) {
|
||||
const token = req.headers['authorization'];
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({message: 'No token provided'});
|
||||
}
|
||||
|
||||
auth.verify(token, this.secret, (err, decoded) => {
|
||||
if (err) {
|
||||
return res.status(403).json({message: 'Failed to authenticate token'});
|
||||
}
|
||||
req.userId = decoded.userId;
|
||||
next();
|
||||
});
|
||||
},
|
||||
generateToken(userId) {
|
||||
return auth.sign({userId}, this.secret, {expiresIn: '24h'});
|
||||
}
|
||||
}
|
||||
8
src/config/db.js
Normal file
8
src/config/db.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
host: "192.168.1.87",
|
||||
user: "root",
|
||||
port: 3306,
|
||||
password: "Cwy@2019",
|
||||
database: "dvcp_oms_dev",
|
||||
multipleStatements: true
|
||||
}
|
||||
20
src/rest/addressBook/action.js
Normal file
20
src/rest/addressBook/action.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const {getSignature, decrypt} = require("@wecom/crypto");
|
||||
const {addOrUpdate} = require("../../utils/dbUitls");
|
||||
const token = "OTUlglGGoGm7EKKpKeg6tc"
|
||||
const encodingAESKey = "LHLwd2nhbia4iCEfyDJkUPBb9TT7G8GMlWpgqzNHODi"
|
||||
module.exports = {
|
||||
action: "/wxwork/addressBook/action",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {msg_signature, timestamp, nonce, echostr} = request.query
|
||||
const signature = getSignature(token, timestamp, nonce, echostr);
|
||||
if (msg_signature == signature) {
|
||||
const context = decrypt(encodingAESKey, echostr)
|
||||
const {name, mobile: phone, email, userId} = context
|
||||
addOrUpdate({
|
||||
table: "sys_user", form: {name, email, phone, userId}
|
||||
})
|
||||
response.send({code: 0, message: "success"})
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/rest/addressBook/actionGet.js
Normal file
15
src/rest/addressBook/actionGet.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const {getSignature, decrypt} = require("@wecom/crypto");
|
||||
const token = "OTUlglGGoGm7EKKpKeg6tc"
|
||||
const encodingAESKey = "LHLwd2nhbia4iCEfyDJkUPBb9TT7G8GMlWpgqzNHODi"
|
||||
module.exports = {
|
||||
action: "/wxwork/addressBook/action",
|
||||
method: "get",
|
||||
execute: (request, response) => {
|
||||
const {msg_signature, timestamp, nonce, Encrypt} = request.query
|
||||
const signature = getSignature(token, timestamp, nonce, Encrypt);
|
||||
if (msg_signature == signature) {
|
||||
const context = decrypt(encodingAESKey, Encrypt)
|
||||
response.send(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/rest/addressBook/add.js
Normal file
48
src/rest/addressBook/add.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const fs = require('fs');
|
||||
const FormData = require('form-data');
|
||||
const fastcsv = require('fast-csv');
|
||||
const axios = require("axios");
|
||||
|
||||
//生成csv并上传至企微后台获取 media_id
|
||||
const uploadCsv = (data = [], access_token) => {
|
||||
// data数据格式
|
||||
// {"name": "张三", "email": "john.doe@example.com",phone:"13388888888"},
|
||||
const csv = data.map(e => {
|
||||
return {
|
||||
"姓名": e.name,
|
||||
"账号": e.phone,
|
||||
"手机号": e.phone,
|
||||
"邮箱": e.email,
|
||||
}
|
||||
})
|
||||
const form = new FormData()
|
||||
const csvStream = fastcsv.format({headers: true})
|
||||
csvStream.pipe(fs.createWriteStream('tmp.csv'))
|
||||
data.forEach(item => csvStream.write(item))
|
||||
csvStream.end()
|
||||
form.append('media', fs.createReadStream('tmp.csv'))
|
||||
return axios.post(`https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=${access_token}&type=file`, {
|
||||
headers: form.getHeaders()
|
||||
}).then(res => {
|
||||
const {media_id} = res.data
|
||||
return media_id
|
||||
})
|
||||
}
|
||||
module.exports = {
|
||||
action: "/wxwork/addressBook/syncUser",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {access_token} = request.body
|
||||
// 获取原CA账号数据
|
||||
dbUtils.list({
|
||||
table: "sys_user",
|
||||
}).then(data => uploadCsv(data, access_token))
|
||||
.then(media_id => {
|
||||
// 上传csv至企微后台
|
||||
return axios.post(`https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser?access_token=${access_token}`, {
|
||||
media_id
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
31
src/rest/aicode/add.js
Normal file
31
src/rest/aicode/add.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const {v4: uuid} = require('uuid');
|
||||
module.exports = {
|
||||
action: "/node/aicode/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let form = request.body, sql
|
||||
if (form.id) {//编辑
|
||||
let arr = Object.keys(form).filter(e => form[e]).map(e => {
|
||||
if (typeof form[e] == "object") form[e] = JSON.stringify(form[e])
|
||||
return `${e}='${form[e]}'`
|
||||
})
|
||||
sql = `update node_aicode set ${arr.join(",")} where id='${form.id}'`
|
||||
} else {//新增
|
||||
let cols = [], arr = []
|
||||
Object.keys(form).map(e => {
|
||||
if (form[e]) {
|
||||
cols.push(e)
|
||||
if (typeof form[e] == "object") form[e] = JSON.stringify(form[e])
|
||||
arr.push(`'${form[e]}'`)
|
||||
}
|
||||
})
|
||||
sql = `insert into node_aicode (id,${cols.join(",")}) values('${uuid()}',${arr.join(",")})`
|
||||
}
|
||||
dbUtils.query(sql).then(() => {
|
||||
response.send({code: 0})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
14
src/rest/aicode/delete.js
Normal file
14
src/rest/aicode/delete.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/aicode/delete",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {query: {ids}} = request
|
||||
ids = ids?.split(",")?.map(e => `'${e}'`)?.toString()
|
||||
dbUtils.query(`delete from node_aicode where id in (${ids})`).then(() => {
|
||||
response.send({code: 0})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
28
src/rest/aicode/detail.js
Normal file
28
src/rest/aicode/detail.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const {checkJson} = require("../../tools");
|
||||
|
||||
module.exports = {
|
||||
action: "/node/aicode/detail",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id} = request.query
|
||||
let condition = `where id='${id}'`
|
||||
let sql = `select * from node_aicode ${condition} limit 0,1`
|
||||
dbUtils.query(sql).then(res => res?.[0]).then(data => {
|
||||
for (const k in data) {
|
||||
if (checkJson(data[k])) {
|
||||
data[k] = JSON.parse(data[k])
|
||||
} else if (["props"].includes(k)) {
|
||||
//关于json对象的处理
|
||||
data[k] = data[k] || []
|
||||
} else if (["btns"].includes(k)) {
|
||||
//关于数组的处理
|
||||
data[k] = data[k]?.split(",") || []
|
||||
}
|
||||
}
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
34
src/rest/aicode/getCode.js
Normal file
34
src/rest/aicode/getCode.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const fse = require("fs-extra");
|
||||
const execute = require("../../tools/exec");
|
||||
const generate = require("../../tools/generate");
|
||||
module.exports = {
|
||||
action: "/node/aicode/getCode",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id, sql = `select * from node_aicode where id='${id}'`
|
||||
dbUtils.query(sql).then(res => {
|
||||
let info = res?.[0]
|
||||
if (info?.id) {
|
||||
let path = `./aicode/${info.id}`, zipPath = `${path}/${info.id}.zip`
|
||||
generate(info, path).then(() => {
|
||||
fse.pathExists(path, (err, exists) => {
|
||||
console.log(`${path}=========>${exists}`)
|
||||
if (exists) {
|
||||
execute(`cd ${path}&&zip -r ${info.id}.zip .`)
|
||||
.then(() => {
|
||||
console.log('压缩完成!')
|
||||
setTimeout(() => {
|
||||
response.download(zipPath)
|
||||
}, 1000)
|
||||
})
|
||||
} else response.send({code: 1, err: "没有打包文件!"})
|
||||
})
|
||||
})
|
||||
} else response.send({code: 1, err: "无法找到应用信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
28
src/rest/aicode/list.js
Normal file
28
src/rest/aicode/list.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/aicode/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let total = 0, records = [], {size, current = 1, name = ""} = request.query
|
||||
let condition = `where (name like '%${name}%' or appName like '%${name}%')`
|
||||
Promise.all([
|
||||
dbUtils.query(`select 1 from node_aicode ${condition}`).then(res => {
|
||||
return total = res.length
|
||||
}),
|
||||
new Promise(resolve => {
|
||||
let sql = `select * from node_aicode ${condition} limit ${(current-1)*size||0},${size||1}`
|
||||
dbUtils.query(sql).then(res => {
|
||||
records = res
|
||||
resolve()
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
})
|
||||
]).then(() => {
|
||||
response.send({
|
||||
code: 0,
|
||||
data: {records, total}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
27
src/rest/autodeploy/add.js
Normal file
27
src/rest/autodeploy/add.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const {v4: uuid} = require('uuid');
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let form = request.body, sql
|
||||
if (form.id) {//编辑
|
||||
let arr = Object.keys(form).filter(e => form[e]).map(e => `${e}='${form[e]}'`)
|
||||
sql = `update node_autodeploy set ${arr.join(",")} where id='${form.id}'`
|
||||
} else {//新增
|
||||
let cols = [], arr = []
|
||||
Object.keys(form).map(e => {
|
||||
if (form[e]) {
|
||||
cols.push(e)
|
||||
arr.push(`'${form[e]}'`)
|
||||
}
|
||||
})
|
||||
sql = `insert into node_autodeploy (id,${cols.join(",")}) values('${uuid()}',${arr.join(",")})`
|
||||
}
|
||||
dbUtils.query(sql).then(() => {
|
||||
response.send({code: 0})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
14
src/rest/autodeploy/cancelZip.js
Normal file
14
src/rest/autodeploy/cancelZip.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/cancelZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id, sql = `update node_autodeploy set zipTime=null where id='${id}'`
|
||||
dbUtils.query(sql).then(() => {
|
||||
response.send({code: 0, data: "取消成功!"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
17
src/rest/autodeploy/confirmZip.js
Normal file
17
src/rest/autodeploy/confirmZip.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/confirmZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id, sql = `select * from node_autodeploy where id='${id}'`
|
||||
dbUtils.query(sql).then(res => {
|
||||
let info = res?.[0]
|
||||
if (info?.id) {
|
||||
response.send({code: 0, data: info})
|
||||
} else response.send({code: 1, err: "无法找到git信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
14
src/rest/autodeploy/delete.js
Normal file
14
src/rest/autodeploy/delete.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/delete",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {query: {ids}} = request
|
||||
ids = ids?.split(",")?.map(e => `'${e}'`)?.toString()
|
||||
dbUtils.query(`delete from node_autodeploy where id in (${ids})`).then(() => {
|
||||
response.send({code: 0})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
33
src/rest/autodeploy/download.js
Normal file
33
src/rest/autodeploy/download.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const fse = require("fs-extra");
|
||||
const execute = require("../../tools/exec");
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/download",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id, sql = `select * from node_autodeploy where id='${id}'`
|
||||
dbUtils.query(sql).then(res => {
|
||||
let info = res?.[0]
|
||||
if (info?.id) {
|
||||
let path = `${info.target}`, zipPath = `/zips/${info.id}.zip`
|
||||
fse.removeSync(zipPath)
|
||||
fse.pathExists(path, (err, exists) => {
|
||||
console.log(`${path}=========>${exists}`)
|
||||
if (exists) {
|
||||
execute(`cd ${path}&&zip -r ${info.id}.zip .`)
|
||||
.then(() => execute(`cd ${path}&&mv ${info.id}.zip /zips`))
|
||||
.then(() => {
|
||||
console.log('压缩完成!')
|
||||
setTimeout(() => {
|
||||
response.download(zipPath)
|
||||
}, 1000)
|
||||
})
|
||||
} else response.send({code: 1, err: "没有打包文件!"})
|
||||
})
|
||||
} else response.send({code: 1, err: "无法找到git信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
38
src/rest/autodeploy/getZip.js
Normal file
38
src/rest/autodeploy/getZip.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const db = require("../../utils/dbUitls");
|
||||
const dayjs = require("dayjs")
|
||||
const execute = require("../../tools/exec");
|
||||
const fse = require("fs-extra");
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/getZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id, sql = `select * from node_autodeploy where id='${id}'`
|
||||
db.query(sql).then(res => {
|
||||
let info = res?.[0]
|
||||
if (info?.id) {
|
||||
db.query(`update node_autodeploy set download=null,error=null,zipTime='${dayjs().format("YYYY-MM-DD HH:mm:ss")}' where id='${info.id}'`).then(() => {
|
||||
fse.emptydir(info.target, () => {
|
||||
response.send({code: 0})
|
||||
})
|
||||
}).then(() => {
|
||||
if (!!info.type) {
|
||||
let {type, zipPath, target, name, nodeVersion} = info,
|
||||
updateCMD = `/root/node-service/update.sh ${name} ${zipPath}`,
|
||||
buildCMD = `/root/node-service/build.sh ${type} ${zipPath} ${target} ${nodeVersion || '16.14.0'}`
|
||||
return execute(updateCMD).then(() => execute(buildCMD))
|
||||
} else {
|
||||
return execute(`${info.updateShell}`).then(() => execute(`${info.libShell}`))
|
||||
}
|
||||
}).then(() => {
|
||||
db.query(`update node_autodeploy set download='${dayjs().format("YYYY-MM-DD HH:mm:ss")}',error='' where id='${info.id}'`)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
db.query(`update node_autodeploy set error='${err}',zipTime=null where id='${info.id}'`)
|
||||
})
|
||||
} else response.send({code: 1, err: "无法找到部署工程"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
28
src/rest/autodeploy/list.js
Normal file
28
src/rest/autodeploy/list.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/autodeploy/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let total = 0, records = [], {size, current, name} = request.query
|
||||
Promise.all([
|
||||
dbUtils.query(`select 1 from node_autodeploy where name like '%${name}%'`).then(res => {
|
||||
return total = res.length
|
||||
}),
|
||||
new Promise(resolve => {
|
||||
let sql = `select * from node_autodeploy where name like '%${name}%' limit ${(current-1)*size},${size}`
|
||||
dbUtils.query(sql).then(res => {
|
||||
records = res
|
||||
resolve()
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
})
|
||||
|
||||
]).then(() => {
|
||||
response.send({
|
||||
code: 0,
|
||||
data: {records, total}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
16
src/rest/custom/add.js
Normal file
16
src/rest/custom/add.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/custom/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id, name, type, customPath, apps, createTime, dist, version, zipTime, download, error, extra,webhook} = request.body
|
||||
dbUtils.addOrUpdate({
|
||||
table: 'node_custom_config',
|
||||
form: {id, name, type, customPath, apps, createTime, dist, version, zipTime, download, error, extra,webhook}
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
14
src/rest/custom/cancelZip.js
Normal file
14
src/rest/custom/cancelZip.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/custom/cancelZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id, sql = `update node_custom_config set zipTime=null where id='${id}'`
|
||||
dbUtils.query(sql).then(() => {
|
||||
response.send({code: 0, data: "取消成功!"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
13
src/rest/custom/delete.js
Normal file
13
src/rest/custom/delete.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/custom/delete",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {ids} = request.query
|
||||
dbUtils.delete({table: 'node_custom_config', ids}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
28
src/rest/custom/detail.js
Normal file
28
src/rest/custom/detail.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/custom/detail",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id} = request.query
|
||||
dbUtils.detail({table: 'node_custom_config', id}).then(data => {
|
||||
data.apps = JSON.parse(data.apps || "[]")
|
||||
data.extra = JSON.parse(data.extra.replace(/\n/g,'') || null)
|
||||
Promise.all([
|
||||
dbUtils.query(`select * from node_wechat_apps where id in (${data.apps?.map(e=>`'${e}'`)?.toString()||202207181503})`)
|
||||
.then(res => data.appList = [data.appList, res].flat()),
|
||||
dbUtils.query(`select * from node_wechat_apps where type='${data.type}' and id like '%project_${data.customPath}%'`)
|
||||
.then(res => data.appList = [data.appList, res].flat())
|
||||
]).then(() => {
|
||||
data.appList = data.appList.filter(Boolean).map(e => {
|
||||
if (data.type == 'mp') {
|
||||
e.tabbar = data.extra?.tabBar.list?.map(c => c.id)?.includes(e.id)
|
||||
}
|
||||
return e
|
||||
})
|
||||
response.send({code: 0, data})
|
||||
})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
32
src/rest/custom/download.js
Normal file
32
src/rest/custom/download.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const fse = require("fs-extra");
|
||||
const execute = require("../../tools/exec");
|
||||
module.exports = {
|
||||
action: "/node/custom/download",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id
|
||||
dbUtils.detail({table: 'node_custom_config', id}).then(info => {
|
||||
if (info?.id) {
|
||||
let path = `${info.dist || `/zips/${info.name}v${info.version}`}`, zipPath = `/zips/${info.id}.zip`
|
||||
fse.removeSync(zipPath)
|
||||
fse.pathExists(path, (err, exists) => {
|
||||
console.log(`${path}=========>${exists}`)
|
||||
if (exists) {
|
||||
execute(`cd ${path}&&zip -r ${info.id}.zip .`)
|
||||
.then(() => execute(`cd ${path}&&mv ${info.id}.zip /zips/`))
|
||||
.then(() => {
|
||||
console.log('压缩完成!')
|
||||
setTimeout(() => {
|
||||
response.download(zipPath)
|
||||
}, 1000)
|
||||
})
|
||||
} else response.send({code: 1, err: "没有打包文件!"})
|
||||
})
|
||||
} else response.send({code: 1, err: "无法找到项目信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
74
src/rest/custom/getZip.js
Normal file
74
src/rest/custom/getZip.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const db = require("../../utils/dbUitls");
|
||||
const execute = require("../../tools/exec")
|
||||
const dayjs = require("dayjs")
|
||||
const fse = require("fs-extra");
|
||||
const axios = require('axios')
|
||||
module.exports = {
|
||||
action: "/node/custom/getZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id} = request.query, uniCon = `id='${id}'`
|
||||
db.query(`select *
|
||||
from node_custom_config
|
||||
where id = '${id}'`).then(res => {
|
||||
let info = res?.[0] || {}, sql
|
||||
if (info.id) {
|
||||
sql = `update node_custom_config
|
||||
set download=null,
|
||||
error=null,
|
||||
zipTime='${dayjs().format("YYYY-MM-DD HH:mm:ss")}'
|
||||
where ${uniCon}`
|
||||
if (info.type == 'web') {
|
||||
const {name, version, dist = `${name}_v${version}`} = info
|
||||
const buildConfig = {
|
||||
web: {task: "devops-web", token: 'fLeOGSVIRs405Me'},
|
||||
}[info.type]
|
||||
db.query(sql).then(() => axios.get(`https://jenkins.sinoecare.com/view/devops/job/${buildConfig.task}/buildWithParameters`,null,{
|
||||
params:{
|
||||
token: buildConfig.token,
|
||||
pid: id, dist
|
||||
}
|
||||
}))
|
||||
.then(() => db.query(`update node_custom_config
|
||||
set download='${dayjs().format("YYYY-MM-DD HH:mm:ss")}',
|
||||
error=''
|
||||
where ${uniCon}`))
|
||||
.then(() => response.send({code: 0, msg: "打包任务已发送"}))
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
return fse.outputFile(`./logs/errors/${dayjs().format("YYYY-MM-DD")}.log`, err)
|
||||
})
|
||||
} else {
|
||||
const buildPath = {
|
||||
web: 'base-web',
|
||||
wxwork: 'base-wxcp',
|
||||
mp: 'dvcp_v2_wxmp'
|
||||
}[info.type] || {}
|
||||
let path = `../${buildPath}`,
|
||||
{dist = `../zips/${info.name}v${info.version || "1.0.0"}`} = info
|
||||
Promise.all([
|
||||
execute(`./shell/update.sh ${info.name} ${path}`),
|
||||
db.query(sql)
|
||||
]).then(() => setTimeout(() => {
|
||||
response.send({code: 0})
|
||||
}, 1000))
|
||||
execute(`cd ${path}&&npm run apps&&node bin/pages.js ${id}&&npm run build`)
|
||||
.then(() => fse.emptyDir(dist))
|
||||
.then(() => execute(`./shell/move.sh ${info.type} ${path} ${dist}`))
|
||||
.then(() => {
|
||||
return db.query(`update node_custom_config
|
||||
set download='${dayjs().format("YYYY-MM-DD HH:mm:ss")}',
|
||||
error=''
|
||||
where ${uniCon}`)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
return fse.outputFile(`./logs/errors/${dayjs().format("YYYY-MM-DD")}.log`, err)
|
||||
})
|
||||
}
|
||||
} else return response.send({code: 1, err: "无法找到定制项目信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
16
src/rest/custom/list.js
Normal file
16
src/rest/custom/list.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/custom/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {size, current, name, type} = request.query
|
||||
dbUtils.list({
|
||||
table: 'node_custom_config',
|
||||
search: {size, current, type, name}, sort: 'download'
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
26
src/rest/custom/webhook.js
Normal file
26
src/rest/custom/webhook.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const axios = require("axios");
|
||||
module.exports = {
|
||||
action: "/node/custom/webhook",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let id = request.query?.id
|
||||
dbUtils.detail({table: 'node_custom_config', id}).then(info => {
|
||||
if (info?.id) {
|
||||
axios.post("https://qyapi.weixin.qq.com/cgi-bin/webhook/send", {
|
||||
msgtype: "markdown",
|
||||
markdown: {
|
||||
content: `> 发布系统:${info.name}
|
||||
> 发布版本:${info.version}
|
||||
> 打包完成时间:${info.download}`
|
||||
}
|
||||
}, {params: {key: info.webhook || "a5971027-2dd3-4c23-a4e4-c99a962d25a7",}}).then(res => {
|
||||
response.send({code: 0, msg: res.data})
|
||||
})
|
||||
} else response.send({code: 1, err: "无法找到项目信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
18
src/rest/index.js
Normal file
18
src/rest/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const {findFile} = require("../utils/fsUtils");
|
||||
const chalk = require("chalk");
|
||||
const log = console.log
|
||||
module.exports = {
|
||||
init: ins => {
|
||||
return findFile('./src/rest', file => {
|
||||
if (!/index\.js/.test(file)) {
|
||||
let rest = require(file.replace(/src[\\\/]rest/, '.'))
|
||||
log(`${chalk.bgBlue.black(" REST ")} ${rest.action}`)
|
||||
if (rest.method == "post") {
|
||||
ins.post(rest.action, (req, res) => rest.execute(req, res))
|
||||
} else if (rest.method == "get") {
|
||||
ins.get(rest.action, (req, res) => rest.execute(req, res))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
32
src/rest/monitorApi/add.js
Normal file
32
src/rest/monitorApi/add.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
const addLog = ({id, status, path, device, url, createTime, nodeProcess, method, code, userName, error}) => dbUtils.addOrUpdate({
|
||||
table: 'node_api_logs',
|
||||
form: {id, status, path, device, url, createTime, nodeProcess, method, code, userName, error}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
action: "/node/monitorApi/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
dbUtils.batchInsert({
|
||||
table: 'node_api_logs',
|
||||
list: [request.body].flat().map(({id, status, path, device, url, createTime, nodeProcess, method, code, userName, error}) => ({
|
||||
id,
|
||||
status,
|
||||
path,
|
||||
device,
|
||||
url,
|
||||
createTime,
|
||||
nodeProcess,
|
||||
method,
|
||||
code,
|
||||
userName,
|
||||
error
|
||||
}))
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
16
src/rest/monitorApi/list.js
Normal file
16
src/rest/monitorApi/list.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/monitorApi/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {size, current, name: path, status} = request.query
|
||||
dbUtils.list({
|
||||
table: 'node_api_logs', con: 'path',
|
||||
search: {size, current, status, path}, sort: 'createTime'
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
17
src/rest/monitorApi/sta.js
Normal file
17
src/rest/monitorApi/sta.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/monitorApi/sta",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const data = {}
|
||||
Promise.all([
|
||||
dbUtils.query(`select path,method,SUM(1) as total,createTime FROM node_api_logs where status not like '200' GROUP BY path ORDER BY total DESC limit 0,10`).then(res => data.top10 = res),
|
||||
dbUtils.query(`select status as name,SUM(1) as value FROM node_api_logs where status not like '200' GROUP BY status`).then(res => data.distribution = res)
|
||||
]).then(() => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
13
src/rest/sysuser/sysuser.js
Normal file
13
src/rest/sysuser/sysuser.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/sys/user",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
dbUtils.query(`select * from sys_user`).then(res => {
|
||||
response.send({
|
||||
code: 0,
|
||||
data: res
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
16
src/rest/wechat/add.js
Normal file
16
src/rest/wechat/add.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/wxmp/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {appid, privateKey, projectPath, version, versionName, id, npmScript} = request.body,
|
||||
form = {appid, privateKey, projectPath, version, versionName, id, npmScript}
|
||||
dbUtils.addOrUpdate({
|
||||
table: 'node_wxmp_deploy', form
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
17
src/rest/wechat/confirmZip.js
Normal file
17
src/rest/wechat/confirmZip.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/wxmp/confirmZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id} = request.query, sql = `select * from node_wxmp_deploy where id='${id}'`
|
||||
dbUtils.query(sql).then(res => {
|
||||
let info = res?.[0]
|
||||
if (info?.appid) {
|
||||
response.send({code: 0, data: info})
|
||||
} else response.send({code: 1, err: "无法找到小程序信息"})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
13
src/rest/wechat/delete.js
Normal file
13
src/rest/wechat/delete.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/wxmp/delete",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {ids} = request.query
|
||||
dbUtils.delete({table: 'node_wxmp_deploy', ids}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
16
src/rest/wechat/detail.js
Normal file
16
src/rest/wechat/detail.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/wxmp/detail",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id} = request.query
|
||||
dbUtils.query(`select * from node_wxmp_deploy where id='${id}' limit 0,1`).then(res => {
|
||||
response.send({
|
||||
code: 0,
|
||||
data: res?.[0]
|
||||
})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
26
src/rest/wechat/download.js
Normal file
26
src/rest/wechat/download.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const fse = require("fs-extra");
|
||||
const execute = require("../../tools/exec");
|
||||
module.exports = {
|
||||
action: "/node/wxmp/download",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id} = request.query
|
||||
if (id) {
|
||||
let path = `/zips/${id}/`, zipPath = `/zips/${id}.zip`
|
||||
fse.removeSync(zipPath)
|
||||
fse.pathExists(path, (err, exists) => {
|
||||
console.log(`${path}=========>${exists}`)
|
||||
if (exists) {
|
||||
execute(`cd ${path}&&zip -r ${id}.zip .`)
|
||||
.then(() => execute(`cd ${path}&&mv ${id}.zip /zips`))
|
||||
.then(() => {
|
||||
console.log('压缩完成!')
|
||||
setTimeout(() => {
|
||||
response.download(zipPath)
|
||||
}, 1000)
|
||||
})
|
||||
} else response.send({code: 1, err: "没有打包文件!"})
|
||||
})
|
||||
} else response.send({code: 1, err: "无法找到小程序信息"})
|
||||
}
|
||||
}
|
||||
39
src/rest/wechat/getZip.js
Normal file
39
src/rest/wechat/getZip.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const db = require("../../utils/dbUitls");
|
||||
const execute = require("../../tools/exec")
|
||||
const dayjs = require("dayjs")
|
||||
const fse = require("fs-extra");
|
||||
const isDev = process.env.OS == 'Windows_NT'
|
||||
module.exports = {
|
||||
action: "/node/wxmp/getZip",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {id, appid} = request.query
|
||||
db.query(`select * from node_wxmp_deploy where id='${id}'`).then(res => {
|
||||
let info = res?.[0], sql
|
||||
if (info?.id) {
|
||||
sql = `update node_wxmp_deploy set error=null where id='${id}'`
|
||||
} else return response.send({code: 1, err: "无法找到小程序信息"})
|
||||
db.query(sql).then(() => setTimeout(() => {
|
||||
response.send({code: 0})
|
||||
}, 2000))
|
||||
const path = info.projectPath || (isDev ? 'E:\\code\\cunwei\\dvcp_v2_wechat' : '/dvcp_v2_wechat'),
|
||||
dest = (isDev ? `E:\\wxmpZips\\${id}` : `/zips/${id}/`),
|
||||
processEnv = info.npmScript || 'build',
|
||||
dist = info.npmScript ? `${path}/dist/${info.npmScript}/` : `${path}/dist/build/mp-weixin/`
|
||||
execute(`cd ${path}&&npm run apps&&node bin/pages.js ${appid} ${id}&&npm run ${processEnv}`)
|
||||
.then(() => fse.emptyDir(dest))
|
||||
.then(() => fse.ensureDir(dist))
|
||||
.then(() => fse.copy(dist, dest))
|
||||
.then(() => fse.emptyDir(dist))
|
||||
.then(() => {
|
||||
db.query(`update node_wxmp_deploy set error='打包时间:${dayjs().format("YYYY-MM-DD HH:mm:ss")}' where id='${id}'`)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
db.query(`update node_wxmp_deploy set error='${err}' where id='${id}'`)
|
||||
})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
}
|
||||
}
|
||||
16
src/rest/wechat/list.js
Normal file
16
src/rest/wechat/list.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/wxmp/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {size, current, name, type} = request.query
|
||||
dbUtils.list({
|
||||
table: 'node_wxmp_deploy',
|
||||
search: {size, current, type, name}
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
21
src/rest/wechat/sync.js
Normal file
21
src/rest/wechat/sync.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
uid = e => [e.appid, e.corpId].join("_")
|
||||
module.exports = {
|
||||
action: "/node/wxmp/sync",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let records = {}, meta = []
|
||||
Promise.all([
|
||||
dbUtils.query("select * from app_dvcp_config").then(res => meta = res),
|
||||
dbUtils.query("select * from node_wxmp_deploy").then(res => res?.map(e => records[uid(e)] = e))
|
||||
]).then(() => Promise.all(meta.map(e => {
|
||||
const {name, miniapp_appid: appid, corp_id: corpId, web_url: webUrl} = e
|
||||
const id = records[uid({appid, corpId})]?.id
|
||||
delete e.system_info
|
||||
return dbUtils.addOrUpdate({
|
||||
table: 'node_wxmp_deploy',
|
||||
form: {id, name, appid, corpId, webUrl, dvcpConfig: e}
|
||||
})
|
||||
}))).finally(() => response.send({code: 0, data: ""}))
|
||||
}
|
||||
}
|
||||
42
src/rest/wechatapps/add.js
Normal file
42
src/rest/wechatapps/add.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
|
||||
const addOrUpdate = form => {
|
||||
let cols = [], arr = []
|
||||
Object.keys(form).map(e => {
|
||||
if (form[e]) {
|
||||
cols.push(e)
|
||||
arr.push(`'${form[e]}'`)
|
||||
}
|
||||
})
|
||||
return Promise.resolve(`insert into node_wechat_apps (${cols.join(",")}) values(${arr.join(",")})`)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
action: "/node/wechatapps/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let form = request.body
|
||||
if (form.type) {
|
||||
dbUtils.query(`delete from node_wechat_apps where type='${form.type}'`).then(() => {
|
||||
if (form.list?.length > 0) {
|
||||
Promise.all(form.list.map(e => addOrUpdate(e).then(sql => dbUtils.query(sql)))).then(() => {
|
||||
response.send({code: 0})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
} else {
|
||||
if (form.name) {
|
||||
addOrUpdate(form).then(sql => dbUtils.query(sql)).then(() => {
|
||||
response.send({code: 0})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
} else response.send({code: 1, err: "name必填"})
|
||||
}
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
} else response.send({code: 1, err: "缺少必要参数type"})
|
||||
|
||||
}
|
||||
}
|
||||
31
src/rest/wechatapps/list.js
Normal file
31
src/rest/wechatapps/list.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/wechatapps/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let total = 0, records = [], {size, current = 1, name = "", type, isMain} = request.query
|
||||
if (type) {
|
||||
let condition = `where type='${type}' and (name like '%${name}%' or label like '%${name}%')`
|
||||
isMain && (condition += ` and libPath not like '%project%'`)
|
||||
Promise.all([
|
||||
dbUtils.query(`select 1 from node_wechat_apps ${condition}`).then(res => {
|
||||
return total = res.length
|
||||
}),
|
||||
new Promise(resolve => {
|
||||
let sql = `select * from node_wechat_apps ${condition} limit ${(current-1)*size||0},${size||1}`
|
||||
dbUtils.query(sql).then(res => {
|
||||
records = res
|
||||
resolve()
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err.sqlMessage})
|
||||
})
|
||||
})
|
||||
]).then(() => {
|
||||
response.send({
|
||||
code: 0,
|
||||
data: {records, total}
|
||||
})
|
||||
})
|
||||
} else response.send({code: 1, err: 'type为必填参数'})
|
||||
}
|
||||
}
|
||||
71
src/rest/wxtest/action.js
Normal file
71
src/rest/wxtest/action.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const {getSignature, decrypt} = require("@wecom/crypto");
|
||||
const {Parser} = require("xml2js");
|
||||
const {query} = require("../../utils/dbUitls");
|
||||
const dayjs = require("dayjs");
|
||||
const axios = require("axios");
|
||||
const {getAccessToken} = require("./getUserInfo");
|
||||
const token = "pnYAdXEHYzYhIyzE6Qbs2L"
|
||||
const encodingAESKey = "fHkOHrUGSVUmPjFmshLEFN2XbaqF3OxsuYgnJu6DB1G"
|
||||
|
||||
let accessToken
|
||||
|
||||
const reply = (agentid, to, content) => {
|
||||
axios.post("https://qyapi.weixin.qq.com/cgi-bin/message/send", {
|
||||
touser: to, agentid, msgtype: "markdown", markdown: {
|
||||
content
|
||||
}
|
||||
}, {params: {access_token: accessToken}})
|
||||
}
|
||||
/**
|
||||
* 获取当前值班人并将信息发送给询问人,同时通知值班人员
|
||||
* @param params
|
||||
*/
|
||||
const handleReplyDutyInfo = (params) => {
|
||||
const {FromUserName: touser, AgentID: agentid} = params,
|
||||
now = dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
sql = `select * from node_wx_test_duty where dutyStartTime<='${now}' and dutyEndTime>='${now}'`
|
||||
query(sql).then(res => {
|
||||
const info = res?.[0] || {}
|
||||
if (info.dutyUserId) {
|
||||
getAccessToken().then(access_token => {
|
||||
accessToken = access_token
|
||||
/**
|
||||
* 回复查询值班信息给查询人
|
||||
*/
|
||||
reply(agentid, touser, `当前值班信息如下\n>值班时间:${info.dutyStartTime} - ${info.dutyEndTime}\n值班人员:${info.dutyUserName}\n`)
|
||||
/**
|
||||
* 通知提醒值班人员
|
||||
*/
|
||||
reply(agentid, info.dutyUserId, `今天轮到你值班了,请知悉~`)
|
||||
})
|
||||
} else {
|
||||
/**
|
||||
* 无值班人员
|
||||
*/
|
||||
reply(agentid, touser, `今天没有值班人员哦~`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
action: "/node/wxtest/action",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {msg_signature, timestamp, nonce} = request.query,
|
||||
{xml: {encrypt}} = request.body
|
||||
const signature = getSignature(token, timestamp, nonce, encrypt[0]);
|
||||
if (msg_signature == signature) {
|
||||
const context = decrypt(encodingAESKey, encrypt[0])
|
||||
const parser = new Parser({explicitArray: false})
|
||||
parser.parseString(context.message, (err, result) => {
|
||||
if (!err) {
|
||||
if (result.xml.Content == '值班') {
|
||||
handleReplyDutyInfo(result.xml)
|
||||
}
|
||||
response.send({code: 0, message: "success"})
|
||||
} else response.send({code: 1, err})
|
||||
})
|
||||
} else response.send({code: 1, message: "error"})
|
||||
}
|
||||
}
|
||||
17
src/rest/wxtest/actionGet.js
Normal file
17
src/rest/wxtest/actionGet.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const {getSignature, decrypt} = require("@wecom/crypto");
|
||||
const token = "pnYAdXEHYzYhIyzE6Qbs2L"
|
||||
const encodingAESKey = "fHkOHrUGSVUmPjFmshLEFN2XbaqF3OxsuYgnJu6DB1G"
|
||||
module.exports = {
|
||||
action: "/node/wxtest/action",
|
||||
method: "get",
|
||||
execute: (request, response) => {
|
||||
const {msg_signature, timestamp, nonce, echostr} = request.query
|
||||
const signature = getSignature(token, timestamp, nonce, echostr);
|
||||
if (msg_signature == signature) {
|
||||
const context = decrypt(encodingAESKey, echostr)
|
||||
response.send(context.message)
|
||||
} else {
|
||||
response.send({code: 1, message: "验证不通过"})
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/rest/wxtest/add.js
Normal file
16
src/rest/wxtest/add.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/duty/addOrUpdate",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {id, dutyUserId,dutyUserName,dutyStartTime,dutyEndTime} = request.body
|
||||
dbUtils.addOrUpdate({
|
||||
table: 'node_wx_test_duty',
|
||||
form: {id, dutyUserId,dutyUserName,dutyStartTime,dutyEndTime}
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
43
src/rest/wxtest/getUserInfo.js
Normal file
43
src/rest/wxtest/getUserInfo.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const axios = require("axios");
|
||||
const auth = require("../../config/auth.js")
|
||||
const CORPID = "ww596787bb70f08288"
|
||||
const SECRET = "ZEpS51fCRPznHG16k0z1lfxaH0VciEnBljeP9aR47VU"
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
*/
|
||||
const getAccessToken = (corpid = CORPID, secret = SECRET) => {
|
||||
const url = `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${secret}`
|
||||
return axios.get(url).then(res => {
|
||||
return res.data?.access_token
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 获取 userId及其他信息
|
||||
*/
|
||||
const getUserInfo = (accessToken, code) => {
|
||||
return axios.get(`https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo`, {
|
||||
params: {access_token: accessToken, code}
|
||||
})
|
||||
}
|
||||
module.exports = {
|
||||
action: "/node/wxtest/token",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
const {code} = request.query
|
||||
getAccessToken().then(token => getUserInfo(token, code)).then(res => {
|
||||
const userid = res?.data?.userid
|
||||
//userid换取我方系统token
|
||||
if (userid) {
|
||||
const token = auth.generateToken(userid)
|
||||
response.send({code: 0, token})
|
||||
} else {
|
||||
response.send({code: 1, err: res.data})
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err})
|
||||
})
|
||||
},
|
||||
getAccessToken
|
||||
}
|
||||
16
src/rest/wxtest/list.js
Normal file
16
src/rest/wxtest/list.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const dbUtils = require("../../utils/dbUitls");
|
||||
module.exports = {
|
||||
action: "/node/duty/list",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
let {size, current} = request.query
|
||||
dbUtils.list({
|
||||
table: 'node_wx_test_duty',
|
||||
search: {size, current}, sort: 'dutyStartTime', con: "dutyUserName"
|
||||
}).then(data => {
|
||||
response.send({code: 0, data})
|
||||
}).catch(err => {
|
||||
response.send({code: 1, err: err?.sqlMessage || err || ""})
|
||||
})
|
||||
}
|
||||
}
|
||||
23
src/rest/wxtest/token.js
Normal file
23
src/rest/wxtest/token.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const axios = require("axios");
|
||||
const CORPID = "ww596787bb70f08288"
|
||||
const SECRET = "Bh3GT11_bzxSm03xZBY8otjw_WLWeLsduzDQweUohAY"
|
||||
const getAccessToken = (corpid = CORPID, secret = SECRET) => {
|
||||
const url = `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${secret}`
|
||||
return axios.get(url).then(res => {
|
||||
return res.data?.access_token
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
action: "/node/wxtest/access",
|
||||
method: "post",
|
||||
execute: (request, response) => {
|
||||
getAccessToken().then(token => {
|
||||
response.send({code: 0, token})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
response.send({code: 1, err})
|
||||
})
|
||||
},
|
||||
getAccessToken
|
||||
}
|
||||
12
src/tools/exec.js
Normal file
12
src/tools/exec.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const cp = require("child_process");
|
||||
const execute = (cmd, signal) => new Promise((resolve, reject) => {
|
||||
const pid = cp.exec(cmd, {windowsHide: true, signal}, (err) => {
|
||||
if (!err) {
|
||||
resolve(cmd)
|
||||
} else reject(err)
|
||||
})
|
||||
pid.stdout.on('data', data => {
|
||||
console.log(data)
|
||||
})
|
||||
})
|
||||
module.exports = execute
|
||||
161
src/tools/generate.js
Normal file
161
src/tools/generate.js
Normal file
@@ -0,0 +1,161 @@
|
||||
const fse = require("fs-extra");
|
||||
const {readFile} = require("../utils/fsUtils");
|
||||
const {checkJson} = require("./index");
|
||||
/**
|
||||
* 生成入口页
|
||||
*/
|
||||
const genHome = (app, dest) => {
|
||||
return readFile('./tpl/AppEntry.vue').then(data => {
|
||||
let file = data.toString(),
|
||||
content = file.replace(/@appName/g, app.appName)
|
||||
.replace(/@name/g, app.name)
|
||||
let dicts = `'yesOrNo'`
|
||||
if (checkJson(app.props)) {
|
||||
let props = JSON.parse(app.props)?.map(e => e.dict).filter(e => !!e)
|
||||
props.length > 0 && (dicts = props.map(e => `'${e}'`).toString())
|
||||
}
|
||||
content = content.replace(/@dicts/g, dicts)
|
||||
return fse.outputFileSync(`${dest}/${app.appName}.vue`, content)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 生成列表页
|
||||
*/
|
||||
const genList = (app, dest) => {
|
||||
return readFile('./tpl/list.vue').then(data => {
|
||||
let file = data.toString(),
|
||||
content = file.replace(/@rightCode/g, app.rightCode)
|
||||
.replace(/@name/g, app.name),
|
||||
listProps = "", searchProps = "", btns = "", tableBtns = ""
|
||||
if (checkJson(app.props)) {
|
||||
let props = JSON.parse(app.props)
|
||||
listProps = JSON.stringify(props.filter(e => e.isTable)?.map(e => {
|
||||
delete e.isSearch
|
||||
delete e.isTable
|
||||
delete e.isDetail
|
||||
return e
|
||||
}) || null)?.replace(/"([^"]+)":/g, '$1:')
|
||||
props.filter(e => e.isSearch && e.dict).map(e => {
|
||||
searchProps += `<ai-select v-model="search.${e.prop}" placeholder="${e.label}" :selectList="dict.getDict('${e.dict}')"/>`
|
||||
})
|
||||
}
|
||||
if (checkJson(app.btns)) {
|
||||
let buttons = JSON.parse(app.btns)
|
||||
buttons.map(e => {
|
||||
if (e == "insertEnable") {
|
||||
btns += `<el-button type="primary" icon="iconfont iconAdd" @click="handleAdd()">添加</el-button>`
|
||||
} else if (e == "importEnable") {
|
||||
btns += `<ai-import :instance="instance" name="${app.name}" title="导入${app.name}" suffixName="xlsx"
|
||||
url="/app/${app.rightCode}/downloadTemplate" importUrl="/app/${app.rightCode}/import"
|
||||
@onSuccess="page.current=1,getTableData()"/>`
|
||||
} else if (e == "exportEnalbe") {
|
||||
btns += `<ai-download url="/app/${app.rightCode}/export" :params="{...search,ids}" :instance="instance" fileName="${app.name}导出文件"/>`
|
||||
} else if (e == "editEnable") {
|
||||
tableBtns += `<el-button type="text" @click="handleAdd(row.id)">编辑</el-button>`
|
||||
} else if (e == "deleteEnable") {
|
||||
tableBtns += `<el-button type="text" @click="handleDelete(row.id)">删除</el-button>`
|
||||
} else if (e == "batchDelEnable") {
|
||||
btns += `<el-button icon="iconfont iconDelete" :disabled="!search.ids" @click="handleDelete(search.ids)">删除</el-button>`
|
||||
}
|
||||
})
|
||||
if (!searchProps) {
|
||||
//当没有筛选条件时,按钮替换原筛选条件位置
|
||||
searchProps = btns
|
||||
btns = ""
|
||||
} else {
|
||||
btns = `<ai-search-bar><template #left>${btns}</template></ai-search-bar>`
|
||||
}
|
||||
}
|
||||
content = content.replace(/@listProps/g, listProps)
|
||||
.replace(/@searchProps/g, searchProps)
|
||||
.replace(/@btns/g, btns)
|
||||
.replace(/@tableBtns/g, tableBtns)
|
||||
return fse.outputFileSync(`${dest}/list.vue`, content)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 生成新增/编辑页
|
||||
*/
|
||||
const genAdd = (app, dest) => {
|
||||
return readFile('./tpl/add.vue').then(data => {
|
||||
let file = data.toString(),
|
||||
content = file.replace(/@rightCode/g, app.rightCode)
|
||||
.replace(/@name/g, app.name),
|
||||
rules = "", domain = ""
|
||||
if (checkJson(app.detailConfig)) {
|
||||
let detail = JSON.parse(app.detailConfig), props = detail?.map(e => e.column).flat()
|
||||
props.filter(e => e.mustFill == 1).map(e => {
|
||||
rules += `${e.prop}: {required: true, message: "${e.fieldTips}"},`
|
||||
})
|
||||
detail.map(group => {
|
||||
let fields = ``
|
||||
group.column?.map(e => {
|
||||
fields += `<el-form-item label="${e.fieldName}" prop="${e.prop}" ${e.grid == 1 ? '' : 'class="half"'}>${getComp(e)}</el-form-item>`
|
||||
})
|
||||
domain += `<ai-card title="${group.groupName}"><template #content> ${fields}</template></ai-card>`
|
||||
})
|
||||
}
|
||||
content = content.replace(/@content/g, domain)
|
||||
.replace(/@rules/g, rules)
|
||||
return fse.outputFileSync(`${dest}/add.vue`, content)
|
||||
})
|
||||
}
|
||||
const getComp = e => {
|
||||
//字典下拉选择
|
||||
if (e.type == 'dict') {
|
||||
return `<ai-select v-model="form.${e.prop}" placeholder="${e.fieldName}" :selectList="dict.getDict('${e.dict}')" ${e.disable == 1 ? 'disabled' : ''}/>`
|
||||
//单选radio
|
||||
} else if (e.type == 'radio') {
|
||||
return `<el-radio-group v-model="form.${e.prop}" ${e.disable == 1 ? 'disabled' : ''}>
|
||||
<el-radio :label="item.dictValue" v-for="(item, i) in dict.getDict('${e.dict}')" :key="i">{{ item.dictName }}</el-radio>
|
||||
</el-radio-group>`
|
||||
//开关onOff
|
||||
} else if (e.type == 'onOff') {
|
||||
return `<el-switch v-model="form.${e.prop}" active-color="#26f" inactive-color="#ddd" active-value="1" inactive-value="0" ${e.disable == 1 ? 'disabled' : ''}/>`
|
||||
//多选checkbox
|
||||
} else if (e.type == 'checkbox') {
|
||||
return `<el-checkbox-group v-model="form.${e.prop}" ${e.disable == 1 ? 'disabled' : ''}>
|
||||
<el-checkbox v-for="(item, i) in dict.getDict('${e.dict}')" :label="item.dictValue" :key="i">{{ item.dictName }}</el-checkbox>
|
||||
</el-checkbox-group>`
|
||||
} else if (e.type == 'idNumber') {
|
||||
return `<ai-id v-model="form.${e.prop}" ${e.disable == 1 ? 'disabled' : ''}/>`
|
||||
//input输入框
|
||||
} else if (['input', 'name', 'phone'].includes(e.type)) {
|
||||
return `<el-input v-model="form.${e.prop}" placeholder="请输入${e.fieldName}" clearable ${e.disable == 1 ? 'disabled' : ''} :maxlength="${e.maxLength}" show-word-limit/>`
|
||||
//number 输入框
|
||||
} else if (e.type == 'number') {
|
||||
return `<el-input-number v-model="form.${e.prop}" label="请输入${e.fieldName}" ${e.disable == 1 ? 'disabled' : ''} :precision="${e.decimalPlaces}" :max="${e.maxValue}" :min="${e.minValue}"/>`
|
||||
//textarea输入框
|
||||
} else if (e.type == 'textarea' || e.type == 'text') {
|
||||
return `<el-input v-model="form.${e.prop}" placeholder="请输入${e.fieldName}" clearable ${e.disable == 1 ? 'disabled' : ''} :maxlength="${e.maxLength}" type="textarea" show-word-limit :rows="3"/>`
|
||||
//日期选择
|
||||
} else if (e.type == 'date') {
|
||||
return `<el-date-picker style="width: 100%;" v-model="form.${e.prop}" type="date" placeholder="请选择" ${e.disable == 1 ? 'disabled' : ''} :value-format="${e.timePattern}"/>`
|
||||
//日期带时分秒选择
|
||||
} else if (e.type == 'datetime') {
|
||||
return `<el-date-picker v-model="form.${e.prop}" type="datetime" placeholder="选择日期时间" ${e.disable == 1 ? 'disabled' : ''} :value-format="${e.timePattern}"/>`
|
||||
//时间-时分秒选择
|
||||
} else if (e.type == 'time') {
|
||||
return `<el-time-picker v-model="form.${e.prop}" placeholder="请选择" ${e.disable == 1 ? 'disabled' : ''} :value-format="${e.timePattern}"/>`
|
||||
//附件
|
||||
} else if (e.type == 'upload') {
|
||||
return ` <ai-uploader :instance="instance" isShowTip fileType="file" v-model="form.${e.prop}" ${e.disable == 1 ? 'disabled' : ''}
|
||||
acceptType=".zip,.rar,.doc,.docx,.xls,.ppt,.pptx,.pdf,.txt,.jpg,.png,.xlsx" :limit="${e.fileMaxCount}" :maxSize="${e.fileChoseSize}"/>`
|
||||
//富文本
|
||||
} else if (e.type == 'rtf') {
|
||||
return `<ai-editor v-model="form.${e.prop}" :instance="instance" ${e.disable == 1 ? 'disabled' : ''}/>`
|
||||
//地区选择
|
||||
} else if (e.type == 'area') {
|
||||
return ` <ai-area-get :instance="instance" v-model="form.${e.prop}" :name.sync="form.${e.fieldDbName}_name" ${e.disable == 1 ? 'disabled' : ''}/>`
|
||||
} else if (e.type == 'user') {
|
||||
//人员选择
|
||||
return `<ai-wechat-selecter slot="append" isShowUser :instance="instance" v-model="form.${e.prop}"/>`
|
||||
}
|
||||
}
|
||||
const generate = (app, dest) => {
|
||||
fse.emptydirSync(dest)
|
||||
let tasks = [genHome(app, dest), genList(app, dest)]
|
||||
app.detailType == 0 && tasks.push(genAdd(app, dest))
|
||||
return Promise.all(tasks)
|
||||
}
|
||||
module.exports = generate
|
||||
19
src/tools/index.js
Normal file
19
src/tools/index.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const checkJson = str => {
|
||||
if (typeof str == 'object') {
|
||||
try {
|
||||
str = JSON.stringify(str)
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (typeof str == 'string') {
|
||||
try {
|
||||
let obj = JSON.parse(str);
|
||||
return !!(typeof obj == 'object' && obj);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
module.exports = {checkJson}
|
||||
96
src/utils/dbUitls.js
Normal file
96
src/utils/dbUitls.js
Normal file
@@ -0,0 +1,96 @@
|
||||
const mysql = require("mysql");
|
||||
const dbConfig = require("../config/db");
|
||||
const {v4: uuid} = require("uuid");
|
||||
const dayjs = require("dayjs");
|
||||
const chalk = require("chalk");
|
||||
const query = sql => new Promise((resolve, reject) => {
|
||||
this.pool?.getConnection((err, conn) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
conn.query(sql, (err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
conn.release()
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
const insert = ({table, form}) => {
|
||||
let sql
|
||||
if (form.id) {//编辑
|
||||
let arr = Object.entries(form).map(([e, v]) => {
|
||||
if (v) {
|
||||
if (typeof v == "object") {
|
||||
v = JSON.stringify(v)
|
||||
v = v.replace(/(')/g, "\\$1")
|
||||
}
|
||||
} else v = ''
|
||||
return `${e}='${v}'`
|
||||
})
|
||||
sql = `update ${table} set ${arr.join(",")} where id='${form.id}'`
|
||||
} else {//新增
|
||||
let cols = [], arr = []
|
||||
Object.entries(form).map(([e, v]) => {
|
||||
if (v) {
|
||||
cols.push(e)
|
||||
if (typeof v == "object") {
|
||||
v = JSON.stringify(v)
|
||||
v = v.replace(/(')/g, "\\$1")
|
||||
}
|
||||
arr.push(`'${v}'`)
|
||||
}
|
||||
})
|
||||
sql = `insert into ${table} (id,createTime,${cols.join(",")}) values('${uuid()}','${dayjs().format("YYYY-MM-DD HH:mm:ss")}',${arr.join(",")})`
|
||||
}
|
||||
return sql
|
||||
}
|
||||
module.exports = {
|
||||
pool: null,
|
||||
init: () => {
|
||||
this.pool = mysql.createPool(dbConfig)
|
||||
console.log(`${chalk.bgBlue.black(" DATABASE ")} 数据库已连接`)
|
||||
},
|
||||
query,
|
||||
list: ({table, search, con = 'name', sort}) => {
|
||||
//列表查询
|
||||
let total = 0, records = []
|
||||
if (table) {
|
||||
const {current, size = 10} = search, params = JSON.parse(JSON.stringify(search))
|
||||
const conValue = params[con] || ""
|
||||
delete params.current
|
||||
delete params.size
|
||||
delete params[con]
|
||||
const sqlCon = Object.keys(params).map(e => `and ${e}='${params[e]}'`).join(" ")
|
||||
return Promise.all([
|
||||
query(`select 1 from ${table} where ${con} like '%${conValue}%' ${sqlCon}`).then(res => {
|
||||
return total = res.length
|
||||
}),
|
||||
query(`select * from ${table} where ${con} like '%${conValue}%' ${sqlCon} order by ${sort||'createTime'} desc limit ${((current-1)||0)*size},${size}`).then(res => {
|
||||
return records = res
|
||||
})
|
||||
]).then(() => {
|
||||
return {records, total}
|
||||
})
|
||||
}
|
||||
},
|
||||
batchInsert({table, list}) {
|
||||
return query(list.map(form => insert({table, form})).join(";"))
|
||||
},
|
||||
addOrUpdate: ({table, form}) => {
|
||||
//新增和更新
|
||||
const sql = insert({table, form})
|
||||
return query(sql)
|
||||
},
|
||||
delete: ({table, ids}) => {
|
||||
ids = ids?.split(",")?.map(e => `'${e}'`)?.toString()
|
||||
return query(`delete from ${table} where id in (${ids})`)
|
||||
},
|
||||
detail: ({table, id}) => {
|
||||
return query(`select * from ${table} where id='${id}' limit 0,1`).then(res => res?.[0])
|
||||
},
|
||||
format: args => args.map(e => `${e.prop}`).join(" ")
|
||||
}
|
||||
38
src/utils/fsUtils.js
Normal file
38
src/utils/fsUtils.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
const promisify = fn => {
|
||||
return function () {
|
||||
let args = arguments;
|
||||
return new Promise(function (resolve, reject) {
|
||||
[].push.call(args, function (err, result) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
fn.apply(null, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const readdir = promisify(fs.readdir)
|
||||
const stat = promisify(fs.stat)
|
||||
const findFile = (dir = '.', cb) => {
|
||||
return readdir(dir).then(apps => {
|
||||
return Promise.all(apps.map(e => {
|
||||
let cPath = path.join(dir, e)
|
||||
return stat(cPath).then(state => {
|
||||
if (state.isDirectory()) {
|
||||
return findFile(cPath, cb)
|
||||
} else if (state.isFile()) {
|
||||
cb && cb(cPath)
|
||||
}
|
||||
})
|
||||
}))
|
||||
})
|
||||
}
|
||||
const readFile = promisify(fs.readFile)
|
||||
module.exports = {readdir, stat, findFile, readFile}
|
||||
149
src/websocket/custom/getZip.js
Normal file
149
src/websocket/custom/getZip.js
Normal file
@@ -0,0 +1,149 @@
|
||||
const db = require("../../utils/dbUitls");
|
||||
const execute = require("../../tools/exec")
|
||||
const dayjs = require("dayjs")
|
||||
const fse = require("fs-extra");
|
||||
const axios = require('axios')
|
||||
|
||||
const http = axios.create({
|
||||
baseURL: 'http://jenkins:114295d0b955e67a18b11917bd281ea9dc@121.37.155.68:35801',
|
||||
})
|
||||
|
||||
const jobs = {}
|
||||
let controller = new AbortController()
|
||||
const handleZip = (id, ws) => {
|
||||
const uniCon = `id='${id}'`
|
||||
const sendMessage = data => ws.send(JSON.stringify(data))
|
||||
|
||||
class counter {
|
||||
constructor(remark) {
|
||||
this.count = 0
|
||||
sendMessage({code: 0, progress: this.count, remark})
|
||||
this.timer = setInterval(() => {
|
||||
sendMessage({code: 0, progress: ++this.count, remark})
|
||||
}, 6000)
|
||||
}
|
||||
|
||||
set(progress, id) {
|
||||
if (this.timer) clearInterval(this.timer)
|
||||
this.count = progress
|
||||
sendMessage({code: 0, progress: this.count, id})
|
||||
this.timer = setInterval(() => {
|
||||
sendMessage({code: 0, progress: ++this.count, id})
|
||||
}, 4000)
|
||||
}
|
||||
|
||||
stop(row) {
|
||||
if (this.timer) clearInterval(this.timer)
|
||||
sendMessage({code: 1, row, id: row.id})
|
||||
}
|
||||
|
||||
finish(row) {
|
||||
if (this.timer) clearInterval(this.timer)
|
||||
sendMessage({code: 0, progress: 100, row, id: row.id})
|
||||
}
|
||||
}
|
||||
|
||||
const startUpdateSql = () => db.query(`update node_custom_config
|
||||
set download=null,
|
||||
error=null,
|
||||
zipTime='${dayjs().format("YYYY-MM-DD HH:mm:ss")}'
|
||||
where ${uniCon}`)
|
||||
const endUpdateSql = () => db.query(`update node_custom_config
|
||||
set download='${dayjs().format("YYYY-MM-DD HH:mm:ss")}',
|
||||
error=''
|
||||
where ${uniCon}`)
|
||||
const errorUpdateSql = msg => db.query(`update node_custom_config
|
||||
set error='${msg}',
|
||||
zipTime=null
|
||||
where ${uniCon}`)
|
||||
db.detail({table: "node_custom_config", id}).then((info = {}) => {
|
||||
if (info.id) {
|
||||
const {signal} = controller;
|
||||
const progress = new counter(`正在处理 ${info.name} 的打包工作...`)
|
||||
if (['web','wxwork'].includes(info.type)) {
|
||||
const {name, version, dist} = info
|
||||
const deploy = dist?.trim() || `${name}v${version}`
|
||||
const buildConfig = {
|
||||
web: {task: "devops-web", token: 'fLeOGSVIRs405Me'},
|
||||
wxwork: {task: "devops-h5", token: 'fLeOGSVIRs405Me'},
|
||||
}[info.type]
|
||||
let currentJob = 1
|
||||
startUpdateSql()
|
||||
.then(() => progress.set(30, id))
|
||||
.then(() => fse.emptyDir(dist || `../zips/${deploy}`))
|
||||
.then(() => http.get(`/view/devops/job/${buildConfig.task}/api/json`).then(res => currentJob = (res.data?.nextBuildNumber || 1)))
|
||||
.then(() => http.get(`/view/devops/job/${buildConfig.task}/buildWithParameters`, {params: {token: buildConfig.token, pid: id, dist: deploy}}))
|
||||
.then(() => new Promise((resolve, reject) => {
|
||||
jobs[id] = {task: buildConfig.task, build: currentJob}
|
||||
const timer = setInterval(() => {
|
||||
http.get(`/view/devops/job/${buildConfig.task}/${currentJob}/api/json`).then(res => {
|
||||
if (['SUCCESS', 'UNSTABLE'].includes(res.data.result)) {
|
||||
clearInterval(timer)
|
||||
progress.set(90, id)
|
||||
endUpdateSql().then(resolve)
|
||||
} else if (res.data.result == 'ABORTED') {
|
||||
clearInterval(timer)
|
||||
reject("构建取消")
|
||||
} else if (res.data.result == 'FAILURE') {
|
||||
clearInterval(timer)
|
||||
reject("构建失败")
|
||||
}
|
||||
}).catch(() => 0)
|
||||
}, 2000)
|
||||
}))
|
||||
.then(() => db.detail({table: "node_custom_config", id}))
|
||||
.then(row => progress.finish(row))
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
const msg = `执行失败:${err.cmd || err}`
|
||||
return errorUpdateSql(msg)
|
||||
.then(() => db.detail({table: "node_custom_config", id}))
|
||||
.then(row => progress.stop(row))
|
||||
.catch(() => 0)
|
||||
})
|
||||
} else {
|
||||
const buildPath = {
|
||||
web: 'base-web', wxwork: 'base-wxcp', mp: 'dvcp_v2_wxmp'
|
||||
}[info.type] || {}
|
||||
let path = `/${buildPath}`, {dist} = info
|
||||
dist = dist || `/zips/${info.name}v${info.version || "1.0.0"}`
|
||||
Promise.all([startUpdateSql(), execute(`./shell/update.sh ${info.name} ${path}`, signal)])
|
||||
.then(cmd => progress.set(30, info?.id))
|
||||
.then(() => execute(`cd ${path}&&npm run apps&&node bin/pages.js ${id}&&npm run build`, signal))
|
||||
.then(cmd => progress.set(70, info?.id))
|
||||
.then(() => fse.emptyDir(dist))
|
||||
.then(() => execute(`./shell/move.sh ${info.type} ${path} ${dist}`, signal))
|
||||
.then(cmd => progress.set(90, info?.id))
|
||||
.then(() => endUpdateSql())
|
||||
.then(() => db.detail({table: "node_custom_config", id}))
|
||||
.then(row => progress.finish(row))
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
const msg = `执行失败:${err.cmd}`
|
||||
return errorUpdateSql(msg)
|
||||
.then(() => db.detail({table: "node_custom_config", id}))
|
||||
.then(row => progress.stop(row))
|
||||
.catch(() => 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
module.exports = {
|
||||
action: "/custom/getZip", execute: (ws, request) => {
|
||||
const {id, cid} = request
|
||||
if (cid) {
|
||||
if (jobs[cid]) {
|
||||
const {task, build} = jobs[cid]
|
||||
http.post(`/job/${task}/${build}/stop`)
|
||||
} else {
|
||||
controller.abort()
|
||||
controller = new AbortController()
|
||||
}
|
||||
} else if (id) {
|
||||
handleZip(id, ws)
|
||||
}
|
||||
},
|
||||
}
|
||||
34
src/websocket/index.js
Normal file
34
src/websocket/index.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const {findFile} = require("../utils/fsUtils");
|
||||
const chalk = require("chalk");
|
||||
const dayjs = require("dayjs");
|
||||
const {checkJson} = require("../tools");
|
||||
const {log} = console
|
||||
module.exports = {
|
||||
init: ins => new Promise(resolve => {
|
||||
let actions = {}
|
||||
findFile('./src/websocket', file => {
|
||||
if (!/index\.js/.test(file)) {
|
||||
const item = require(file.replace(/src[\\\/]websocket/, '.'))
|
||||
actions[item.action] = item.execute
|
||||
}
|
||||
}).then(() => {
|
||||
ins.ws('/ws', ws => {
|
||||
log(`${chalk.bgBlue.black(" WEBSOCKET ")} 服务已启动!`)
|
||||
ws.send('您已成功连接到node websocket')
|
||||
ws.onerror = () => ws.close()
|
||||
ws.on('close', () => {
|
||||
log(`${chalk.bgRed.black(" WEBSOCKET ")} 连接已断开!`)
|
||||
clearInterval(heartBeat)
|
||||
})
|
||||
ws.on('message', res => {
|
||||
if (checkJson(res)) {
|
||||
const data = JSON.parse(res)
|
||||
!!data?.action && actions[data.action]?.(ws, data)
|
||||
}
|
||||
})
|
||||
let heartBeat = setInterval(() => ws.send(`heartBeat at ${dayjs().format("YYYY-MM-DD HH:mm:ss")}`), 5000)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
36
tpl/AppEntry.vue
Normal file
36
tpl/AppEntry.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<section class="@appName">
|
||||
<component :is="currentPage" v-bind="$props"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from "./list";
|
||||
import Add from "./add";
|
||||
|
||||
export default {
|
||||
name: "@appName",
|
||||
components: {Add, List},
|
||||
label: "@name",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
currentPage() {
|
||||
let {hash} = this.$route
|
||||
return hash == "#add" ? Add : List
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict.load(@dicts)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.@appName {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
81
tpl/add.vue
Normal file
81
tpl/add.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<section class="add">
|
||||
<ai-detail>
|
||||
<ai-title slot="title" :title="pageTitle" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<el-form ref="AddForm" :model="form" size="small" label-width="120px" :rules="rules">
|
||||
@content
|
||||
</el-form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="back">取消</el-button>
|
||||
<el-button type="primary" @click="submit">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "add",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
isEdit: v => !!v.$route.query.id,
|
||||
pageTitle: v => v.isEdit ? "编辑@name" : "新增@name"
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
rules: {
|
||||
@rules
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDetail() {
|
||||
let {id} = this.$route.query
|
||||
id && this.instance.post("/node/@rightCode/detail", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
back() {
|
||||
this.$router.push({})
|
||||
},
|
||||
submit() {
|
||||
this.$refs.AddForm.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post("/node/@rightCode/addOrUpdate", this.form).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("提交成功!")
|
||||
this.back()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.add {
|
||||
.half {
|
||||
width: 50%;
|
||||
|
||||
& + .half {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
82
tpl/list.vue
Normal file
82
tpl/list.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<section class="list">
|
||||
<ai-list>
|
||||
<ai-title slot="title" title="@name" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
@searchProps
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="搜索" v-model="search.name" clearable
|
||||
@change="page.current=1,getTableData()"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
@btns
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
|
||||
@getList="getTableData" :col-configs="colConfigs" :dict="dict">
|
||||
<el-table-column slot="options" label="操作" fixed="right" align="center" width="300">
|
||||
<template slot-scope="{row}">
|
||||
@tableBtns
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "list",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: {name: ""},
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
tableData: [],
|
||||
colConfigs: @listProps,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTableData() {
|
||||
this.instance.post("/node/@rightCode/list", null, {
|
||||
params: {...this.page, ...this.search}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
handleAdd(id) {
|
||||
this.$router.push({hash: "#add", query: {id}})
|
||||
},
|
||||
handleDelete(ids) {
|
||||
this.$confirm("是否要删除?").then(() => {
|
||||
this.instance.post("/node/@rightCode/delete", null, {
|
||||
params: {ids}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("删除成功")
|
||||
this.getTableData()
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTableData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user