73
社区成员




项目 | 内容 |
---|---|
这个作业属于哪个课程 | 2024年北航敏捷软件工程 |
这个作业的要求在哪里 | [T.17] 团队项目:Beta 阶段项目展示 |
我在这个课程的目标是 | 学习软件工程的方法论,强化成员团队合作能力,并通过实际开发产品进行实践。 |
这个作业在哪个具体方面帮助我实现目标 | 发布 Beta 阶段的相关说明,描述新的功能特性,运行环境要求,安装使用方法,系统已知的问题 |
Author: Oak团队
Date: 2024.06.13
Oak 团队共由 7 名成员组成,具体分工如下图所示
首先,使用金山文档——Oak 开发工作日志:进行任务分工展示、日常会议纪要、会议主题与后续安排确定、任务板等需要协作编辑的事务,工作日志字数已超过19000字
同时,使用微信群用于即时沟通,承载 Oak 团队的基本交流需求
并且使用腾讯会议于每周四晚 19:00 召开周例会,如果线上则采用腾讯会议的形式。同时 Beta 阶段每两天召开一次 Scrum-meeting,统一会议时间设置在晚上 22:00,具体会议内容可以参考每次的会议纪要。
必要的时候,采取线下面对面沟通,重要事项讨论时采用。在第四周测试与集成的过程中,全天全队线下进行网站的开发与测试,保证开发的敏捷性。
Github:拟采用前后端分仓库的形式进行代码管理,选用 Github 的原因如下。开源社区、用户基数庞大,GitHub拥有1亿以上的开发人员,400万以上组织机构和3.3亿以上资料库;强大的工具和功能,使用GitHub Actions可以自动化项目流程,并且模版众多;优秀的UI设计,充满着未来的科技赛博感和代码的强逻辑性与强创造力,同时坐拥了良好的用户反馈与动画
Github Actions:持续开发与持续部署
项目前后端仓库均实现了 CI/CD,实现理由:
前端
前端的CI/CD,实现人员私以为比较优雅(嘿嘿),基本实现工具囊括了Github Actions、Docker、nginx,过程可以分为以下几个阶段:
后端
后端的CI/CD比较丑陋,但怎么说呢,反正能用(),基本实现工具包括Github Actions、uwsgi,过程可以分为以下几个阶段:
领歌Leangoo:进行团队燃尽图的绘制
在项目管理中,由于课程组提供的基于Github Issue与Milestone绘制的工具不能使用,本次开发Oak主要采用 Leangoo领歌 来进行燃尽图的绘制,根据任务分配设置任务看板,并在每次 scrum-meeting 前针对此两日的工作进行已完成标注。如上图所示,该燃尽图表明团队整体开发基本符合规范,在开发阶段有合理的时间分配,不存在畸形的开发进度。
由于并未结合Issue,所以事实上该燃尽图是一定程度上美化了团队的实际开发进展的,主要可以从以下几个方面展开描述:
Slogan:把地图当作画布,记录美好生活
定位:以地图为基础的生活记录和分享平台
在快速发展的数字时代,人们的生活方式和记录习惯也在发生变化。传统的地图应用主要关注于导航和位置搜索,而忽视了个人生活记录与分享的需求。"吟游Map"旨在填补这一市场空缺,提供一个结合地图与生活记录的平台,不仅帮助用户规划行程,记录旅行中的点点滴滴,还能在日常生活中捕捉和分享那些与地点相关的特殊时刻。这种结合地图的生活记录方式,为用户带来全新的体验和记忆存储方式,增加了地理信息的情感价值。
旅游博主
姓名 | Elena |
---|---|
年龄 | 30 |
职业 | 社交平台博主 |
需求 | 记录自己的旅行,在小红书、B站、抖音上分享旅行日常、攻略 |
占比 | 15% |
旅行爱好者 |
姓名 | Billy |
---|---|
年龄 | 23 |
职业 | 学生 |
需求 | 出行前制定旅行计划,出行过程中记录日常,在旅行后可以在微信朋友圈分享自己的旅行记录 |
占比 | 80% |
文旅相关工作人员 |
姓名 | Iris |
---|---|
年龄 | 35 |
职业 | 文旅宣传工作负责人 |
需求 | 记录所在地区的旅行热点、在社交媒体及官方宣传渠道分享宣传,吸引游客前来旅行 |
占比 | 5% |
计划
Billy 决定在即将到来的五一假期和四个同学前往天津旅行。出行前他查找了大量的攻略,但这些攻略分布在不同的平台,将这些攻略分享给一起出行的朋友以及在实际旅行时打开每一个查看都十分繁杂,于是他决定用”吟游Map“结合已搜索到的攻略制定自己的旅行计划并在出行前发送给每一个同学。
他首先创建新的地图画布,选定自己要前往的地区。
接着,他根据搜集来的攻略在地图上标记要旅行的景点,并选定参观景点的顺序,再通过路线规划功能自动生成推荐的旅行路线。
然后,他选择标定的景点,并添加备注文本。他可以将参观该景点的建议、景点开放时间、门票价格、景点亮点等信息均填入到备注文本中,便于在实地参观使用。
最后他使用导出地图画布,将制定好的攻略以 pdf 的形式发送给同行的同学们。
记录
Elena 决定前往欧洲旅行,以往她会在小红书等社交媒体平台同步更新一期自己的旅行 vlog,但上次视频下,有粉丝留言希望她能同时分享文图结合的旅行日志,于是在这次她决定使用”吟游Map“来完成粉丝的这一心愿。
第一站,她来到了巴黎,她在巴黎游览了埃菲尔铁塔,探索了世界上最大的艺术博物馆卢浮宫,在香榭丽舍大街上步行到凯旋门……下一站她决定前往米兰,在机场,她决定写一份巴黎的旅行日志。
她首先新建地图画布,将地区选在了巴黎,然后标记自己到访过的景点,并在选定景点插入了自己旅行时拍的照片,同时加入了文字介绍,接着她根据自己的旅行顺序,绘制了旅行线路图,并最后记录了自己在巴黎的账单。
完成地图画布的创作后,她根据自己的喜欢,风格化了地图,并将其以图文的方式分享在了小红书。
分享
Iris 是 D 市文化和旅游局的工作人员,她承担着 D 市传文旅的工作。以往她发布的宣传信息中,文字与图片分离,地图上的路线信息和景点的介绍彼此孤立,因此导致宣传效果大大折扣。她在了解到”吟游Map
“可以把地图当成画布,在地图上记录后,决定在最新的宣传中使用”吟游Map“来编辑文案,完成自己的宣传工作。
她首先新建地图画布,选择 D 市的范围,然后标记了特色、热门的景点,并在插入景区照片,加入了景点信息介绍,同时还描绘了推荐路线图。
她在地图画布的编辑完成后,选择要分享的平台,根据不同平台导出对应形式的文案,并分享在不同的平台上。
在使用了”吟游Map“后,这一次的浏览量大幅提升,高质量地完成了宣传工作,在过去了清明假期中,吸引了大量游客,为 D 市带来了大量的旅游收入。
小明是一位喜欢旅游的大学生,但他一直苦于没有合适的地方来记录每次经历。某次朋友给他推荐了「吟游Map」app,听说这款软件可以帮他在地图上记录生活,于是小明准备试试这款软件。
首先小明通过搜索功能找到目标景点:
随后,小明点击目标景点以跳转到对应位置,手动缩放到合适大小:
点击地址搜索栏的 x
号关闭地址搜索组件。
随后,小明在地图上标注出值得一去的景。选择锚点工具,然后标注:
上图标注了来北航学院路校区必去的几个地方:大运村、新主楼、航空航天博物馆、晨兴音乐厅、绿园。
不过先去哪里?后去哪里?最佳的游玩路线是什么?
切换到路径规划工具,在右上方选择步行作为出行方式,然后按照期望的游玩顺序点击锚点,首先点击大运村和绿园的锚点:
然后点击绿园和航空航天博物馆的锚点:
重复这个操作,把剩下的锚点也加到路径里:
不小心点错了?没关系,右键锚点可以删除附着到该锚点上的路径。删除新主楼锚点上附着的路径:
锚点标记的位置不太理想?没关系,回到锚点工具下,拖动锚点,路径将会自动重新规划。移动航空航天博物馆以及晨兴音乐厅的锚点:
完善一下,一份北航学院路校区的旅游攻略就做好了:
用户也可以边旅行边记录走过的路径,比如在沈阳玩上几天,可能会得到下面这张地图:
本次发布新增了用户引导的功能。点击地图页面右下角的 ?
按钮即可进入当前工具视图下的用户引导。
例如,目前没有选中任何工具,点击 ?
按钮则会依次介绍页面上所有元素的功能:
如果正在使用锚点工具,点击 ?
按钮则会介绍锚点工具的使用方法:
除此之外,本次发布也对危险行为添加了二次确认,例如删除地图时,会弹出二次确认的对话框:
在 raccoon
路由下,可以进入Oak开发团队的菜单页面,该桌面宠物本来想作为用户引导的一部分,大大提升该产品的趣味性。可以做到最后,本团队遗憾地发现该组件的背景色在Web端无法调整至透明。
Anyway,这也是一次伟大的尝试!!!最后我们将它作为一个彩蛋页面,或许你可以试试多点几次,点到100次说不定还有惊喜~
小A在创建地图画布后,可以根据自己的喜好选择对应的地图风格,如标准、幻影黑、月光银、远山黛等等。
小A在白天参观中国国家博物馆后,想把自己的见闻以日记的形式记录下来。
首先小A在地图上用"marker"标记出中国国家博物馆。
然后小A点击对应锚点,点击查看日记。
接着小A新增日记,输入标题和摘要,便点击查看。
此时的日记内容为空,小A点击编辑日记,用文字结合自己白天拍摄的图片,编辑了图文并茂的日记。
小A想记录一下在北京旅游第一天的花费,TA同样先在地图上标记今天游览过的地方。
点击对应的"marker",创建并查看账单。
再点击编辑账单,进入编辑页面。
小A根据今天的花费,在账单中添加记录。
下方自动为小A统计出了每类花费的占比等数据。
小明是一位喜欢旅游的大学生,但他一直苦于没有合适的地方来记录每次经历。某次朋友给他推荐了「吟游Map」app,听说这款软件可以帮他在地图上记录生活,于是小明准备试试这款软件。
小明首先注册了一个账号。
该页面引导新用户进行注册。新用户在输入用户名、密码并再次输入相同的密码后点击注册按钮,待系统检测通过后即可用新账号进行登录。
小明随即用刚刚注册的账号进行登录。
该页面引导用户进行登录。用户输入用户名以及密码后点击登录按钮,待系统验证通过后即可成功登录。
小明觉得之前用的密码不够安全,所以决定修改密码。
该页面允许用户修改密码。用户在登录状态下输入原密码并输入两次新密码后点击修改按钮,等待系统验证通过后修改密码成功。
小明登录成功后来到了开始页面,瞬间小明就被宣传语深深吸引住了,于是他迫不及待点击了开始按钮。
小明的每一次旅行对他而言都是一次非常珍贵的回忆,他在主页创建了一张又一张地图来记录每一次旅行的点点滴滴。
用户可以在主页创建新地图,主页上会显示用户最近更新的地图以及其他地图的名字,标记数目,日记数目等信息。
用户可以收藏地图。点击地图右边的五角星即可收藏/取消收藏,收藏的地图会在收藏页展示。
用户可以搜索创建的地图。点击搜索框后在框中输入关键词即可查看相关的地图。
小明想要把自己精心制作的地图保存下来或分享给其他人看看,于是他尝试了导出功能。
用户可以点击右上角的导出图片/pdf按钮将地图导出为图片/pdf。
「吟游Map」是一款 Web 端应用,通过浏览器访问 吟游Map即可
地图搜索
地图收藏
支持PDF导出与JPG导出,分别对应攻略分享和朋友圈分享两个场景
剩余介绍详见“项目与团队总结——特色功能”部分
略,见“项目与团队总结——三、用户日活”部分
团队 PR 情况
团队 CI/CD 触发情况
代码编写情况
前端
后端
其余略,见“项目与团队总结——五、软件工程质量”部分
以成员姓名首字母的字典序进行排列
我是练习时长两年半的北航练习生,喜欢吃、睡、code和群星。
在今后的节目中,我和我的朋友们还准备了很多我们自己做调查、做分析、编码的原创作品,期待的话,请多多为我们投票吧
在这次团队中主要担任后端开发的工作
我是胡诗杰
在本次团队中担任前端开发,架构设计的工作
“全世界的水都会相逢,北冰洋与尼罗河也会在湿云中相逢”
想做有意义的东西,讨厌当麻木的编程机器,更讨厌成为被工具化的码农
编码能力有待提升,等着各位大佬带着飞
在本次团队中主要担任后端开发、Project Manager的工作
希望跟大家能拥有一段有趣而独特的项目经历~
在本次团队中主要担任后端开发的工作
我是闵若涵
在本次团队中担任前端开发的工作
--<-<<+[+[<+>--->->->-<<<]>]<<--.<++++++.<<-..<<.<+.>>.>>.<<<.+++.>>.>>-.<<<+.
在团队中主要担任前端开发的工作
“to console the unconsoled”
希望和大家创造一个好的产品
在本次团队中主要担任前端开发的工作
金山文档——Oak 开发工作日志:用于任务分工展示、日常会议纪要、会议主题与后续安排确定、任务板等需要协作编辑的功能
微信群:用于即时沟通,承载 Oak 团队的基本交流需求
腾讯会议:每周四晚 19:00 召开周例会,如果线上则采用腾讯会议的形式
线下:面对面沟通,重要事项讨论时采用
Github:拟采用前后端分仓库的形式进行代码管理,选用 Github 的原因如下。开源社区、用户基数庞大,GitHub拥有1亿以上的开发人员,400万以上组织机构和3.3亿以上资料库;强大的工具和功能,使用GitHub Actions可以自动化项目流程,并且模版众多;优秀的UI设计,充满着未来的科技赛博感和代码的强逻辑性与强创造力,同时坐拥了良好的用户反馈与动画
Github Actions:持续开发与持续部署
领歌:进行团队燃尽图的绘制
由PM按照功能模块,大致划分任务,然后经过会议的方式进行统一的表决,尽量保证任务分配均衡,在此基础上多劳多得。Alpha 阶段的任务分配主要采用成员认领,先到先得的方式进行分配。
总的开发更新点:
(1)用户提示(基于Element UI的导航组件,浮窗的形式显示,拖拽之类的实现存疑,非Element UI组件存疑,js捕获或许可以;悬浮在页面上的提示窗;做一个引导教程类型的东西)1人 wjl
(2)风格化(地图、路径、锚点) 1人 hsj
(3)导出功能(格式:图片、文本、html)2人 lnb mrh
(4)日记账单在地图上的显示、一个锚点多日记 1人 yyy
(5)添加锚点的形式 数字、emoji(搜索、中心打点)、锚点的有序化 1人 hrl
任务名称 | 预计时长(小时) |
---|---|
地图风格化方案敲定 | 8 |
地图图层的风格化 | 8 |
路径风格化 | 4 |
自定义样式的地图风格创建 | 8 |
用户提示方案敲定 | 6 |
用户提示浮窗的实现 | 8 |
引导教程 | 6 |
导出方案的敲定 | 4 |
导出模式的确定(图片、文本、html) | 4 |
图片导出的制作 | 8 |
HTML导出功能的制作 | 8 |
文本导出功能的制作 | 8 |
日记在地图上的显示 | 4 |
账单在地图上的显示 | 4 |
导出日记与账单的适配 | 6 |
一个锚点多日记的实现 | 8 |
前后端交互API | 6 |
Sauce Labs进行不同浏览器的适配测试 | 8 |
基于DRF进行单元测试 | 8 |
项目展示与总结 | 6 |
会议纪要与文档 | 6 |
导出方案的敲定 | 4 |
导出模式的确定(图片、文本、html) | 4 |
图片导出的制作 | 8 |
HTML导出功能的制作 | 8 |
文本导出功能的制作 | 8 |
前端锚点的多样式功能(数字、emoji) | 8 |
后端锚点多样式的适配 | 4 |
锚点的有序化 | 4 |
中间添加锚点的功能实现 | 4 |
搜索添加锚点的功能 | 4 |
首先,使用金山文档——Oak 开发工作日志:进行任务分工展示、日常会议纪要、会议主题与后续安排确定、任务板等需要协作编辑的事务,工作日志字数已超过19000字
同时,使用微信群用于即时沟通,承载 Oak 团队的基本交流需求
并且使用腾讯会议于每周四晚 19:00 召开周例会,如果线上则采用腾讯会议的形式。同时Alpha 阶段每两天召开一次 Scrum-meeting,统一会议时间设置在晚上 22:00,具体会议内容可以参考每次的会议纪要。
必要的时候,采取线下面对面沟通,重要事项讨论时采用。在第四周测试与集成的过程中,全天全队线下进行网站的开发与测试,保证开发的敏捷性。
燃尽图
在项目管理中,由于课程组提供的基于Github Issue与Milestone绘制的工具不能使用,本次开发Oak主要采用 Leangoo领歌 来进行燃尽图的绘制,根据任务分配设置任务看板,并在每次 scrum-meeting 前针对此两日的工作进行已完成标注。如上图所示,该燃尽图表明团队整体开发基本符合规范,在开发阶段有合理的时间分配,不存在畸形的开发进度。
由于并未结合Issue,所以事实上该燃尽图是一定程度上美化了团队的实际开发进展的,主要可以从以下几个方面展开描述:
名字 | 角色 | 团队基础分+转赠分+工作量互评分 | 具体的, 可衡量的, 可验证的贡献 |
---|---|---|---|
柯棋严 | PM | 38+6+(2+2+1+4+1+2)=56 | 单元测试,浏览器匹配性测试,网站部署运维和CICD,后端PR审核,项目展示,团队博客(T13-14,T17-18共4篇博客撰写,余下两篇博客整合),7篇会议纪要,1次用户推广,1次用户调查 |
王继来 | 前端开发 | 38+4+(2+1+2+2)=49 | 用户手册,功能规格书部分内容 实现了用户引导,彩蛋页面,重构部分功能 |
尹悠阳 | 前端开发 | 38+2+(1+2)=43 | 用户手册,功能规格书,实现了单锚点多日记,地图上地日记帐单显示,日记帐单查看和编辑分离 |
胡诗杰 | 前端开发 | 38+2+(1+1+1+3)=46 | 测试报告,功能规格书,基础框架搭建,登录注册密码鉴权,主页面,导航栏,开发者名单,意见反馈模块 |
闵若涵 | 前端开发 | 38+4+(1+4+2)=49 | 共同实现了导出功能,包括导出地图图片,导出地图与日记为PDF,压缩导出PDF,html2canvas与地图日记的适应 用户手册、运行环境 |
黄融亮 | 后端开发 前端开发 | 38+6+(2+2+4+2+4+1)=59 | 团队博客(T14后端出口,前端marker出口) 1次用户调查(9个ux建议,完成5个) 后端API迭代与文档 数据库迁移工作 前端导出库的补丁 前端基础的日记弹窗基础适配 前端marker label拓展,提色器拓展,二级toolbar拓展 5次bug修改 ...... |
李南冰 | 后端开发 | 38+4+(1+4+1)=48 | 测试报告,技术规格书 共同实现了导出功能,包括导出地图图片,导出地图与日记为PDF,压缩导出PDF,html2canvas与地图日记的适应 完成了对新增多个接口的压力测试 |
注:团队贡献分严格按照以下公式计算得到,过程完全透明,保证多劳多得的原则,详细分配规则参考[Oak 08] 团队项目:团队贡献分分配规则
$$score = Base + Bonus_d + Bonus_w$$
名字 | Alpha得分 | Beta得分 | 总分(平均后微调) |
---|---|---|---|
柯棋严 | 60 | 56 | 57 |
王继来 | 53 | 49 | 51 |
尹悠阳 | 45 | 43 | 45 |
胡诗杰 | 45 | 46 | 46 |
闵若涵 | 46 | 49 | 48 |
黄融亮 | 52 | 59 | 55 |
李南冰 | 49 | 48 | 48 |
Slogan:把地图当作画布,记录美好生活
定位:以地图为基础的生活记录和分享平台
在快速发展的数字时代,人们的生活方式和记录习惯也在发生变化。传统的地图应用主要关注于导航和位置搜索,而忽视了个人生活记录与分享的需求。"吟游Map"旨在填补这一市场空缺,提供一个结合地图与生活记录的平台,不仅帮助用户规划行程,记录旅行中的点点滴滴,还能在日常生活中捕捉和分享那些与地点相关的特殊时刻。这种结合地图的生活记录方式,为用户带来全新的体验和记忆存储方式,增加了地理信息的情感价值。
旅游博主
姓名 | Elena |
---|---|
年龄 | 30 |
职业 | 社交平台博主 |
需求 | 记录自己的旅行,在小红书、B站、抖音上分享旅行日常、攻略 |
占比 | 15% |
旅行爱好者 |
姓名 | Billy |
---|---|
年龄 | 23 |
职业 | 学生 |
需求 | 出行前制定旅行计划,出行过程中记录日常,在旅行后可以在微信朋友圈分享自己的旅行记录 |
占比 | 80% |
文旅相关工作人员 |
姓名 | Iris |
---|---|
年龄 | 35 |
职业 | 文旅宣传工作负责人 |
需求 | 记录所在地区的旅行热点、在社交媒体及官方宣传渠道分享宣传,吸引游客前来旅行 |
占比 | 5% |
计划
Billy 决定在即将到来的五一假期和四个同学前往天津旅行。出行前他查找了大量的攻略,但这些攻略分布在不同的平台,将这些攻略分享给一起出行的朋友以及在实际旅行时打开每一个查看都十分繁杂,于是他决定用”吟游Map“结合已搜索到的攻略制定自己的旅行计划并在出行前发送给每一个同学。
他首先创建新的地图画布,选定自己要前往的地区。
接着,他根据搜集来的攻略在地图上标记要旅行的景点,并选定参观景点的顺序,再通过路线规划功能自动生成推荐的旅行路线。
然后,他选择标定的景点,并添加备注文本。他可以将参观该景点的建议、景点开放时间、门票价格、景点亮点等信息均填入到备注文本中,便于在实地参观使用。
最后他使用导出地图画布,将制定好的攻略以 pdf 的形式发送给同行的同学们。
记录
Elena 决定前往欧洲旅行,以往她会在小红书等社交媒体平台同步更新一期自己的旅行 vlog,但上次视频下,有粉丝留言希望她能同时分享文图结合的旅行日志,于是在这次她决定使用”吟游Map“来完成粉丝的这一心愿。
第一站,她来到了巴黎,她在巴黎游览了埃菲尔铁塔,探索了世界上最大的艺术博物馆卢浮宫,在香榭丽舍大街上步行到凯旋门……下一站她决定前往米兰,在机场,她决定写一份巴黎的旅行日志。
她首先新建地图画布,将地区选在了巴黎,然后标记自己到访过的景点,并在选定景点插入了自己旅行时拍的照片,同时加入了文字介绍,接着她根据自己的旅行顺序,绘制了旅行线路图,并最后记录了自己在巴黎的账单。
完成地图画布的创作后,她根据自己的喜欢,风格化了地图,并将其以图文的方式分享在了小红书。
分享
Iris 是 D 市文化和旅游局的工作人员,她承担着 D 市传文旅的工作。以往她发布的宣传信息中,文字与图片分离,地图上的路线信息和景点的介绍彼此孤立,因此导致宣传效果大大折扣。她在了解到”吟游Map
“可以把地图当成画布,在地图上记录后,决定在最新的宣传中使用”吟游Map“来编辑文案,完成自己的宣传工作。
她首先新建地图画布,选择 D 市的范围,然后标记了特色、热门的景点,并在插入景区照片,加入了景点信息介绍,同时还描绘了推荐路线图。
她在地图画布的编辑完成后,选择要分享的平台,根据不同平台导出对应形式的文案,并分享在不同的平台上。
在使用了”吟游Map“后,这一次的浏览量大幅提升,高质量地完成了宣传工作,在过去了清明假期中,吸引了大量游客,为 D 市带来了大量的旅游收入。
本团队此处采用 Axure 进行原型设计,下文主要展示了产品的十个构成页面,从而涵盖用户功能模块、地图功能模块、日记功能模块的基本功能。此处仅用作示意功能,后续开发可能会动态调整以适应用户需求。
注册与登录页面
集成了登录与注册功能的页面。
开始页
地图页——日记预览
地图页——marker 编辑
地图页——日记编辑
地图页——记账
地图页——样式与风格化
地图页——路径规划
地图页——分享
地图页——大纲
小明是一位喜欢旅游的大学生,但他一直苦于没有合适的地方来记录每次经历。某次朋友给他推荐了「吟游Map」app,听说这款软件可以帮他在地图上记录生活,于是小明准备试试这款软件。
首先小明通过搜索功能找到目标景点:
随后,小明点击目标景点以跳转到对应位置,手动缩放到合适大小:
点击地址搜索栏的 x
号关闭地址搜索组件。
随后,小明在地图上标注出值得一去的景。选择锚点工具,然后标注:
上图标注了来北航学院路校区必去的几个地方:大运村、新主楼、航空航天博物馆、晨兴音乐厅、绿园。
不过先去哪里?后去哪里?最佳的游玩路线是什么?
切换到路径规划工具,在右上方选择步行作为出行方式,然后按照期望的游玩顺序点击锚点,首先点击大运村和绿园的锚点:
然后点击绿园和航空航天博物馆的锚点:
重复这个操作,把剩下的锚点也加到路径里:
不小心点错了?没关系,右键锚点可以删除附着到该锚点上的路径。删除新主楼锚点上附着的路径:
锚点标记的位置不太理想?没关系,回到锚点工具下,拖动锚点,路径将会自动重新规划。移动航空航天博物馆以及晨兴音乐厅的锚点:
完善一下,一份北航学院路校区的旅游攻略就做好了:
用户也可以边旅行边记录走过的路径,比如在沈阳玩上几天,可能会得到下面这张地图:
本次发布新增了用户引导的功能。点击地图页面右下角的 ?
按钮即可进入当前工具视图下的用户引导。
例如,目前没有选中任何工具,点击 ?
按钮则会依次介绍页面上所有元素的功能:
如果正在使用锚点工具,点击 ?
按钮则会介绍锚点工具的使用方法:
除此之外,本次发布也对危险行为添加了二次确认,例如删除地图时,会弹出二次确认的对话框:
在 raccoon
路由下,可以进入Oak开发团队的菜单页面,该桌面宠物本来想作为用户引导的一部分,大大提升该产品的趣味性。可以做到最后,本团队遗憾地发现该组件的背景色在Web端无法调整至透明。
Anyway,这也是一次伟大的尝试!!!最后我们将它作为一个彩蛋页面,或许你可以试试多点几次,点到100次说不定还有惊喜~
小A在创建地图画布后,可以根据自己的喜好选择对应的地图风格,如标准、幻影黑、月光银、远山黛等等。
小A在白天参观中国国家博物馆后,想把自己的见闻以日记的形式记录下来。
首先小A在地图上用"marker"标记出中国国家博物馆。
然后小A点击对应锚点,点击查看日记。
接着小A新增日记,输入标题和摘要,便点击查看。
此时的日记内容为空,小A点击编辑日记,用文字结合自己白天拍摄的图片,编辑了图文并茂的日记。
小A想记录一下在北京旅游第一天的花费,TA同样先在地图上标记今天游览过的地方。
点击对应的"marker",创建并查看账单。
再点击编辑账单,进入编辑页面。
小A根据今天的花费,在账单中添加记录。
下方自动为小A统计出了每类花费的占比等数据。
小明是一位喜欢旅游的大学生,但他一直苦于没有合适的地方来记录每次经历。某次朋友给他推荐了「吟游Map」app,听说这款软件可以帮他在地图上记录生活,于是小明准备试试这款软件。
小明首先注册了一个账号。
该页面引导新用户进行注册。新用户在输入用户名、密码并再次输入相同的密码后点击注册按钮,待系统检测通过后即可用新账号进行登录。
小明随即用刚刚注册的账号进行登录。
该页面引导用户进行登录。用户输入用户名以及密码后点击登录按钮,待系统验证通过后即可成功登录。
小明觉得之前用的密码不够安全,所以决定修改密码。
该页面允许用户修改密码。用户在登录状态下输入原密码并输入两次新密码后点击修改按钮,等待系统验证通过后修改密码成功。
小明登录成功后来到了开始页面,瞬间小明就被宣传语深深吸引住了,于是他迫不及待点击了开始按钮。
小明的每一次旅行对他而言都是一次非常珍贵的回忆,他在主页创建了一张又一张地图来记录每一次旅行的点点滴滴。
用户可以在主页创建新地图,主页上会显示用户最近更新的地图以及其他地图的名字,标记数目,日记数目等信息。
用户可以收藏地图。点击地图右边的五角星即可收藏/取消收藏,收藏的地图会在收藏页展示。
用户可以搜索创建的地图。点击搜索框后在框中输入关键词即可查看相关的地图。
小明想要把自己精心制作的地图保存下来或分享给其他人看看,于是他尝试了导出功能。
用户可以点击右上角的导出图片/pdf按钮将地图导出为图片/pdf。
「吟游Map」是一款 Web 端应用,通过浏览器访问 吟游Map即可
Beta阶段完成后,典型场景基本满足
Beta阶段新增的功能:
基本符合用户需求,以下是一位目标用户使用产品的过程和评价。
背景:该目标用户使用 吟游Map 进行了北航校园行程规划和北京旅游攻略制作。
过程与评价:这个新版本的软件已经能够满足我的需求,比如说用来进行攻略的制作,旅游或者日常出行的路径规划,还有记账日记一些用来记录生活的功能。新版本里内置的风格化与导出功能我觉得很好地弥补了上一个版本的缺失,也从某种意义上符合了我试用这个软件的初衷,能够较为美观且清晰地展示我的规划。但是美中不足的是,导出的图片我觉得不太有特点,还是局限在了一个地图载体之上。
在 吟游Map 用户群进行内部交流,发布版本更新;同时建立了用户反馈问卷,并在用户群和网站上发布
目标
实际结果
基本满足预先定义的数量
用户数目:155个用户
实际地图数目:1000+部地图(其余地图用于压力测试)
实际路径数目:5000+条路径(其余路径用于压力测试)
实际标记点数目:2000+个标记点(其余标记点用于压力测试)
有用户进行功能上的反馈,但是数量较为有限
用户反馈的 bug 主要有以下几个:
问题:锚点文字标识功能存在问题
在部分浏览器上,在编辑锚点中央的文字标识时可能出不能顺利输入文字的问题。为了输入文字,用户可以选择将剪切板中的内容复制到文字标识输入框内,可缓解该问题的影响。本功能的初衷是让用户输入数字,输入数字以及英文字母均不会触发该问题。
限制:缩略图显示的区域缺乏实用性
当前的缩略图显示区域为地图上所有锚点的几何中心所在位置。如果锚点分布分散,则会导致该区域没有实际内容。不过,进入地图后会自动移动到上一次离开时的位置,实际使用过程中不会有明显感知。
限制:移动端操作不够便捷
当前版本在开发时优先适配桌面端浏览器环境,部分操作如右键删除锚点在移动端只能通过长按代替,操作不够便捷。
限制:部分功能的使用次数有限
由于高德部分 API 的调用有次数限制,因此次数用完之后部分功能将无法使用。其中受到影响最大的是位置搜索功能,该功能的使用上限为 100 次,因此很快就会用完。不过,本应用的核心功能(锚点标注、日记、记账)均不会依赖这些 API ,因此不会影响用户的核心体验。
限制:缺少快捷键
当前版本不支持快捷键,强依赖于鼠标点击与拖拽,部分场景如登录、添加锚点、移动地图、删除锚点等可能更加适合用键盘操作。不过当前版本尽可能优化了鼠标操作的便捷程度,使之符合直觉。
Beta阶段完成了该软件所有功能的研发,Oak团队认为,本产品具有四大杀手功能外加一个菜单,这三个功能分别是地图搜索与收藏、地图样式自主风格化、日记记账与地图导出,
地图搜索
地图收藏
支持PDF导出与JPG导出,分别对应攻略分享和朋友圈分享两个场景
竞品Exping事实上在地图风格化方面做得较好,预设了多种样式的地图,但是绝大多数都是收费体验,且Exping完全不支持地图导出功能。我们认为主要原因在于,地图渲染的成本高,作为一个企业组织需要有效平衡产出比;其次,其实很难找到一个平衡美观和地图导出的方案,日记的文字数目,锚点数目都是一些未知且动态范围大的变量。
团队的优势是,以实现该功能为出发点,舍弃掉了一些美工上的特性,尝试以html2canvas为基础进行功能的实现(例如该组件不支持SVG,故放弃了锚点多样式的功能)
竞品 Exping 的简介模块采用了简介和照片分离的模式,且简介部分仅支持纯文本的编辑,同时,Exping 中并未加入记账这样一个功能。
团队的优势是结合 Froala 编辑器实现了富文本编辑日记的功能,从而实现图片与文字夹杂同时单独开辟日记模块,生成日常开销的相关统计数据。
日记和记账模块基本达到预期,其能够有效地辅助用户完成旅游计划或日常开销的记录,并且允许用户以富文本的形式撰写日记记录生活,允许文字与图片相结合的方式进行呈现。
地图样式自主风格化与地图导出功能基本达到预期,但是其实为了导出,在美工方面还是妥协了不少。但是作为一个工具,还是能够支持用户利用这个工具制作出比较精美的地图记录。
用户对这些功能的评价为基本满意,其特别赞赏“吟游Map”在旅行和日常生活记录方面的实用性。应用的地图集成和标记功能使得记录具体地点的经历变得非常直观和方便。此外,用户还提到,该应用的界面友好且易于导航,新用户可以迅速上手并开始记录他们的旅程。另外,记账功能也被认为是一个亮点,它不仅帮助用户跟踪旅行开支,还使得日常财务管理更加有序。用户们认为这个功能帮助他们更好地理解和控制旅行期间的个人财务。
地图样式的个性化定制和地图数据的导出功能同样也是一大亮点。用户对能够改变地图的视觉样式表示出较大兴趣,表示能基于此实现一个美观简洁的地图记录。此外,能够导出地图为不同格式,如PDF或图片,极大地增加其实用性,用户能够更方便地分享和打印他们的旅行和生活记录。
首先,项目有完善的前后端对接文档,详情可见工作日志中前后端对接文档与后端仓库中的 api.md 文档,以下使用部分对接文档作为展示
其次,Oak团队约定了代码规范
API 规约
统一格式
<对象>_id
进行区分成功信息为
"<行为><对象>成功"
失败信息为
"没有对应的<对象>" --> <对象>id不存在
"用户权限错误" --> 操作别人的地图、marker、日记、账目
"请求缺少数据" --> 请求缺少必要数据
"数据库错误" --> 数据库sql执行错误
"未知错误"
.......
后端代码规约
参考 Django 代码规范:https://blog.csdn.net/zhouruifu2015/article/details/129647979?ops_request_misc=&request_id=&biz_id=102&utm_term=Django%E4%BB%A3%E7%A0%81%E7%BC%96%E5%86%99%E8%A7%84%E8%8C%83&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-129647979.142^v100^pc_search_result_base7&spm=1018.2226.3001.4187
环境规范:Python 3.10.6;Django4.2.3;mysql Ver 8.0.11 for Win64
前端代码规范
参考 Vue 前端代码开发规范:
https://blog.csdn.net/sjsja/article/details/123480376
环境规范:Vue3; Node Its 20.12.2
项目基本没有出现代码混乱,没有注释,没有详细文档的问题。我们认为明年的同学继续开发这个项目,不会出现以上抱怨
如果一个新学生在一台新机器上想编译并运行你的项目, 我们认为能顺利完成
首先关于环境配置,我们提供了相关的配置文件 requirements.txt
同时提供了相关的部署文件,例如nginx.conf
, dev.yml
, Dockerfile
, uwsgi.ini
此外,前后端都有关于配置项目与启动项目的简单说明 README.md
团队基于Jmeter对主要API进行压力测试,基于DRF架构针对路由进行了覆盖率为76%的单元测试,基于SauceLabs对软件进行了浏览器适配的测试。
Oak 团队以 DRF 框架为基础进行针对后端 API 的单元测试,总文件测试类覆盖率达到90%,方法覆盖率达到76%
File | class | statements | missing | excluded | coverage |
---|---|---|---|---|---|
path\views.py | (no class) | 16 | 0 | 0 | 100% |
path\urls.py | (no class) | 3 | 0 | 0 | 100% |
path\tests.py | PathAPITests | 31 | 0 | 0 | 100% |
path\tests.py | (no class) | 21 | 1 | 0 | 95% |
path\models.py | Path | 1 | 0 | 0 | 100% |
path\models.py | Path.Meta | 0 | 0 | 0 | 100% |
path\models.py | (no class) | 12 | 0 | 0 | 100% |
path\apps.py | PathConfig | 0 | 0 | 0 | 100% |
path\apps.py | (no class) | 4 | 0 | 0 | 100% |
path\admin.py | (no class) | 3 | 0 | 0 | 100% |
myapp\views\index\user.py | LoginView | 22 | 4 | 0 | 82% |
myapp\views\index\user.py | ChangePasswordView | 21 | 21 | 0 | 0% |
myapp\views\index\user.py | RegisterView | 22 | 4 | 0 | 82% |
myapp\views\index\user.py | (no class) | 26 | 0 | 0 | 100% |
myapp\views\index\secure.py | EncryptedService | 4 | 0 | 0 | 100% |
myapp\views\index\secure.py | (no class) | 16 | 0 | 0 | 100% |
myapp\urls.py | (no class) | 3 | 0 | 0 | 100% |
myapp\tests.py | EncryptionTests | 39 | 0 | 0 | 100% |
myapp\tests.py | (no class) | 14 | 0 | 0 | 100% |
myapp\models\user.py | MapUser | 0 | 0 | 0 | 100% |
myapp\models\user.py | MapUser.Meta | 0 | 0 | 0 | 100% |
myapp\models\user.py | (no class) | 16 | 0 | 0 | 100% |
myapp\apps.py | MyappConfig | 0 | 0 | 0 | 100% |
myapp\apps.py | (no class) | 4 | 0 | 0 | 100% |
myapp\admin.py | (no class) | 3 | 0 | 0 | 100% |
marker\views.py | (no class) | 17 | 0 | 0 | 100% |
marker\urls.py | (no class) | 3 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests | 33 | 0 | 0 | 100% |
marker\tests.py | (no class) | 20 | 1 | 0 | 95% |
marker\models.py | Marker | 23 | 10 | 0 | 57% |
marker\models.py | Marker.Meta | 0 | 0 | 0 | 100% |
marker\models.py | (no class) | 23 | 0 | 0 | 100% |
marker\apps.py | MarkerConfig | 0 | 0 | 0 | 100% |
marker\apps.py | (no class) | 4 | 0 | 0 | 100% |
marker\admin.py | (no class) | 3 | 0 | 0 | 100% |
manage.py | (no class) | 5 | 0 | 0 | 100% |
graph\views.py | (no class) | 18 | 0 | 0 | 100% |
graph\urls.py | (no class) | 3 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests | 36 | 0 | 0 | 100% |
graph\tests.py | (no class) | 19 | 1 | 0 | 95% |
graph\signals.py | (no class) | 5 | 0 | 0 | 100% |
graph\models.py | Graph | 1 | 0 | 0 | 100% |
graph\models.py | Graph.Meta | 0 | 0 | 0 | 100% |
graph\models.py | (no class) | 22 | 0 | 0 | 100% |
graph\apps.py | GraphConfig | 21 | 19 | 0 | 10% |
graph\apps.py | (no class) | 6 | 0 | 0 | 100% |
graph\admin.py | (no class) | 3 | 0 | 0 | 100% |
diary\views.py | (no class) | 26 | 0 | 0 | 100% |
diary\urls.py | (no class) | 3 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests | 49 | 0 | 0 | 100% |
diary\tests.py | (no class) | 24 | 1 | 0 | 96% |
diary\signals.py | (no class) | 9 | 0 | 0 | 100% |
diary\models.py | Diary | 18 | 0 | 0 | 100% |
diary\models.py | Diary.Meta | 0 | 0 | 0 | 100% |
diary\models.py | DiaryImg | 7 | 3 | 0 | 57% |
diary\models.py | DiaryImg.Meta | 0 | 0 | 0 | 100% |
diary\models.py | (no class) | 33 | 0 | 0 | 100% |
diary\apps.py | DiaryConfig | 30 | 28 | 0 | 7% |
diary\apps.py | (no class) | 6 | 0 | 0 | 100% |
diary\admin.py | (no class) | 4 | 0 | 0 | 100% |
backEnd\urls.py | (no class) | 6 | 0 | 0 | 100% |
backEnd\tools.py | (no class) | 3 | 0 | 0 | 100% |
backEnd\settings.py | (no class) | 29 | 0 | 0 | 100% |
account\views.py | (no class) | 18 | 0 | 0 | 100% |
account\urls.py | (no class) | 3 | 0 | 0 | 100% |
account\tests.py | AccountAPITests | 36 | 0 | 0 | 100% |
account\tests.py | (no class) | 22 | 1 | 0 | 95% |
account\models.py | Account | 1 | 0 | 0 | 100% |
account\models.py | Account.Meta | 0 | 0 | 0 | 100% |
account\models.py | (no class) | 15 | 0 | 0 | 100% |
account\migrations\0002_initial.py | Migration | 0 | 0 | 0 | 100% |
account\migrations\0002_initial.py | (no class) | 6 | 0 | 0 | 100% |
account\migrations\0001_initial.py | Migration | 0 | 0 | 0 | 100% |
account\migrations\0001_initial.py | (no class) | 6 | 0 | 0 | 100% |
account\apps.py | AccountConfig | 0 | 0 | 0 | 100% |
account\apps.py | (no class) | 4 | 0 | 0 | 100% |
account\admin.py | (no class) | 3 | 0 | 0 | 100% |
Total | 954 | 94 | 0 | 90% |
File | function | statements | missing | excluded | coverage |
---|---|---|---|---|---|
path\views.py | get | 19 | 11 | 0 | 42% |
path\views.py | add | 29 | 14 | 0 | 52% |
path\views.py | delete | 20 | 11 | 0 | 45% |
path\views.py | (no function) | 16 | 0 | 0 | 100% |
path\urls.py | (no function) | 3 | 0 | 0 | 100% |
path\tests.py | PathAPITests.setUp | 8 | 0 | 0 | 100% |
path\tests.py | PathAPITests.get_token | 1 | 0 | 0 | 100% |
path\tests.py | PathAPITests.test_get_paths | 5 | 0 | 0 | 100% |
path\tests.py | PathAPITests.test_add_path | 6 | 0 | 0 | 100% |
path\tests.py | PathAPITests.test_add_path_invalid | 5 | 0 | 0 | 100% |
path\tests.py | PathAPITests.test_delete_path | 6 | 0 | 0 | 100% |
path\tests.py | (no function) | 21 | 1 | 0 | 95% |
path\models.py | Path.dict_type | 1 | 0 | 0 | 100% |
path\models.py | (no function) | 12 | 0 | 0 | 100% |
path\migrations\0001_initial.py | (no function) | 6 | 0 | 0 | 100% |
path\apps.py | (no function) | 4 | 0 | 0 | 100% |
path\admin.py | (no function) | 3 | 0 | 0 | 100% |
myapp\views\index\user.py | LoginView.post | 22 | 4 | 0 | 82% |
myapp\views\index\user.py | changePassword | 21 | 4 | 0 | 81% |
myapp\views\index\user.py | ChangePasswordView.post | 21 | 21 | 0 | 0% |
myapp\views\index\user.py | RegisterView.post | 22 | 4 | 0 | 82% |
myapp\views\index\user.py | generate_token | 4 | 0 | 0 | 100% |
myapp\views\index\user.py | mod_power | 8 | 0 | 0 | 100% |
myapp\views\index\user.py | get_user_by_token | 10 | 3 | 0 | 70% |
myapp\views\index\user.py | (no function) | 26 | 0 | 0 | 100% |
myapp\views\index\secure.py | EncryptedService.post | 4 | 0 | 0 | 100% |
myapp\views\index\secure.py | get_server_private_key | 1 | 0 | 0 | 100% |
myapp\views\index\secure.py | store_server_private_key | 1 | 0 | 0 | 100% |
myapp\views\index\secure.py | decrypt_password | 5 | 0 | 0 | 100% |
myapp\views\index\secure.py | mod_power | 8 | 0 | 0 | 100% |
myapp\views\index\secure.py | (no function) | 16 | 0 | 0 | 100% |
myapp\urls.py | (no function) | 3 | 0 | 0 | 100% |
myapp\tests.py | EncryptionTests.setUp | 1 | 0 | 0 | 100% |
myapp\tests.py | EncryptionTests.mod_power | 8 | 0 | 0 | 100% |
myapp\tests.py | EncryptionTests.encrypt_password | 4 | 0 | 0 | 100% |
myapp\tests.py | EncryptionTests.test_register_and_login | 26 | 0 | 0 | 100% |
myapp\tests.py | (no function) | 14 | 0 | 0 | 100% |
myapp\models\user.py | (no function) | 16 | 0 | 0 | 100% |
myapp\apps.py | (no function) | 4 | 0 | 0 | 100% |
myapp\admin.py | (no function) | 3 | 0 | 0 | 100% |
marker\views.py | get | 24 | 14 | 0 | 42% |
marker\views.py | add | 19 | 10 | 0 | 47% |
marker\views.py | modify | 30 | 11 | 0 | 63% |
marker\views.py | delete | 20 | 11 | 0 | 45% |
marker\views.py | (no function) | 17 | 0 | 0 | 100% |
marker\urls.py | (no function) | 3 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests.setUp | 6 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests.get_token | 1 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests.test_get_markers | 5 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests.test_add_marker | 6 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests.test_modify_marker | 9 | 0 | 0 | 100% |
marker\tests.py | MarkerAPITests.test_delete_marker | 6 | 0 | 0 | 100% |
marker\tests.py | (no function) | 20 | 1 | 0 | 95% |
marker\models.py | Marker.dict_type | 1 | 0 | 0 | 100% |
marker\models.py | Marker.save | 6 | 0 | 0 | 100% |
marker\models.py | Marker.delete | 6 | 0 | 0 | 100% |
marker\models.py | Marker.colorEncode | 8 | 8 | 0 | 0% |
marker\models.py | Marker.colorDecode | 2 | 2 | 0 | 0% |
marker\models.py | (no function) | 23 | 0 | 0 | 100% |
marker\migrations\0001_initial.py | (no function) | 6 | 0 | 0 | 100% |
marker\apps.py | (no function) | 4 | 0 | 0 | 100% |
marker\admin.py | (no function) | 3 | 0 | 0 | 100% |
manage.py | main | 6 | 2 | 0 | 67% |
manage.py | (no function) | 5 | 0 | 0 | 100% |
graph\views.py | get | 25 | 15 | 0 | 40% |
graph\views.py | add | 27 | 8 | 0 | 70% |
graph\views.py | modify | 63 | 28 | 0 | 56% |
graph\views.py | delete | 18 | 9 | 0 | 50% |
graph\views.py | (no function) | 18 | 0 | 0 | 100% |
graph\urls.py | (no function) | 3 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests.setUp | 5 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests.get_token | 1 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests.test_get_graphs | 5 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests.test_add_graph | 6 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests.test_modify_graph | 13 | 0 | 0 | 100% |
graph\tests.py | GraphAPITests.test_delete_graph | 6 | 0 | 0 | 100% |
graph\tests.py | (no function) | 19 | 1 | 0 | 95% |
graph\signals.py | post_graph_delete | 1 | 0 | 0 | 100% |
graph\signals.py | (no function) | 5 | 0 | 0 | 100% |
graph\models.py | Graph.dict_type | 1 | 0 | 0 | 100% |
graph\models.py | (no function) | 22 | 0 | 0 | 100% |
graph\migrations\0001_initial.py | (no function) | 6 | 0 | 0 | 100% |
graph\apps.py | GraphConfig.ready | 21 | 19 | 0 | 10% |
graph\apps.py | (no function) | 6 | 0 | 0 | 100% |
graph\admin.py | (no function) | 3 | 0 | 0 | 100% |
diary\views.py | get | 23 | 14 | 0 | 39% |
diary\views.py | add | 24 | 11 | 0 | 54% |
diary\views.py | modify | 40 | 15 | 0 | 62% |
diary\views.py | delete | 20 | 11 | 0 | 45% |
diary\views.py | upload_image | 31 | 16 | 0 | 48% |
diary\views.py | get_image | 15 | 15 | 0 | 0% |
diary\views.py | delete_image | 22 | 11 | 0 | 50% |
diary\views.py | (no function) | 26 | 0 | 0 | 100% |
diary\urls.py | (no function) | 3 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.setUp | 7 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.get_token | 1 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.test_get_diaries | 5 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.test_add_diary | 6 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.test_modify_diary | 9 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.test_delete_diary | 6 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.test_upload_image | 6 | 0 | 0 | 100% |
diary\tests.py | DiaryAPITests.test_delete_image | 9 | 0 | 0 | 100% |
diary\tests.py | (no function) | 24 | 1 | 0 | 96% |
diary\signals.py | post_diary_delete | 2 | 0 | 0 | 100% |
diary\signals.py | post_diaryImg_delete | 1 | 0 | 0 | 100% |
diary\signals.py | (no function) | 9 | 0 | 0 | 100% |
diary\models.py | Diary.dict_type | 1 | 0 | 0 | 100% |
diary\models.py | Diary.save | 9 | 0 | 0 | 100% |
diary\models.py | Diary.delete | 8 | 0 | 0 | 100% |
diary\models.py | DiaryImg.save | 3 | 0 | 0 | 100% |
diary\models.py | DiaryImg.img | 3 | 3 | 0 | 0% |
diary\models.py | DiaryImg.get_new_random_name | 1 | 0 | 0 | 100% |
diary\models.py | (no function) | 33 | 0 | 0 | 100% |
diary\migrations\0002_initial.py | (no function) | 6 | 0 | 0 | 100% |
diary\migrations\0001_initial.py | (no function) | 6 | 0 | 0 | 100% |
diary\apps.py | DiaryConfig.ready | 30 | 28 | 0 | 7% |
diary\apps.py | (no function) | 6 | 0 | 0 | 100% |
diary\admin.py | (no function) | 4 | 0 | 0 | 100% |
backEnd\urls.py | (no function) | 6 | 0 | 0 | 100% |
backEnd\tools.py | stringToDate | 6 | 1 | 0 | 83% |
backEnd\tools.py | (no function) | 3 | 0 | 0 | 100% |
backEnd\settings.py | (no function) | 29 | 0 | 0 | 100% |
account\views.py | get | 20 | 11 | 0 | 45% |
account\views.py | add | 22 | 13 | 0 | 41% |
account\views.py | modify | 41 | 13 | 0 | 68% |
account\views.py | delete | 20 | 11 | 0 | 45% |
account\views.py | (no function) | 18 | 0 | 0 | 100% |
account\urls.py | (no function) | 3 | 0 | 0 | 100% |
account\tests.py | AccountAPITests.setUp | 7 | 0 | 0 | 100% |
account\tests.py | AccountAPITests.get_token | 1 | 0 | 0 | 100% |
account\tests.py | AccountAPITests.test_get_accounts | 5 | 0 | 0 | 100% |
account\tests.py | AccountAPITests.test_add_account | 6 | 0 | 0 | 100% |
account\tests.py | AccountAPITests.test_modify_account | 11 | 0 | 0 | 100% |
account\tests.py | AccountAPITests.test_delete_account | 6 | 0 | 0 | 100% |
account\tests.py | (no function) | 22 | 1 | 0 | 95% |
account\models.py | Account.dict_type | 1 | 0 | 0 | 100% |
account\models.py | (no function) | 15 | 0 | 0 | 100% |
account\apps.py | (no function) | 4 | 0 | 0 | 100% |
account\admin.py | (no function) | 3 | 0 | 0 | 100% |
Total | 1600 | 387 | 0 | 76% |
/api/graph/add
/api/marker/add
/api/graph/modify
/api/marker/modify
/api/path/add
/api/marker/add
/api/diary/modify
/api/diary/add
/api/account/add
/api/account/modify
项目前后端仓库均实现了 CI/CD,实现理由:
前端
前端的CI/CD,实现人员私以为比较优雅(嘿嘿),基本实现工具囊括了Github Actions、Docker、nginx,过程可以分为以下几个阶段:
后端
后端的CI/CD比较丑陋,但怎么说呢,反正能用(),基本实现工具包括Github Actions、uwsgi,过程可以分为以下几个阶段:
在Beta阶段中,团队成员收获良多,无论是从团队开发协作过程中的收获还是测试对接过程中的教训,都可以成为成员此后适应团队开发的宝贵财富。