egg + vue + mongodb практика разработки онлайн-платформы управления документами - чернильный документ

Vue.js

предисловие

Команда столкнется с потребностями онлайн-управления документами, включая техническую документацию, интерфейсные документы, документы Excel, размещение прототипов продуктов и т. д., и не нашла подходящего проекта с открытым исходным кодом для удовлетворения потребностей, поэтому система управления документами ( реализация Это не сложно, туториал просто предлагает идеи, а не лучшие практики)

Github: портал
Демонстрационный адрес:портал

список функций

  • войти Зарегистрироваться
  • Таблица |Список документов
  • Предварительный просмотр редактирования документа (поддержка: md, excel, размещение прототипов продуктов в формате html)
  • Совместное редактирование
  • Настройки прав доступа
  • Управление командой
  • Нравится Избранное
  • Управление шаблонами
  • История просмотров
  • корзина
  • Чтение формы папки (документация по интерфейсу)
  • Изменить версию истории

Предварительный просмотр интерфейса системы

подготовиться перед чтением

1. Понимание разработки стека технологий vue
2. Понять коа
3. Поймите яйца
4. Понимание монгодб

стек технологий

внешний интерфейс:
vue: Модульная разработка незаменима для angular, react и vue, и здесь выбран vue.
vuex: государственное управление
sass: прекомпилятор css.
element-ui: Не стройте колеса, конечно, есть готовые отличные библиотеки компонентов vue.

Сервер:
egg.js: Фреймворк уровня предприятия, разработка приложений осуществляется в соответствии с унифицированным набором соглашений, и разработка очень эффективна.
mongodb: база данных на основе распределенного хранилища файлов, которая является более гибкой.
egg-alinode: бесплатный мониторинг производительности сервера nodejs, предоставляемый Ali.

Инженерное сооружение

Здесь мы управляем интерфейсными и внутренними проектами в одном каталоге, используем шаблоны egg и vue-cli3 для создания проектов инициализации, копируем и объединяем их в один и тот же каталог и не забываем объединять содержимое package.json. (Проект создания скаффолдинга представлен не будет, просто следуйте документации), после слияния измените каталог src проекта vue на web следующим образом:

···
·
|-- app					// egg 初始化app目录
|-- config				// egg 初始化app目录
|-- public				// vue 静态资源目录
|-- web					// 原 src 目录,改成 web 用作前端项目目录
·
···

В этом случае нам нужно внести некоторые коррективы в нашу конфигурацию упаковки vue webpack.Во-первых, изменить каталог, в котором исходная компиляция указывает на src на web.Во-вторых, чтобы npm run build нормально скомпилировал веб, нам также нужно добавить еще одну компиляцию для babel-loader.content:

  • Добавьте vue.config.js в корневой каталог, цель состоит в том, чтобы преобразовать запись проекта vue, изменить ее на: web/main.js

        module.exports = {    
          pages: {        
            index: {            
              entry: "web/main.js"        
            }    
          }
        }
    
  • babel-loader может нормально компилировать веб-каталог, добавьте следующую конфигурацию в vue.config.js

    // 扩展 webpack 配置
    chainWebpack: config => {
    	config.module
    	.rule('js')
    	.include.add(/web/).end()
    	.use('babel')
    	.loader('babel-loader')
    	.tap(options => {
    	// 修改它的选项...
    	return options
    	})
    }
    
  • package.json добавляет внешние команды упаковки проекта.

"dev-web": "vue-cli-service serve",
"build-web": "vue-cli-service build",

Инициализация back-end проекта завершена, и начинается front-end разработкаnpm run dev-webНачалась бэкенд-разработкаnpm run dev

Структура каталогов проекта

|-- app					--------服务器端项目代码
    |--controller				--------用于解析用户的输入,处理后返回相应的结果
    |--extend					--------框架的扩展
    |--middleware				--------编写中间件
    |--model					--------Schema数据模型
    |--public					--------用于放置静态资源
    |--service					--------用于编写业务逻辑层
    |--router.js				--------用于配置 URL 路由规则
|-- config					--------egg 配置文件
    |--config.default.js			--------默认配置
    |--config.local.js				--------开发环境配置
    |--config.prod.js				--------生产环境配置
    |--plugin.js					--------配置需要加载的插件
|-- web						--------前端项目界面代码
    |--common					--------前端界面对应静态资源
    |--components				--------组件
    |--config					--------配置文件
    |--filter					--------过滤器
    |--pages					--------页面
    |--router					--------路由配置
    |--store					--------vuex状态管理
    |--service					--------axios封装
    |--App.vue					--------App
    |--main.js					--------入口文件
    |--permission.js			--------权限控制
|-- docs					--------预留编写项目文档目录
|-- vue.config.js			--------vue webpack配置文件
|-- package.json
...
...

После завершения инициализации каталога проекта сначала настройте некоторые методы промежуточного программного обеспечения и расширения в mongodb глобально, чтобы подготовиться к разработке интерфейса.

конфигурация mongodb

1. Установите модуль мангуста

npm install egg-mongoose --save

2. Настройте файл конфигурации

// config/plugin.js
exports.mongoose = {
    enable: true,
    package: 'egg-mongoose',
};

// config/config.default.js
config.mongoose = {
    url: 'mongodb://127.0.0.1:27017/inkwash',
    options: {},
};

Глобальное промежуточное ПО и конфигурация расширений

1. При разработке внутреннего интерфейса нам нужен унифицированный формат возврата.Мы можем расширить функцию возвращаемых данных под объектом контекста для унифицированной обработки данных ответа интерфейса.

Создайте новую папку в приложении и создайте новый context.js

// app/extend/context.js
module.exports = {
	/**
	 * 返回客户端的内容
	 * @param status // 接口是否成功
	 * @param body // 返回数据
	 * @param msg // 返回信息提示
	 * @param code // 返回状态码
	 */
	returnBody (status = true, body = {}, msg = 'success', code = 200) {
		this.status = code;
		this.body = {
			status: status,
			body: body,
			msg,
			code: code
		}
	}
}

// передачаconst { ctx } = this; ctx.returnBody(true, {}, "成功");

2. Добавьте промежуточное ПО для унифицированной обработки ошибок. Создайте новую папку промежуточного программного обеспечения в папке приложения, создайте новый файл error_handler.js и настройте глобальную конфигурацию промежуточного программного обеспечения configfig.

// app/middleware/error_handler.js
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' ? '网络错误' : err.message;

			ctx.body = {
				msg: error,
				status: false,
				body: {},
				code: status
			};
		}
	};
};

// app/middleware/error_handler.js
// config/config.default.js 配置全局中间件
config.middleware = [ 'errorHandler'];

jwt аутентификация аутентификация входа

1. Установите пакет генерации и проверки токена egg-jwt.

npm install egg-jwt --save

2. После завершения установки настройте его в config/plugin.js в корневом каталоге, например:

'use strict';

/** @type Egg.EggPlugin */
module.exports = {
	jwt: {
		enable: true,
		package: "egg-jwt"
	},
  mongoose: {
    enable: true,
    package: 'egg-mongoose',
  }
};

3. Далее продолжаем настройку в config/config.default.js:

config.jwt = {
  secret: "123456"//自定义 token 的加密条件字符串
};

4. Расширьте две функции в контексте, getToken и checkToken используются для создания токена и проверки токена.

// app/extend/context.js
async getToken(data) {
	return await this.app.jwt.sign(data, this.app.config.jwt.secret, {expiresIn: 30* 24 * 60 * 60 + 's'});
},
async checkToken(token) {
	return await this.app.jwt.verify(token, this.app.config.jwt.secret)
}

5. Напишите промежуточное ПО для реализации перехвата проверки входа Создайте новый auth.js в папке app/middleware.

// app/middleware/auth.js
module.exports = () => {
	return async function(ctx, next) {
		let token = '';
		if (
			ctx.headers.authorization && ctx.headers.authorization.split(' ')[0] === 'Bearer'
		) {
			token = ctx.headers.authorization.split(' ')[1];
		} else if (ctx.query.accesstoken) {
			token = ctx.query.accesstoken;
		} else if (ctx.request.body.accesstoken) {
			token = ctx.request.body.accesstoken;
		}
		let user;
		try{
			user = await ctx.checkToken(token);
		}catch (e) {
			ctx.returnBody(false,{}, 'Token 无效,请重新登录', 401);
		}
		if (!user) {
			ctx.returnBody(false,{}, 'Token 无效,请重新登录', 401);
			return;
		}
		ctx.request.user = user;
		await next();
	};
};

Что ж, после того, как вышеуказанная конфигурация будет завершена, начнутся следующие операции, связанные с основной функцией регистрации.

  • Сначала я создаю маршрут доступа в app/router.js в корневом каталоге:
import { Application } from 'egg';

export default (app: Application) => {
  const { controller, router, jwt } = app;
  //正常路由
  router.post('/auth/register', controller.auth.register);
  
  // 只有在需要验证 token 的路由上添加jwt
  router.post('/user/infor',jwt, controller.user.infor); 
};

  • Затем я приступаю к написанию своего контроллера и записываю содержимое в app/controller/home.ts в корневом каталоге: Здесь используются два общих метода, которые мы расширяем в app/extend/context.js.
    1. Через ctx.getToken (объект объекта информации о пользователе) информация о пользователе генерируется jwt, и токен возвращается во внешний интерфейс.
    2. Возврат данных через ctx.returnBody
// app/controller/auth.js
const Controller = require('egg').Controller
class AuthController extends Controller {
	async login() {
		//... 略
	}
	async register() {
		const { ctx, service } = this;
		const { username, password, email } = ctx.request.body
		let userData = await ctx.service.user.createUser(username, password, email);
		userData = userData.toObject();
		let userDataStr = JSON.parse(JSON.stringify(userData));
		// 生成token
		let token =await ctx.getToken(userDataStr);
		ctx.returnBody(true, {access_token: token, userInfo: userData}, "注册成功!")
	}
}

module.exports = AuthController;

  • При выполнении внешнего запроса вам необходимо разорвать авторизацию с помощью слова аутентификации по умолчанию в заголовках, например:
axios({
 method: 'get',
  url: 'http://127.0.0.1:7001/user/info',
  headers:{
      // 切记 token 不要直接发送,要在前面加上 Bearer 字符串和一个空格
    'Authorization':`Bearer ${token}`
  }
})
  • Интерфейс получает зашифрованную информацию от toen
  1. Расширьте метод getUser в app/extend/context.js, чтобы получить информацию о шифровании токена.
// app/extend/context.js
// 获取用户信息
	async getUserData() {
		var token = this.headers.authorization ? this.headers.authorization : '';
		token = token.substring(7) //把Bearer 截取掉,解析的时候不需要加上Bearer
		let user = {}
		try {
			user = this.app.jwt.verify(token, this.app.config.jwt.secret);
		} catch (err) {
			user = {}
		}
		return user;
	}
  1. Реализовать интерфейс для получения личной информации
// app/controller/user.js
'use strict';

const Controller = require('egg').Controller;

class UserController extends Controller {
	async info() {
		let {ctx} = this;
		let user = await this.ctx.getUserData()
		ctx.returnBody(true, user)
	}
}

module.exports = UserController;

До сих пор мы реализовали токен генерации jwt, а затем получили информацию о текущем вошедшем в систему пользователе через токен, переданный из внешнего интерфейса.Авторизация входа в jwt должна быть завершена, и другие бизнес-интерфейсы не должны быть сложными для реализации.

MD редактирование документов

Редактор документов Vditor, редактор Markdown на стороне браузера, поддерживает WYSIWYG (форматированный текст), рендеринг в реальном времени (аналогично Typora) и режим предварительного просмотра с разделением экрана. Установка Вдитор

npm install vditor --save

Внедрение и инициализация объектов в коде

<template>
  <div class="editor-component editor-md" ref="editor-component">
    <div id="editor-md-dom"></div>
  </div>
</template>

<script>
	import Vditor from 'vditor'
	import "vditor/src/assets/scss/index.scss"

	let timer = null;
	export default {
		 data(){
		 	return {
				contentEditor: '',
			}
		  },
		  mounted () {
			this.contentEditor = new Vditor('vditor', {
			  height: 360,
			  toolbarConfig: {
				pin: true,
			  },
			  cache: {
				enable: false,
			  },
			  after: () => {
				this.contentEditor.setValue('hello, Vditor + Vue!')
			  },
			})
		 },
	}
</script>

Редактирование таблицы Excel

Установить x-data-таблицу

npm install x-data-spreadsheet
<div id="x-spreadsheet-demo"></div>
import Spreadsheet from "x-data-spreadsheet";
// If you need to override the default options, you can set the override
// const options = {};
// new Spreadsheet('#x-spreadsheet-demo', options);
const s = new Spreadsheet("#x-spreadsheet-demo")
  .loadData({}) // load data
  .change(data => {
    // save data to db
  });
 
// data validation
s.validate()

хостинг прототипов axure

Страница прототипа axure размещена, обратитесь к WuliHub, чтобы пользователи могли загрузить сгенерированный сжатый html-пакет, затем распаковать его в каталог статических ресурсов и вернуть адрес доступа, все в порядке, внешний интерфейс получает адрес прототипа и отображает его с помощью встроенный iframe, это нормально

Компиляция пакетов и настройки статических ресурсов

1. Настройте интерфейсную команду упаковки vue page.

// kage.json script新增打包命令
"build-web": "vue-cli-service build",

2. Запуск npm run build-web В корневом каталоге будет сгенерирован статический файл внешнего кода dist, поскольку egg поддерживает настройку нескольких каталогов статических ресурсов.Здесь непосредственно настройте папку dist в корневом каталоге как статический каталог и настроить конфигурацию

// config/config.default.js
config.static = {
		prefix: '/',// 将静态资源前缀改为'/'(默认是 '/public')
		dir: [
			path.join(__dirname, '../app/public'), 
			path.join(__dirname, '../dist')
		]
	}

После того, как упаковка будет завершена, запустите яйцо, вы можете пройтиhttp://localhost:7001/index.htmlПосетил главную страницу


потому что прямой доступhttp://localhost:7001Будет 404 Вы можете настроить другое перенаправление маршрута, чтобы перенаправить следующий маршрут «/» на «/index.html».

// app/router.js 
// 重定向到index页面
app.router.redirect('/', '/index.html', 302);

развертывать

Развертывание сервера запускает команду start

npm run start

мониторинг производительности

Для мониторинга производительности службы узла вы можете использовать бесплатный алинод с открытым исходным кодом Ali. 1. Установите яйцо-алинод

npm i egg-alinode

2. Настройка плагина

// config/plugin.js
exports.alinode = {
  enable: true,
  package: 'egg-alinode',
};

3. Настройте конфиг

// config/config.default.js
exports.alinode = {
  enable: true,
  appid: 'my app id',
  secret: 'my app secret',
};

Вот и все, данные мониторинга можно увидеть в панели мониторинга консоли платформы производительности Alibaba Node.js.

конец

Это не сложно реализовать, это руководство просто предоставляет идеи, не лучшие практики