Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/node_modules
**/dist

**/.vscode
**/.DS_Store

37 changes: 24 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
# interview-todoList
The Interview with TodoList

语言必须Typescript、框架不限、数据库不限、接口文档
实现一个TodoList, 可参考飞书的任务功能。
仅需要列表、列表需要考虑TodoList的全部功能、不需要分组、不需要协作清单
- 需要实现一下功能
- 增删改查
- 修改历史记录
- 内容筛选(时间段、创建人)
- 支持排序(创建时间、计划完成时间、创建者、ID)
- 支持评论、@他人、消息提醒(无需实现具体功能、数据库表结构设计需要体现)
- 部署采用dockerfile(数据库可使用docker构建)
目录:
```
todolist-frontend 前端代码
todolist-backend 后端代码
```

前端构建:
```
cd todolist-frontend
npm install
npm run build
```

后端构建和启动:
```
cd todolist-backend
npm install
npm run build
docker-compose build
docker-compose up -d
```

访问地址 http://localhost:7891/static/index.html

2 changes: 2 additions & 0 deletions todolist-backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
5 changes: 5 additions & 0 deletions todolist-backend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
PORT=7891
DB_HOST=mongo
# DB_HOST=localhost
DB_PORT=27017
DB_NAME=todolist
102 changes: 102 additions & 0 deletions todolist-backend/doc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
数据库表和索引:
1. todos (model/Todo) 任务表
字段:
text 内容
creator 创建人
createTime 创建时间
planTime 计划完成时间
updateTime 更新时间
finishTime 完成时间
remindTime 提醒时间
repeatPeriod 重复周期
asignees 负责人(数组)
followers 关注人(数组)
status 状态(新建,进行中,完成,删除)
索引:
1) (followers,createTime) 联合索引
2) (followers,planTime) 联合索引
说明:任务的创建和更新接口都包含了任务的creator和asignees将自动成为followers的逻辑,所以索引建立在了followers字段上。
在根据creator进行过滤或排序的时候,同时也会在ollowers上设置相应的条件,以触发索引的查询。

2. comments (model/Comment) 评论表
字段:
content 评论内容
creator 评论人
todoId 相关任务id
replyTo 回复人
createTime 评论时间
updateTime 更新时间
索引:
1) todoId 唯一索引
说明:根据todoId上的索引可以查询出该任务下的所有评论。
replyTo字段默认为任务的创建人,也可以是评论列表内的其他人。通过replyTo字段可以构建出任务下的评论列表的树形结构,满足前端展示需求。
(但是前端暂未实现回复他人功能,只是从数据结构上保留这种可能性)

3. histories (model/History) 历史记录表
字段:
todoId 相关任务id
actionType 操作类型
field 字段
value 字段值
createTime 操作时间
operator 操作人
索引:
1) todoId 唯一索引
说明:在对任务进行创建和更新的时候会在事务内完成历史数据的记录。

4. messages (model/Message) 消息表
字段:
todoId 相关任务id
commentId 相关评论id
sentFrom 触发人
sentTo 接收人
createTime 触发时间
status 消息状态(未读,已读,删除)
索引:
1) sendTo 唯一索引
2) status 唯一索引
说明:在对任务进行评论的时候会在事务内完成消息的新建。
假定提醒消息是通过前端轮询来进行查询。通过sendTo的索引可以查询出当前用户收到的所有消息,通过status的索引可以查询出当前用户的所有未读消息。

5. users (model/User) 用户表
字段:
nickname 用户名
索引:由于用户相关需求不明确,没有建立用户表的索引。
说明:在服务启动的时候,预先写了几条用户数据在用户表里。
由于没有实现登录功能,在调用创建/更新类接口的时候,取了一条用户数据,硬编码为当前登录用户,代码中有标注。



todo.service相关接口:

1) async function getList(filter: ITodoFilter | null, sort: ITotoSort | null = null)
任务的查询,支持过滤和排序,每一条任务会返回除评论以外的所有详情数据

2)async function getHistory(todoId: string)
任务历史记录的查询

3) async function create(params: ITodo)
任务的创建

4) async function update(todoId: string, params: ITodo)
任务的更新,由于任务的删除采用了伪删的方式来实现,没有提供单独的任务删除接口



comment.service相关接口:

1) async function get(todoId: string)
根据任务id查询所有相关评论

2) async function create(params: IComment)
评论的创建

3) async function update(commentId: string, params: IComment)
评论的更新



user.service相关接口:

1) async function getList()
所有用户的查询
18 changes: 18 additions & 0 deletions todolist-backend/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: "3"
services:
mongo:
container_name: mongo
image: mongo:4.4
volumes:
- ~/mongo/db:/data/db
ports:
- 27017:27017
app:
depends_on:
- mongo
container_name: todolist-service
restart: on-failure
build: ./
ports:
- 7891:7891

13 changes: 13 additions & 0 deletions todolist-backend/dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM node:14

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install --registry=https://registry.npm.taobao.org

COPY . .

EXPOSE 7891

CMD [ "npm", "start" ]
52 changes: 52 additions & 0 deletions todolist-backend/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import express, { Express, Request, Response } from 'express';
import dotenv from 'dotenv';

import mongoose from "mongoose";
import { Todo } from './src/model/todo';
import { Comment } from './src/model/comment';
import { Message } from './src/model/message';
import { History } from './src/model/history';
import { User } from './src/model/user';

import { router as todoRouter } from './src/route/todo.router';
import { router as userRouter } from './src/route/user.router';

dotenv.config();

const app: Express = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use("/static", express.static("static"));
app.use('/todo', todoRouter);
app.use('/user', userRouter);

app.get('/', (req: Request, res: Response) => {
res.send('Express + TypeScript Server !!');
});

async function prepareDB() {
[Todo, Comment, Message, History, User].forEach(async coll => {
await coll.prepare();
});
}

async function main() {
const port = process.env.PORT;
const dbhost = process.env.DB_HOST;
const dbport = process.env.DB_PORT;
const dbname = process.env.DB_NAME;

console.log('env:', dbhost, dbport, dbname);

await mongoose.connect(`mongodb://${dbhost}:${dbport}/${dbname}`);
console.log('connected to database');

await prepareDB();

app.listen(port, () => {
console.log(`[server]: Server is running on port:${port}`);
});
}
main().catch(err => console.error(err));
Loading