Commit 9c090f1e authored by wuhao's avatar wuhao 🎯

asder

parents
'use strict';
module.exports = {
write: true,
prefix: '^',
plugin: 'autod-egg',
test: [
'test',
'benchmark',
],
dep: [
'egg',
'egg-scripts',
],
devdep: [
'egg-ci',
'egg-bin',
'egg-mock',
'autod',
'autod-egg',
'eslint',
'eslint-config-egg',
],
exclude: [
'./test/fixtures',
'./dist',
],
};
{
"extends": "eslint-config-egg",
"root": true
}
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master
schedule:
- cron: '0 2 * * *'
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
node-version: [16]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout Git Source
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: npm i
- name: Continuous Integration
run: npm run ci
- name: Code Coverage
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
logs/
npm-debug.log
yarn-error.log
node_modules/
package-lock.json
yarn.lock
coverage/
.idea/
run/
.DS_Store
*.sw*
*.un~
typings/
.nyc_output/
.history
app/public
\ No newline at end of file
'use strict';
const path = require('path');
module.exports = {
config: path.join(__dirname, 'database/config.json'),
'migrations-path': path.join(__dirname, 'database/migrations'),
'seeders-path': path.join(__dirname, 'database/seeders'),
'models-path': path.join(__dirname, 'app/model'),
};
\ No newline at end of file
# Webtool_server
#### Description
Eggjs to handle webtool server
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
# webtool_server
Eggjs to handle webtool server
## QuickStart
<!-- add docs here for user -->
see [egg docs][egg] for more detail.
### Development
```bash
$ npm i
$ npm run dev
$ open http://localhost:7001/
```
### Deploy
```bash
$ npm start
$ npm stop
```
### npm scripts
- Use `npm run lint` to check code style.
- Use `npm test` to run unit test.
- Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
[egg]: https://eggjs.org
\ No newline at end of file
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
ctx.body = 'hi, egg';
}
}
module.exports = HomeController;
'use strict';
const Controller = require('../core/base_controller');
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class ItemController extends Controller {
async mutisort() {
const ctx = this.ctx;
const updates = await ctx.service.item.mutiupdate(
ctx.request.body?.sortlist ?? []
);
this.success(updates);
}
async index() {
const ctx = this.ctx;
const query = {
limit: toInt(ctx.query.limit),
offset: toInt(ctx.query.offset),
};
const result = await ctx.model.Item.findAll(query);
this.success(result);
}
async show() {
const ctx = this.ctx;
const result = await ctx.model.Item.findByPk(toInt(ctx.params.id));
this.success(result);
}
async create() {
const ctx = this.ctx;
console.log(ctx.request.body);
if (!ctx.request.body.mission_name || !ctx.request.body.project_id) {
this.fail('请完善必填项!');
return;
}
const item = await ctx.model.Item.create(ctx.request.body);
this.success(item);
}
async update() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const item = await ctx.model.Item.findByPk(id);
if (!item) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await item.update(ctx.request.body);
this.success(item);
}
async destroy() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const item = await ctx.model.Item.findByPk(id);
if (!item) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await item.destroy();
this.success({
data: '已删除',
});
}
}
module.exports = ItemController;
'use strict';
const Controller = require('../core/base_controller');
class LoginController extends Controller {
async index() {
const { ctx, app } = this;
const result = await ctx.service.login.todo(ctx.request.body);
if (result.length === 0) {
this.fail('用户名不存在!');
return;
}
if (result[0].password === ctx.request.body.password) {
// 创建token
const token = app.jwt.sign(result[0], app.config.jwt.secret, {
expiresIn: 60 * 60 * 24, // 设置过期时间
});
// json格式返回token
this.success(token);
} else {
this.fail('密码错误!');
}
// ctx.body = result;
}
}
module.exports = LoginController;
'use strict';
const Controller = require('../core/base_controller');
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class OrgController extends Controller {
async index() {
const ctx = this.ctx;
const query = {
limit: toInt(ctx.query.limit),
offset: toInt(ctx.query.offset),
};
const result = await ctx.model.Org.findAll(query);
this.success(result);
}
async show() {
const ctx = this.ctx;
const result = await ctx.model.Org.findByPk(toInt(ctx.params.id));
this.success(result);
}
async create() {
const ctx = this.ctx;
console.log(ctx.request.body);
if (!ctx.request.body.org_name) {
this.fail('请完善必填项!');
return;
}
const org = await ctx.model.Org.create(ctx.request.body);
await ctx.service.user.update(
{
role_type: ctx.request.body?.org_join_key,
org_id: org.id,
},
this
);
this.success(org);
}
async update() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const org = await ctx.model.Org.findByPk(id);
if (!org) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await org.update(ctx.request.body);
this.success(org);
}
async destroy() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const org = await ctx.model.Org.findByPk(id);
if (!org) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await org.destroy();
this.success({
data: '已删除',
});
}
}
module.exports = OrgController;
'use strict';
const Controller = require('../core/base_controller');
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class ProjectController extends Controller {
async index() {
const { ctx } = this;
const { Op } = this.app.Sequelize;
const user = await ctx.service.user.getcurrentuser();
// 查询条件
const query = user?.org_id
? [
{
project_user_id: user?.id,
},
{
org_id: user?.org_id,
},
]
: [
{
project_user_id: user?.id,
},
];
let result = await ctx.model.Project.findAll({
where: {
[Op.or]: query,
},
});
let alluser = await ctx.model.User.findAll({
attributes: {
exclude: [ 'password' ],
},
});
let allsteps = await ctx.model.Step.findAll();
let allitems = await ctx.model.Item.findAll();
alluser = alluser.map(it => it?.dataValues);
result = result.map(it => it?.dataValues);
allsteps = allsteps.map(it => it?.dataValues);
allitems = allitems.map(it => it?.dataValues);
// 小组成员可见过滤
const datafliter = result
?.filter(it => {
return (
it.user_list.indexOf(user?.id) !== -1 ||
it?.project_user_id === user?.id
);
})
?.map(it => {
it.user_info_list = alluser?.filter(
item =>
it.user_list.indexOf(item.id) !== -1 ||
it?.project_user_id === item.id
);
let allinitem = [];
const steps = allsteps
?.filter(item => item.project_id === it.id)
.map(item => {
// 过滤当前项目下的所有任务;
const thisitems = allitems.filter(
itemz => itemz.project_id === it.id && itemz.step_id === item.id
);
allinitem.push(thisitems);
return {
...item,
items: thisitems,
};
});
allinitem = allinitem.flat();
console.log(allinitem);
const stastic = [
{
status: '0',
statusName: '未开始',
num: allinitem.filter(it => it.status === '0'),
},
{
status: '1',
statusName: '进行中',
num: allinitem.filter(it => it.status === '1'),
},
{
status: '2',
statusName: '已完成',
num: allinitem.filter(it => it.status === '2'),
},
];
const total = allinitem.length;
return { ...it, steps, stastic, total };
});
this.success(datafliter);
}
async show() {
const ctx = this.ctx;
const { status } = ctx.query;
const result = await ctx.model.Project.findByPk(toInt(ctx.params.id));
const user_info_list = await ctx.model.User.findAll({
where: {
id: result?.dataValues?.user_list,
},
attributes: {
exclude: [ 'password' ],
},
});
let steps = await ctx.service.step.getbyproject_id(ctx.params.id);
const items = await ctx.service.item.getbyproject_id(ctx.params.id , status);
steps = steps.map(it => {
return {
...it?.dataValues,
items: items ? items.filter(item => item.step_id === it?.id) : [],
};
});
this.success({
...result?.dataValues,
user_info_list,
steps,
});
}
async create() {
const ctx = this.ctx;
if (!ctx.request.body.project_name) {
this.fail('请完善必填项!');
return;
}
const user = await ctx.service.user.getcurrentuser();
const user_info_list = await ctx.model.User.findAll({
where: {
id: ctx.request.body.user_list,
},
attributes: {
exclude: [ 'password' ],
},
});
const project = await ctx.model.Project.create({
...ctx.request.body,
project_user_id: user?.id,
org_id: user?.org_id,
user_info_list,
});
if (ctx.request.body.steps?.length > 0) {
await ctx.service.step.muticreate(ctx.request.body.steps, project?.id);
}
this.success(project);
}
async update() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const project = await ctx.model.Project.findByPk(id);
if (!project) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await project.update(ctx.request.body);
this.success(project);
}
async destroy() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const project = await ctx.model.Project.findByPk(id);
if (!project) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await project.destroy();
this.success({
data: '已删除',
});
}
}
module.exports = ProjectController;
'use strict';
const Controller = require('../core/base_controller');
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class StepController extends Controller {
async index() {
const ctx = this.ctx;
const query = {
limit: toInt(ctx.query.limit),
offset: toInt(ctx.query.offset),
};
const result = await ctx.model.Step.findAll(query);
this.success(result);
}
async show() {
const ctx = this.ctx;
const result = await ctx.model.Step.findByPk(toInt(ctx.params.id));
this.success(result);
}
async create() {
const ctx = this.ctx;
console.log(ctx.request.body);
if (!ctx.request.body.name) {
this.fail('请完善必填项!');
return;
}
const step = await ctx.model.Step.create(ctx.request.body);
this.success(step);
}
async update() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const step = await ctx.model.Step.findByPk(id);
if (!step) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await step.update(ctx.request.body);
this.success(step);
}
async destroy() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const step = await ctx.model.Step.findByPk(id);
if (!step) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await step.destroy();
this.success({
data: '已删除',
});
}
}
module.exports = StepController;
const fs = require('fs');
const path = require('path');
const Controller = require('egg').Controller;
class UploadController extends Controller {
async index() {
const { ctx } = this;
const file = ctx.request.files[0];
const fileinfo = fs.readFileSync(file.filepath);
const arr = file.filename.split('.');
const filename = arr[0] + new Date().getTime() + '.' + arr[arr.length - 1];
const target = path.join('app/public/uploads', filename);
try {
await fs.writeFileSync(target, fileinfo);
} catch (error) {
throw error;
} finally {
await fs.promises.unlink(file.filepath, err => {
if (err) {
throw err;
}
});
}
ctx.body = {
url: 'http://' + ctx.host + `/public/uploads/${filename}`,
};
}
}
module.exports = UploadController;
'use strict';
const Controller = require('../core/base_controller');
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class UserController extends Controller {
// 获取用户信息
async getUserInfo() {
const { ctx } = this;
try {
const res = await ctx.service.user.getcurrentuser();
this.success(res);
} catch (error) {
this.fail('获取失败');
}
}
// 绑定组织
async bind() {
const { ctx } = this;
try {
const isinorg = await ctx.model.Org.findOne({
where: {
org_join_key: ctx.request.body.org_join_key,
},
});
if (isinorg) {
await ctx.service.user.update(
{
org_id: isinorg.dataValues.id,
role_type: isinorg.dataValues?.org_join_key,
},
this
);
} else {
this.fail('邀请码不存在');
}
} catch (error) {
this.fail('获取失败');
}
}
async index() {
const ctx = this.ctx;
const user = await ctx.service.user.getcurrentuser();
const query = {
org_id: user?.org_id,
};
const result = await ctx.model.User.findAll({
where: query,
attributes: {
exclude: [ 'password' ],
},
});
this.success(result);
}
async show() {
const ctx = this.ctx;
const result = await ctx.model.User.findByPk(toInt(ctx.params.id));
this.success(result);
}
async create() {
const ctx = this.ctx;
if (!ctx.request.body.user_name || !ctx.request.body.password) {
this.fail('请完善必填项!');
return;
}
const isaddon = await ctx.model.User.findOne({
where: {
user_name: ctx.request.body.user_name,
},
});
if (isaddon) {
this.fail('用户名已存在!');
} else {
const user = await ctx.model.User.create(ctx.request.body);
this.success(user);
}
}
async update() {
const ctx = this.ctx;
await ctx.service.user.update(ctx.request.body, this);
}
async destroy() {
const ctx = this.ctx;
const id = toInt(ctx.params.id);
const user = await ctx.model.User.findByPk(id);
if (!user) {
ctx.status = 404;
ctx.body = {
code: 1,
success: false,
msg: '库里没有该条数据',
};
return;
}
await user.destroy();
this.success({
data: '已删除',
});
}
}
module.exports = UserController;
// app/core/base_controller.js
const { Controller } = require('egg');
class BaseController extends Controller {
get user() {
return this.ctx.session.user;
}
success(data) {
this.ctx.status = 200;
this.ctx.body = {
code: 0,
success: true,
data,
};
}
fail(msg) {
this.ctx.status = 200;
this.ctx.body = {
code: 1,
success: false,
msg,
};
}
notFound(msg) {
msg = msg || 'not found';
this.ctx.throw(404, msg);
}
}
module.exports = BaseController;
module.exports = () => {
return async function errorHandler(ctx, next) {
try {
await next();
} catch (err) {
// 所有的异常都在 app 上触发一个 error 事件,框架会记录一条错误日志
ctx.app.emit('error', err, ctx);
const status = err.status || 500;
// 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
const error =
status === 500 && ctx.app.config.env === 'prod'
? 'Internal Server Error'
: err.message;
// 从 error 对象上读出各个属性,设置到响应中
ctx.body = { error };
if (status === 422) {
ctx.body.detail = err.errors;
}
ctx.status = status;
}
};
};
module.exports = options => {
return async function jwtErr(ctx, next) {
const token = ctx.request.header.authorization;
if (token) {
try {
// 解码token
ctx.app.jwt.verify(token, options.secret);
await next();
} catch (error) {
ctx.status = -1;
ctx.body = {
code: -1,
message: error.message,
};
return;
}
} else {
ctx.body = {
code: -1,
message: '没有token',
};
return;
}
};
};
/* eslint-disable no-unused-vars */
'use strict';
module.exports = app => {
const { STRING, INTEGER, ENUM, DATE, TEXT } = app.Sequelize;
const Item = app.model.define(
'item',
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
project_id: {
type: INTEGER,
allowNull: true,
comment: '所属项目',
unique: true,
},
step_id: {
type: INTEGER,
allowNull: true,
comment: '所属步骤',
unique: true,
},
userid: {
type: INTEGER,
allowNull: true,
comment: '开发负责人',
unique: true,
},
mission_name: {
type: STRING(255),
allowNull: true,
comment: '任务名称',
unique: true,
},
deadline: {
type: DATE,
allowNull: true,
comment: '截止日期',
unique: true,
},
status: {
type: ENUM('0', '1', '2', '3', '4', '5'),
allowNull: false,
defaultValue: '0',
comment: '状态',
unique: true,
},
other: {
type: STRING(255),
allowNull: true,
comment: '冗余字段',
unique: true,
},
sort: {
type: INTEGER,
allowNull: true,
comment: '排序',
unique: true,
},
remark: {
type: TEXT,
allowNull: true,
comment: '备注',
unique: true,
},
created_at: DATE,
updated_at: DATE,
},
{
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
}
);
return Item;
};
// freezeTableName: true, 使用自定义表名
// // 实例对应的表名
// tableName: 'user',
// // 如果需要sequelize帮你维护createdAt,updatedAt和deletedAt必须先启用timestamps功能
// // 将createdAt对应到数据库的created_at字段
// createdAt: 'created_at',
// // 将updatedAt对应到数据库的updated_at字段
// updatedAt: 'updated_at',
// //And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
// deletedAt: false, //'deleted_at',
// //删除数据时不删除数据,而是更新deleteAt字段 如果需要设置为true,则上面的deleteAt字段不能为false,也就是说必须启用
// paranoid: false
/* eslint-disable no-unused-vars */
'use strict';
module.exports = app => {
const { STRING, INTEGER, ENUM, DATE } = app.Sequelize;
const Org = app.model.define(
'org',
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
org_name: {
type: STRING(255),
allowNull: true,
comment: '组织名',
unique: true,
},
org_users: {
type: STRING(512),
allowNull: true,
comment: '组织成员',
unique: true,
},
org_join_key: {
type: STRING(255),
allowNull: true,
comment: '组织邀请码',
unique: true,
},
org_projects: {
type: STRING(512),
allowNull: true,
comment: '组织项目',
unique: true,
},
otherkey: {
type: STRING(512),
allowNull: true,
comment: '拓展字段1',
unique: true,
},
otherkeys: {
type: STRING(255),
allowNull: true,
comment: '拓展字段2',
unique: true,
},
otherkeyc: {
type: STRING(255),
allowNull: true,
comment: '拓展字段3',
unique: true,
},
created_at: DATE,
updated_at: DATE,
},
{
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
}
);
return Org;
};
// freezeTableName: true, 使用自定义表名
// // 实例对应的表名
// tableName: 'user',
// // 如果需要sequelize帮你维护createdAt,updatedAt和deletedAt必须先启用timestamps功能
// // 将createdAt对应到数据库的created_at字段
// createdAt: 'created_at',
// // 将updatedAt对应到数据库的updated_at字段
// updatedAt: 'updated_at',
// //And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
// deletedAt: false, //'deleted_at',
// //删除数据时不删除数据,而是更新deleteAt字段 如果需要设置为true,则上面的deleteAt字段不能为false,也就是说必须启用
// paranoid: false
/* eslint-disable no-unused-vars */
'use strict';
module.exports = app => {
const { STRING, INTEGER, JSON, DATE } = app.Sequelize;
const Project = app.model.define(
'project',
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
project_name: {
type: STRING(255),
allowNull: true,
comment: '项目名',
unique: true,
},
project_address: {
type: STRING(255),
allowNull: true,
comment: '项目地址',
unique: true,
},
project_user_id: {
type: INTEGER,
allowNull: true,
comment: '项目创建人',
unique: true,
},
deadline: {
type: DATE,
allowNull: true,
comment: '截止日期',
unique: true,
},
logo_url: {
type: STRING(255),
allowNull: true,
comment: '项目logo',
unique: true,
},
org_id: {
type: INTEGER,
allowNull: true,
comment: '所属组织',
unique: true,
},
proxy_string: {
type: STRING(255),
allowNull: true,
comment: '代理字符',
unique: true,
},
pro_env: {
type: STRING(1024),
allowNull: true,
comment: '发布生产环境',
unique: true,
},
dev_env: {
type: STRING(1024),
allowNull: true,
comment: '发布开发环境',
unique: true,
},
test_env: {
type: STRING(1024),
allowNull: true,
comment: '发布测试环境',
unique: true,
},
output_path: {
type: STRING(255),
allowNull: true,
comment: '打包文件夹名称',
unique: true,
},
user_list: {
type: JSON,
allowNull: false,
defaultValue: [],
comment: '用户idlist',
unique: true,
},
user_info_list: {
type: JSON,
allowNull: false,
defaultValue: [],
comment: '用户信息list',
unique: true,
},
created_at: DATE,
updated_at: DATE,
},
{
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
}
);
return Project;
};
// freezeTableName: true, 使用自定义表名
// // 实例对应的表名
// tableName: 'user',
// // 如果需要sequelize帮你维护createdAt,updatedAt和deletedAt必须先启用timestamps功能
// // 将createdAt对应到数据库的created_at字段
// createdAt: 'created_at',
// // 将updatedAt对应到数据库的updated_at字段
// updatedAt: 'updated_at',
// //And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
// deletedAt: false, //'deleted_at',
// //删除数据时不删除数据,而是更新deleteAt字段 如果需要设置为true,则上面的deleteAt字段不能为false,也就是说必须启用
// paranoid: false
/* eslint-disable no-unused-vars */
'use strict';
module.exports = app => {
const { STRING, INTEGER, ENUM, DATE } = app.Sequelize;
const Step = app.model.define(
'step',
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
project_id: {
type: INTEGER,
allowNull: true,
comment: '所属项目',
unique: true,
},
name: {
type: STRING(255),
allowNull: true,
comment: '步骤名称',
unique: true,
},
other: {
type: STRING(255),
allowNull: true,
comment: '冗余字段',
unique: true,
},
sort: {
type: INTEGER,
allowNull: true,
comment: '排序',
unique: true,
},
created_at: DATE,
updated_at: DATE,
},
{
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
}
);
return Step;
};
// freezeTableName: true, 使用自定义表名
// // 实例对应的表名
// tableName: 'user',
// // 如果需要sequelize帮你维护createdAt,updatedAt和deletedAt必须先启用timestamps功能
// // 将createdAt对应到数据库的created_at字段
// createdAt: 'created_at',
// // 将updatedAt对应到数据库的updated_at字段
// updatedAt: 'updated_at',
// //And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
// deletedAt: false, //'deleted_at',
// //删除数据时不删除数据,而是更新deleteAt字段 如果需要设置为true,则上面的deleteAt字段不能为false,也就是说必须启用
// paranoid: false
/* eslint-disable no-unused-vars */
'use strict';
module.exports = app => {
const { STRING, INTEGER, ENUM } = app.Sequelize;
const User = app.model.define(
'user',
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '姓名',
unique: true,
},
user_name: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '用户名',
unique: true,
},
password: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '密码',
},
role_type: {
type: STRING(255),
allowNull: false,
defaultValue: '',
comment: '用户角色',
},
head_url: {
type: STRING(255),
allowNull: false,
defaultValue: '',
comment: '头像地址',
},
org_id: {
type: INTEGER,
allowNull: true,
comment: '组织id',
},
age: INTEGER,
},
{
timestamps: false,
}
);
return User;
};
// freezeTableName: true, 使用自定义表名
// // 实例对应的表名
// tableName: 'user',
// // 如果需要sequelize帮你维护createdAt,updatedAt和deletedAt必须先启用timestamps功能
// // 将createdAt对应到数据库的created_at字段
// createdAt: 'created_at',
// // 将updatedAt对应到数据库的updated_at字段
// updatedAt: 'updated_at',
// //And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
// deletedAt: false, //'deleted_at',
// //删除数据时不删除数据,而是更新deleteAt字段 如果需要设置为true,则上面的deleteAt字段不能为false,也就是说必须启用
// paranoid: false
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller, middleware } = app;
const jwtErr = middleware.jwtError(app.config.jwt);
router.get('/', jwtErr, controller.home.index);
router.post('/webtool/upload', jwtErr, controller.upload.index);
router.post('/webtool/login', controller.login.index);
router.get('/webtool/user', jwtErr, controller.user.getUserInfo);// 获取用户信息
router.post('/webtool/userbind', jwtErr, controller.user.bind);// 绑定用户组织
router.resources('user', '/webtool/v1/user', controller.user);
router.resources('project', '/webtool/v1/project', jwtErr, controller.project);
router.resources('org', '/webtool/v1/org', jwtErr, controller.org);
router.resources('step', '/webtool/v1/step', jwtErr, controller.step);
router.resources('item', '/webtool/v1/item', jwtErr, controller.item);
router.post('/webtool/v1/mutisort', jwtErr, controller.item.mutisort);// 绑定用户组织
};
// app/service/user.js
const Service = require('egg').Service;
class ItemService extends Service {
async mutiupdate(itemarr) {
const { ctx, app } = this;
const { Op } = app.Sequelize;
const itemarrs = itemarr?.map((it, i) => ({
...it,
sort: i,
}));
let item;
try {
item = await ctx.model.Item.bulkCreate(itemarrs, {
updateOnDuplicate: [ 'step_id', 'sort' ],
});
} catch (error) {
item = error;
}
return item;
}
async getbyproject_id(project_id, status) {
const { ctx } = this;
const where =
status == '-1'
? {
project_id,
}
: {
project_id,
status,
};
let item;
try {
item = await ctx.model.Item.findAll({
where,
});
} catch (error) {
item = error;
}
return item;
}
}
module.exports = ItemService;
// app/service/topics.js
const Service = require('egg').Service;
class LoginService extends Service {
constructor(ctx) {
super(ctx);
this.state = '';
}
async todo(params) {
const user_name = params?.user_name;
const result = await this.ctx.model.User.findAll({
where: {
user_name,
},
raw: true,
});
return result;
}
}
module.exports = LoginService;
// app/service/user.js
const Service = require('egg').Service;
class StepService extends Service {
async muticreate(steparr, project_id) {
const { ctx } = this;
const steparrs = steparr?.map((it, i) => ({
...it,
project_id,
sort: i,
}));
let step;
try {
step = await ctx.model.Step.bulkCreate(steparrs);
} catch (error) {
step = error;
}
return step;
}
async getbyproject_id(project_id) {
const { ctx } = this;
const where = {
project_id,
};
let step;
try {
step = await ctx.model.Step.findAll({
where,
});
} catch (error) {
step = error;
}
return step;
}
}
module.exports = StepService;
// app/service/user.js
const Service = require('egg').Service;
function toInt(str) {
if (typeof str === 'number') return str;
if (!str) return str;
return parseInt(str, 10) || 0;
}
class UserService extends Service {
async update(body, _this) {
const { ctx, app } = this;
const token = ctx.request.header.authorization;
const decode = await app.jwt.verify(token, app.config.jwt.secret);
const user = await ctx.model.User.findByPk(decode?.id);
if (!user) {
ctx.status = 404;
_this.fail('库里没有该条数据');
return;
}
await user.update(body);
_this.success(user);
return user;
}
async getcurrentuser() {
const { ctx, app } = this;
const token = ctx.request.header.authorization;
const decode = await app.jwt.verify(token, app.config.jwt.secret);
const result = await ctx.model.User.findByPk(toInt(decode.id));
let orginfo = {};
if (result?.org_id) {
orginfo = await ctx.model.Org.findByPk(toInt(result?.org_id));
}
return { ...orginfo.dataValues, ...result.dataValues };
}
}
module.exports = UserService;
/* eslint-disable no-unused-vars */
/* eslint valid-jsdoc: "off" */
'use strict';
/**
* @param {Egg.EggAppInfo} appInfo app info
*/
module.exports = appInfo => {
/**
* built-in config
* @type {Egg.EggAppConfig}
**/
const config = (exports = {});
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1661345954202_4937';
// add your middleware config here
config.middleware = [ 'errorHandler' ];
config.errorHandler = {
match: '/webtool',
};
// 解析formdata
config.multipart = {
mode: 'file',
};
// onerror
config.onerror = {
all(_err, ctx) {
// 在此处定义针对所有响应类型的错误处理方法
// 注意,定义了 config.all 之后,其他错误处理方法不会再生效
ctx.body = 'error';
ctx.status = 500;
},
html(_err, ctx) {
// html hander
ctx.body = '<h3>error</h3>';
ctx.status = 500;
},
json(_err, ctx) {
// json hander
ctx.body = { message: 'error' };
ctx.status = 500;
},
jsonp(_err, _ctx) {
// 一般来说,不需要特殊针对 jsonp 进行错误定义,jsonp 的错误处理会自动调用 json 错误处理,并包装成 jsonp 的响应格式
},
};
// add your user config here
const userConfig = {
// myAppName: 'egg',
};
// cros允许请求
config.security = {
csrf: {
enable: false,
},
domainWhiteList: [ '*' ], // 允许访问域名的白名单,*表示都能访问
};
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
credentials: true,
};
// jwt鉴权
config.jwt = {
secret: '1148547900',
};
// sequelize 【dialect】 support: mysql, mariadb, postgres, mssql
config.sequelize = {
dialect: 'mysql',
database: 'tasks', // webtool_database
host: '192.168.40.68', // 192.168.40.6 124.221.146.79 192.168.40.68
port: 3306,
username: 'root',
password: '123456', // nangao2019-
};
return {
...config,
...userConfig,
};
};
'use strict';
// sequelize
exports.sequelize = {
enable: true,
package: 'egg-sequelize',
};
// cors
exports.cors = {
enable: true,
package: 'egg-cors',
};
// resful_Api
exports.validate = {
enable: true,
package: 'egg-validate',
};
// jwt
exports.jwt = {
enable: true,
package: 'egg-jwt',
};
{
"development": {
"dialect": "mysql",
"database": "tasks",
"host": "192.168.40.68",
"port": 3306,
"username": "root",
"password": "123456"
},
"test": {
"dialect": "mysql",
"database": "tasks",
"host": "192.168.40.68",
"port": 3306,
"username": "root",
"password": "123456"
},
"production": {
"dialect": "mysql",
"database": "tasks",
"host": "192.168.40.68",
"port": 3306,
"username": "root",
"password": "123456"
}
}
\ No newline at end of file
'use strict';
module.exports = {
// 在执行数据库升级时调用的函数,创建 users 表
up: async (queryInterface, Sequelize) => {
const { INTEGER, STRING } = Sequelize;
await queryInterface.createTable('users', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: STRING(30),
user_name: STRING(30),
password: STRING(30),
role_type: STRING(255),
head_url: STRING(255),
org_id: INTEGER,
age: INTEGER,
});
},
// 在执行数据库降级时调用的函数,删除 users 表
down: async queryInterface => {
await queryInterface.dropTable('users');
},
};
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
const { INTEGER, DATE, STRING, JSON } = Sequelize;
await queryInterface.createTable('projects', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
project_name: STRING(255),
project_address: STRING(255),
project_user_id: INTEGER,
deadline: DATE,
logo_url: STRING(255),
org_id: INTEGER,
proxy_string: STRING(255),
pro_env: STRING(512),
dev_env: STRING(512),
test_env: STRING(512),
output_path: STRING(255),
user_list: JSON,
user_info_list: JSON,
created_at: DATE,
updated_at: DATE,
});
},
async down(queryInterface) {
await queryInterface.dropTable('projects');
},
};
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
const { INTEGER, DATE, STRING } = Sequelize;
await queryInterface.createTable('orgs', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
org_name: STRING(255),
org_users: STRING(512),
org_join_key: STRING(255),
org_projects: STRING(512),
otherkey: STRING(512),
otherkeys: STRING(255),
otherkeyc: STRING(255),
created_at: DATE,
updated_at: DATE,
});
},
async down(queryInterface) {
await queryInterface.dropTable('orgs');
},
};
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
const { INTEGER, STRING, DATE } = Sequelize;
await queryInterface.createTable('steps', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
project_id: INTEGER,
name: STRING(255),
other: STRING(255),
sort: INTEGER,
created_at: DATE,
updated_at: DATE,
});
},
async down(queryInterface) {
await queryInterface.dropTable('steps');
},
};
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
const { INTEGER, STRING, DATE, ENUM, TEXT } = Sequelize;
await queryInterface.createTable('items', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
project_id: INTEGER,
step_id: INTEGER,
mission_name: STRING(255),
status: ENUM('0', '1', '2', '3', '4', '5'),
deadline: DATE,
other: STRING(255),
remark: TEXT,
userid: INTEGER,
sort: INTEGER,
created_at: DATE,
updated_at: DATE,
});
},
async down(queryInterface) {
await queryInterface.dropTable('items');
},
};
{
"include": [
"**/*"
]
}
\ No newline at end of file
{
"name": "webtool_server",
"version": "1.0.0",
"description": "Eggjs to handle webtool server",
"private": true,
"egg": {
"declarations": true
},
"dependencies": {
"egg": "^2",
"egg-cors": "^2.2.3",
"egg-jwt": "^3.1.7",
"egg-scripts": "^2",
"egg-sequelize": "^6.0.0",
"egg-validate": "^2.0.2",
"mysql2": "^2.3.3"
},
"devDependencies": {
"autod": "^3",
"autod-egg": "^1",
"egg-bin": "^4",
"egg-ci": "^2",
"egg-mock": "^4",
"eslint": "^8",
"eslint-config-egg": "^12",
"sequelize-cli": "^6.4.1"
},
"engines": {
"node": ">=16.0.0"
},
"scripts": {
"start": "egg-scripts start --daemon --title=egg-server-webtool_server",
"stop": "egg-scripts stop --title=egg-server-webtool_server",
"dev": "egg-bin dev",
"debug": "egg-bin debug",
"test": "npm run lint -- --fix && npm run test-local",
"test-local": "egg-bin test",
"cov": "egg-bin cov",
"lint": "eslint .",
"ci": "npm run lint && npm run cov",
"autod": "autod"
},
"ci": {
"version": "16",
"type": "github"
},
"repository": {
"type": "git",
"url": ""
},
"author": "wuhao",
"license": "MIT"
}
'use strict';
const { app, assert } = require('egg-mock/bootstrap');
describe('test/app/controller/home.test.js', () => {
it('should assert', async () => {
const pkg = require('../../../package.json');
assert(app.config.keys.startsWith(pkg.name));
// const ctx = app.mockContext({});
// yield ctx.service.xx();
});
it('should GET /', async () => {
return app.httpRequest()
.get('/')
.expect('hi, egg')
.expect(200);
});
});
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