隔壁老王都知道的JavaScript+mysql+HTML+CSS的客户管理系统设计和实现【建议收藏,不然看着看着就不见了

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 隔壁老王都知道的JavaScript+mysql+HTML+CSS的客户管理系统设计和实现【建议收藏,不然看着看着就不见了

隔壁老王都知道的JavaScript+mysql+HTML+CSS的客户管理系统设计和实现【建议收藏,不然看着看着就不见了】


🏳️‍🌈目录


🍇1、前言

🍈1.1、需求分析

🍉1.1.1、功能性需求分析

🍊1.1.2、非功能性需求

🍋1.1.3、编写目的

🍌1.1.4项目背景

🏳️‍🌈1.2、可行性分析

🍍1.2.1、技术可行性

🥭1.2.2、经济可行性

🍎1.2.3、社会可行性

🏳️‍🌈1.3、系统结构设计与功能分析

🍏1.3.1、系统结构设计

🍐1.3.2、功能设计

🍑1.3.3、数据设计

🍒1.3.4、系统用途介绍

🍓1.3.5系统界面设计

🏳️‍🌈1.4、开发语言介绍

🥝1.4.1、NodeJS介绍

🏳️‍🌈1.5、HTML和 CSS网页编程语言介绍

🍅1.5.1、html 语言的介绍

🥥1.5.2、CSS的介绍

🏳️‍🌈1.6、JavaScript 编程语言介绍

🥑1.6.1、JavaScript介绍

🏳️‍🌈1.7、系统流程图

🍆1.7.1、系统功能模块图

🏳️‍🌈1.8、系统开发工具和运行环境

🏳️‍🌈1.9、软件技术要求

🏳️‍🌈1.10、系统安全问题

🏳️‍🌈2、系统测试

🥔2.1、系统测试目的

🥕2.2、软件测试的环境


关注苏州程序大白,持续更新技术分享。谢谢大家支持


🏳️‍🌈目录

😊开讲啦!!!!


20210617085340404.gif


🍇1、前言


当今社会为信息社会,世界已进入在计算机信息管理领域中激烈竞争的时代。信息已成为继劳动力、土地、资本之后的又一大资源,谁控制的信息越多,谁利用信息资源的效率越高,谁就会在各方面的竞争中,占有一席之地,谁就会更有优势,这一点已得到举世公认。


随着世界贸易组织的加入和我国工业的迅猛发展,为了抓住机遇,在竞争中占得先机,作为生产企业的一个必不可少的重要环节一库存管理的信息化、计算机化也就迫在眉捷了。开发库存管理信息系统即有宏观上的意义,那就是顺应时代信息化、现代化潮流,提高效益,促进国民经济结构优化;也有微观上的意义,那就是可以提高管理的现代化程序,加强管理的信息化手段,提高工作效率,增加单位效益。


随着计算机技术的发展,计算机应用于管理的必要性和优越性益显示出来,它不仅大大提高了管理事务的处理速度,还提高了处理的质量,成为一个企业高效运转的重要支柱之一。


借助现代信息技术和管理理论,建立客户管理系统是当今社会的重要趋势。党和政府根据知识经济时代的特点,对国民经济建设提出了“用信息化带动工业化”的指导思想。对企业而言,全面开发和应用计算机管理信息系统就是近期不能回避的问题。


在企业管理中,客户是企业的“生命线”,因此客户管理是企业的计算机管理信息系统重要组成部分度设计的客户管理软件,本文介绍的研究工作就是要为这些具有中国特色的中小企业解决他们在客户管理方面的问题。


世纪90年代以来客户关系管理开始在企业界流行起来,客户关系管理已成为企业界的聚焦,有其重要的战略意义和深层次的含义。在中国加入WTO之后,环境发生了很大的变化,企业如何定位自己已成为一个不可回避的问题,战略问题愈发重要。从战略意义上理解客户关系管理,有助于企业村客户关系管理的深层次理解。


现代企业以逐步由传统的以产品和规模为中心的粗放式经营管理模式向以客户为中心,服务至上,实现客户价值和达到企业利润最大化的集约化经营管理模式转变,良好的客户关系是企业求得生存与发展的重要资源。企业如何实现对多渠道销售与服务的集成、统一管理,就需要有一套完整的客户关系管理的理论与技术实现手段提高客户满意度,改善客户关系,从而提高企业的竞争力。


🍈1.1、需求分析


🍉1.1.1、功能性需求分析


对一个公司实施客户关系管理是很有必要的。客户管理系统包括客户信息维护系统和客户信息查询系统。


有客户系统管理系统权限的业务员可登录进入客户信息维护系统,进入客户信息维护子系统之后,业务员通过计算机来管理各类客户实现对客户信息录入、客户信息修改、客户信息删除操作,但是没有将客户信息移动复制的权利,只有超级管理员可以进行该项操作。没有管理权限的一般客户可以登录进入客户信息查询系统实现对客户的按编号查询、按姓名查询、按所客户信息录入时间等查询操作。


客户信息管理系统是一种用于存储企业客户信息资源,便于与客户及时沟通交流,来增强与客户关系、提高企业管理水平的系统。企业可以通过客户信息管理系统管理、分析和统计现有客户资源,以便快速、全面、准确的了解现有企业客户情况,从而制定长期客户沟通和访问计划,制定营销战略,促进企业长期、良性经营发展。


客户管理系统可以帮助企业充分利用客户关系资源,扩展新的市场和业务渠道,提高顾客满意度和企业的盈利能力,是企业在激烈的竞争中得以立足和发展。


客户管理系统包括客户信息的录入,修改,删除。客户信息得浏览包括:按“客户编码”查询客户信息,按“客户姓名”或“录入时间”查询客户信息等。


客户是公司最宝贵的资源,为了更好的发掘老客户的价值,并开发更多新客户,管理公司的日常交往。


对一个公司实施客户关系管理是很有必要的根据用户的需求及以上的简单分析,用户管理系统需要具备前台功能和后台功能:


( 1) 系统前台功能:


未注册用户: 1. 新用户注册 2.浏览主页


已注册用户: 1. 用户登陆 2.工单系统 3.功能包括权限验证 4.登陆 5.修改客户信息 6.增加客户 7.删除客户非物理删除 8.条件查询 9.导出客户资料


( 2) 系统后台功能:


管理员:


1.管理员资料管理:管理员信息


2.用户信息管理:信息浏览、删除;


3.安全退出


4.其他


🍊1.1.2、非功能性需求


(1)时间特性要求:该软件要求加载页面时间不超过30 秒,上传下载速度不少于10kb/s ;


(2)灵活性:要求用户输入简洁,操作方便;


(3)输入输出要求:


         1. 用户名称不超过 20 个字符;
         2. 每次信息不超过 500 个字符;


(4)数据管理能力要求:必须做到用户同时在线超过万级的规模;


(5)故障处理要求:服务器出现故障,要求需要备份主机,在一分钟之内可以切换。

![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20210617103653886.gif#pic_center


🍋1.1.3、编写目的


对一个公司实施客户关系管理是很有必要的。客户管理系统包括客户信息维护系统和客户信息查询系统。有客户系统管理系统权限的业务员可登录进入客户信息维护系统,进入客户信息维护子系统之后,业务员通过计算机来管理各类客 户实现对客户信息录入、客户信息修改、 客户信息删除操作,但是没有将客户信息移动复制的权利,只有超级管理员可以进行该项操作。


没有管理权限的一般客户可以登录进入客户信息查询系统实现对客户的按编号查询、按姓名查询、 按所客户信息录入时间等查询操作。客户信息管理系统是一种用于存储企业客户信息资源,便于与客户及时沟通交流, 来增强与客户关系、 提高企业管理水平的系统。


企业可以通过客户信息管理系统管理、分析和统计现有客户资源,以便快速、 全面、准确的了解现有企业客户情况,从而制定长期客户沟通和访问计划,制定营销战略, 促进企业长期、良性经营发展。客户管理系统可以帮助企业充分利用客户关系资源, 扩展新的市场和业务渠道,提高顾客满意度和企业的盈利能力,是企业在激烈的竞争中得以立足和发展。


🍌1.1.4项目背景


客户信息管理系统是一种用于存储企业客户信息资源,便于与客户及时沟通交流,来增强与客户关系、 提高企业管理水平的系统。企业可以通过客户信息管理系统管理、分析和统计现有客户资源,以便快速、全面、准确的了解现有企业 客户情况,从而制定长期客户沟通和访问计划,制定营销战略,促进企业长期、良性经营发展。


客户关系管理系统(CRM)是以客户数据的管理为核心,利用信息科学技术,实现市场营销、销售、服务等活动自动化,并建立一个客户信息的收集、管理、分析、利用的系统,帮助企业实现以客户为中心的管理模式。客户关系管理既是一种管理理念,又是一种软件技术。


客户关系管理系统主要有高可控性的数据库、更高的安全性、数据实时更新等特点,提供日程管理、订单管理、发票管理、知识库管理等功能。


“以客户为中心”,提高客户满意度,培养、维持客户忠诚度,在今天这个电子商务时代显得日益重要。客户关系管理正是改善企业与客户之间关系的新型管理机制,越来越多的企业运用CRM来增加收入、优化赢利性、提高客户满意度。


最早发展客户关系管理的国家是美国,这个概念最初由Gartner Group提出来,在1980年初便有所谓的“接触管理”(Contact Management),即专门收集客户与公司联系的所有信息,到1990年则演变成包括电话服务中心支持资料分析的客户关怀(Customer care)。开始在企业电子商务中流行。


CRM系统的宗旨是:为了满足每个客户的特殊需求,同每个客户建立联系,通过同客户的联系来了解客户的不同需求,并在此基础上进行"一对一"个性化服务。通常CRM包括销售管理、市场营销管理、客户服务系统以及呼叫中心等方面。


CRM(Customer Relationship Management)–客户关系管理,是一种以"客户关系一对一理论"为基础,旨在改善企业与客户之间关系的新型管理机制。客户关系管理的定义是:企业为提高核心竞争力,利用相应的信息技术以及互联网技术来协调企业与顾客间在销售、营销和服务上的交互,从而提升其管理方式,向客户提供创新式的个性化的客户交互和服务的过程。其最终目标是吸引新客户、保留老客户以及将已有客户转为忠实客户,增加市场份额。


统计数据表明,2008年中小企业CRM市场的规模已达8亿美元。在随后五年中,这一市场将快速增长至18亿美元,在整个CRM市场中占比达30%以上。


CRM系统主要包含传统CRM系统和在线CRM系统。


1、帐号自由设置,用户数量不限


2、 永久性使用,不限使用期限,终身免费的技术支持


3、完全独立的管理平台,不需要租用任何的服务器,可以将其安装在您需要的任何地方


4、基于B/S架构,互联网、局域网、本地电脑皆可使用,不需安装客户端,可无限范围覆盖


5、强大的数据管理和统计分析功能,可根据建立的各种不同的信息,并快速查询出所需要的统计信息和相对应的柱状图、折线图、饼图


6、独立的团队管理系统,使您对整个企业、整个团队情况一目了然。


7、CRM为企业构建了一整套以客户为中心的有关客户、营销、销售、服务与支持信息的数据库,帮助企业了解管理渠道,建立和优化了前端业务流程,包括市场营销、销售、产品的服务与支持、呼叫中心等。该系统可以进行深层次分析和挖掘,从而发现最有价值的客户、新的市场和潜在的客户,创造业务良机。该系统可扩展、可连接的特性可以与企业的SCM、ERP系统无缝集成,实现实时的数据交换,增强企业与供应商、合作伙伴、客户间的关系,加快客户服务与支持响应速度,增强企业在电子商务时代的竞争优势。


8、销售机会的跟踪,可以方便了解每一个销售机会的跟进情况。快速制定客户的跟进策略。——并且在销售机会的详细页可以看到联系活动、报价单、签约单、服务单的明细情况。


🏳️‍🌈1.2、可行性分析


可行性分析是基于在系统调查,是否为新系统开发的必要性和可能性,对新系统的研究和发展的分析,从技术,经济,和社会方面,为了避免投资失误,保证新的开发价值。 可行性分析的目的在于用最小的投入在最短的时间内保证问题是否可以解决。


软件可行性分析是通过对项目的市场需求、资源供应、建设规模、工艺路线、设备选型、环境影响、资金筹措、盈利能力等方面的研究,从技术、经济、工程等角度对项目进行调查研究和分析比较,并对项目建成以后可能取得的财务、经济效益及社会环境影响进行科学预测,为项目决策提供公正、可靠、科学的软件咨询意见。


软件可行性分析是通过对项目的市场需求、资源供应、建设规模、工艺路线、设备选型、环境影响、资金筹措、盈利能力等方面的研究,从技术、经济、工程等角度对项目进行调查研究和分析比较,并对项目建成以后可能取得的财务、经济效益及社会环境影响进行科学预测,为项目决策提供公正、可靠、科学的软件咨询意见。主要从经济、技术、社会环境等方面分析所给出的解决方案是否可行,当解决方案可行并有一定的经济效益和/或社会效益是才开始真正的基于计算机的系统的开发。


就是用最小的代价在尽可能短的时间内确定问题是否能够解决。要达到这个目的,必须分析几种主要的可能解法的利弊,从而判断原定的系统规模和目标是否现实,系统完成后所能带来的效益是否大到值得投资开发这个系统的程度。因此,可行性研究实质上是要进行一次大大压缩简化了的系统分析和设计的过程,也就是在较高层次上以较抽象的方式进行的系统分析和设计的过程。


本系统考虑系统组成各环的功能需求,基于使用成熟技术和实用化的原则,向最终用户提供一套先进的应用系统。这套系统应该具有最先进的技术特征;配置必要的数据库和应用服务程序;组织完整的管理员操作界面。软件系统的界面要美观,布局要合理,窗口的内容尽量简单明了提供的信息,语言要通俗易懂,有层次感,分类要清晰明了。使能够快捷的录入和读取及清楚的看到目前客户的信任度,切保密性能极高!


20210617103710531.gif


🍍1.2.1、技术可行性


技术可行性分析主要分析技术条件是否能够进行开发,硬件、软件条件是否达到研发组的需求等。


超文本标记语言(Hyper Text Markup Language),缩写为HTML,标准通用标记语言下的一个应用。HTML不是一种编程语言,而是一种标记语言 (markup language),是网页制作所必备的工具。“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。


超文本标记语言(或超文本标签语言)的结构包括“头”部分和“主体”部分,其中“头”部提供关于网页的信息,“主体”部分提供网页的具体内容。


JavaScript(缩写为JS)是一种高级的、多范式、解释型的编程语言,是一门基于原型、函数先行的语言,它支持面向对象编程、命令式编程以及函数式编程。它提供语法来操控文本、数组、日期以及正则表达式,不支持I/O(比如网络、存储和图形等),但可以由它的宿主环境提供支持。它已经由ECMA(欧洲计算机制造商协会)通过ECMAScript实现语言的标准化。它被世界上的绝大多数网站所使用,也被世界主流浏览器支持。


层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。


CSS 能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力。


node.js是一个让JavaScript运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言,发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。


node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。V8引擎执行Javascript的速度非常快,性能非常好。


MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,属于Oracle旗下产品,是最流行的关系型数据库管理系统之一。MySQL所使用的SQL语言是用于访问数据库的最常用标准化语言,由于其体积小、速度快、开放源码等特点,一般中小型网站的开发都选择MySQL作为网站数据库。


SQL是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而建立的操作命令集,是一种功能齐全的数据库语言。在使用时,只需要发出“做什么”的命令,“怎么做”是不用使用者考虑的。SQL功能强大、简单易学、使用方便,已经成为了数据库操作的基础,并且现在几乎所有的数据库均支持SQL。SQL数据库数据体系结构:SQL数据库的数据体系结构基本上是三级结构,但使用术语与传统关系模型术语不同。在SQL中,关系模式(模式)称为“基本表”(base table);存储模式(内模式)称为“存储文件”( stored file)子模式(外模式)称为“视图”( view);元组称为“行”(row);属性称为“列”( column)。


🥭1.2.2、经济可行性


经济可行性主要评价项目的经济效益,本客户管理系统模拟的是客户管理系统网络平台, 为用户们提供更多的选择。但实际只是用于个人的设计,以模拟为主, 不存在过大的资金的流动,所以在经济上是可行的。


预算费用的支出:基建投资,这是比不可少的,由于原油基础性资源完好,因此这部分投是很少的;新的开发工具和软件环境的购买和新的服务器和服务器操作系统的购买;开发人员的支出,服务器维护费用等。


收益:系统对内部员工工作流程的优化使公司得以精简人员,节约人力成本,以及客户关系管理成本;系统为外部顾客提供良好的服务而带来的销售量增加,使得日常收入增加;总之只要市场反映良好,在长期内,收益定会大于支出,取得额外收益。对而日可行性的结论。


🍎1.2.3、社会可行性


在目前市场经济的环境下,企业的管理者不仅仅需要掌握客户信息,还需要高效的存储以及读取和安全的防护措施来保护客户信息不受非法用户或未授权用户的窃取!


基于企业管理者管理自己客户的需求,本系统能满足管理者的安全需求的同时采用简洁的操作增加新客户信息和删除不良客户的信息,并能够形成客户信任度的评比曲线,能更理性的做出制胜的决策!


🏳️‍🌈1.3、系统结构设计与功能分析


🍏1.3.1、系统结构设计


本文是基于 Browser/Server 模式的一种 HTML结合 Java 的客户管理系统的设计与实现,主要功能是达到客户端和客户端通过服务器的动态交互。


B/S架构即浏览器和服务器架构模式,是随着Internet技术的兴起,对C/S架构的一种变化或者改进的架构。在这种架构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。


B/S架构是WEB兴起后的一种网络架构模式,WEB浏览器是客户端最主要的应用软件。这种模式统一了客户端,将系统功能实现的核心部分集中到服务器上,简化了系统的开发、维护和使用。


客户机上只要安装一个浏览器(Browser),如Netscape Navigator或Internet Explorer,服务器安装Oracle、Sybase、Informix或SQL Server等数据库。浏览器通过Web Server同数据库进行数据交互。


这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。随着网络技术的发展,特别随着Web技术的不断成熟,B/S 这种软件体系结构出现了。


B/S(Browser/Server)架构也被称为浏览器/服务器体系结构,这种体系结构可以理解为是对 C/S 体系结构的改变和促进。由于网络的快速发展,B/S 结构的功能越来越强大。这种结构可以进行信息分布式处理,可以有效降低资源成本,提高设计的系统性能。


B/S 架构是有更广的应用范围,在处理模式上大大简化了客户端,用户只需安装浏览器即可,而将应用逻辑集中在服务器和中间件上,可以提高数据处理性能。


在软件的通用性上,B/S 架构的客户端具有更好的通用性,对应用环境的依赖性较小,同时因为客户端使用浏览器,在开发维护上更加便利,可以减少系统开发和维护的成本。


面向未来,连排级单位可通过掌上电脑(安卓系统),在训练场、演习场等环境下访问并使用该系统。


B/S 的特征和基本结构:在 B/S 结构中,每个节点都分布在网络上,这些网络节点可以分为浏览器端、服务器端和中间件,通过它们之间的链接和交互来完成系统的功能任务。


三个层次的划分是从逻辑上分的,在实际应用中多根据实际物理网络进行不同的物理划分。


浏览器端:即用户使用的浏览器,是用户操作系统的接口,用户通过浏览器界面向服务器端提出请求,并对服务器端返回的结果进行处理并展示,通过界面可以将系统的逻辑功能更好的表现出来。


服务器端:提供数据服务,操作数据,然后把结果返回中间层,结果显示在系统界面上。


中间件:这是运行在浏览器和服务器之间的。这层主要完成系统逻辑,实现具体的功能,接受用户的请求并把这些请求传送给服务器,然后将服务器的结果返回给用户,浏览器端和服务器端需要交互的信息是通过中间件完成的。


😊前面废话有点多了!!!后面我们开始讲解。发车····


20210617091500179.gif


🍐1.3.2、功能设计


已注册用户功能:


20210617091202335.png


系统功能模块图如下:


20210617091231317.png


系统功能如下:



用户登录功能部分代码:


20210617091258507.png


用户点击登录,通过不同得账号登录系统从而得到不同得权限。


用户登录功能部分代码:


async userLogin() {
            const {
                  ctx
            } = this;
            const bodyData = ctx.request.body;
            try {
                  let results = await this.app.mysql.get("users", {
                        phone: bodyData.phone,
                        password: bodyData.password
                  });
                  if (!results) {
                        throw "密码错误"
                  }
                  if (results.type === "3") {
                        throw "账号冻结"
                  }
                  let jwtParms = {
                        userId: results.userId
                  }
                  let token = await ctx.helper.signJwt(jwtParms)
                  let resData = {
                        type: results.type,
                        token: token
                  }
                  const row = {
                        id: results.id,
                        lastFunTime: moment().format('YYYY-MM-DD HH:mm:ss')
                  };
                  await await this.app.mysql.update('users', row)
                  return ctx.helper.results(200, "成功", resData);
            } catch (error) {
                  return ctx.helper.results(401, error);
            }
      }


权限验证代码如下:


async registered() {
            const {
                  ctx
            } = this;
            const bodyData = ctx.request.body;
            try {
                  if (!(/^1[3456789]\d{9}$/.test(bodyData.phone))) {
                        throw '注册失败,手机号格式不符合';
                  }
                  if (!(/^[a-zA-Z0-9]{8,30}$/.test(bodyData.password))) {
                        throw '注册失败,密码长度必须为8位以上';
                  }
                  if (bodyData.code) {
                        const postCode = await this.app.mysql.get('users', {
                              userId: bodyData.code
                        });
                        if (!postCode) {
                              throw "邀请码无效";
                        }
                  }
                  const post = await this.app.mysql.get("users", {
                        phone: bodyData.phone,
                  });
                  // 判断手机号码是否存在存在就则修改密码
                  if (post) {
                        throw "手机号码已被注册";
                  }
                  let userId = new Date().getTime() + Math.random().toString().substr(2, 4);
                  const result = await this.app.mysql.insert("users", {
                        userId: userId,
                        phone: bodyData.phone,
                        password: bodyData.password,
                        invitation: bodyData.code || ''
                  }); // 在 post 表中,插入 title 为 Hello World 的记录
                  if (result.affectedRows == 1) {
                        return ctx.helper.results(200, "请求成功", "注册成功");
                  } else {
                        throw '网络错误';
                  }
            } catch (err) {
                  return ctx.helper.results(204, err);
            }
      }


查询功能:


用户点击查询之后能进行查询用户表的存储信息,精细的查询出所有用户的精准数据,具有优美的UI界面和查询界面。


20210617091605508.png


查询功能部分代码:


async getUsers() {
            const { ctx } = this;
            const bodyData = ctx.request.query;
            // 获取总条数
            try {
                  let regularData = await ctx.helper.regularData([{ o: bodyData.pageSize, n: "pageSize", t: "n", isUnMust: true }, { o: bodyData.pageNo, n: "pageNo", t: "n", isUnMust: true }])
                  if (regularData.code !== 200) {
                        throw regularData.msg;
                  }
                  /**
                   * 特殊字段含义
                   * pageSize:每一页的条数
                   * pageNo:页码
                   * start_startTime :查询创建时间某段时间之前  
                   * start_endTime :查询创建时间某段时间之后
                   * 举例 查询'2017-1-1 00:00:00 - 2018-1-1 00:00:00'的数据 {start_startTime:'2017-1-1 00:00:00',start_endTime'2018-1-1 00:00:00'}
                   * end_startTime :查询‘结束时间’某段时间之前
                   * end_endTime :查询‘结束时间’某段时间之后
                   * 举例 查询'2017-1-1 00:00:00 - 2018-1-1 00:00:00'的数据 {end_startTime'2017-1-1 00:00:00',end_endTime'2018-1-1 00:00:00'}
                   * 其他:
                   * 1:插入某个字段则动态模糊查询该字段属性,不能插入错误字段,否则报sql错误
                   * 2:'默认'
                   */
                  let selectTxt = 'delTime is not null'
                  for (const iterator in bodyData) {
                        switch (iterator) {
                              case 'pageSize':
                                    break;
                              case 'pageNo':
                                    break;
                              case 'start_startTime':
                                    selectTxt = selectTxt + ` and createTime <= '${bodyData[iterator]}'`
                                    break;
                              case 'start_endTime':
                                    selectTxt = selectTxt + ` and createTime >= '${bodyData[iterator]}'`
                                    break;
                              case 'end_startTime':
                                    selectTxt = selectTxt + ` and endTime <= '${bodyData[iterator]}'`
                                    break;
                              case 'end_endTime':
                                    selectTxt = selectTxt + ` and endTime >= '${bodyData[iterator]}'`
                                    break;
                              default:
                                    selectTxt = selectTxt + ` and ${iterator} like '%${bodyData[iterator]}%'`
                                    break;
                        }
                  }
                  //查询总条数
                  var totalRecord = await this.app.mysql.query(`select count(id) from users;`);
                  totalRecord = totalRecord[0]["count(id)"];
                  bodyData.pageSize = bodyData.pageSize || 10;
                  bodyData.pageNo = bodyData.pageNo || 1;
                  let limit = (bodyData.pageNo - 1) * bodyData.pageSize;
                       let  result = await this.app.mysql.query(`select * from users where ${selectTxt} limit ?, ? `, [limit, Number(bodyData.pageSize)]);
                  console.log(result);
                  const rTime = (date) => {
                        var json_date = new Date(date).toJSON();
                        console.log(111);
                        return new Date(new Date(json_date) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/.[d]{3}Z/, '')
                  }
                  result = result.map((res) => {
                        let keyList = Object.keys(res)
                        keyList.map((result) => {
                              console.log(result);
                              if (result.indexOf('Time') !== -1 && result !=='delTime') {
                                    // console.log(a.length);
                                    let time = res[result];
                                    console.log(time);
                                    res[result] = new Date(time).toISOString().replace(/T/g, ' ').replace(/.[d]{3}Z/, '').substring(0, 19)
                              }
                        })
                        return res
                  })
                  let prams = {
                        pageSize: bodyData.pageSize,
                        // pageNo: bodyData.pageNo,
                        // totalRecord: totalRecord,
                        data: result
                  }
                  return ctx.helper.results(200, "查询成功", prams);
            } catch (error) {
                  console.log(error);
                  if (typeof error != "string") {
                        error = "内部错误,请联系管理人员修复"
                  }
                  return ctx.helper.results(203, error);
            }
      }


查询用户功能:


在这里插入图片描述


查询用户功能部分功能:


async getUsers() {
            const { ctx } = this;
            const bodyData = ctx.request.query;
            // 获取总条数
            try {
                  let regularData = await ctx.helper.regularData([{ o: bodyData.pageSize, n: "pageSize", t: "n", isUnMust: true }, { o: bodyData.pageNo, n: "pageNo", t: "n", isUnMust: true }])
                  if (regularData.code !== 200) {
                        throw regularData.msg;
                  }
                  /**
                   * 特殊字段含义
                   * pageSize:每一页的条数
                   * pageNo:页码
                   * start_startTime :查询创建时间某段时间之前  
                   * start_endTime :查询创建时间某段时间之后
                   * 举例 查询'2017-1-1 00:00:00 - 2018-1-1 00:00:00'的数据 {start_startTime:'2017-1-1 00:00:00',start_endTime'2018-1-1 00:00:00'}
                   * end_startTime :查询‘结束时间’某段时间之前
                   * end_endTime :查询‘结束时间’某段时间之后
                   * 举例 查询'2017-1-1 00:00:00 - 2018-1-1 00:00:00'的数据 {end_startTime'2017-1-1 00:00:00',end_endTime'2018-1-1 00:00:00'}
                   * 其他:
                   * 1:插入某个字段则动态模糊查询该字段属性,不能插入错误字段,否则报sql错误
                   * 2:'默认'
                   */
                  let selectTxt = 'delTime is not null'
                  for (const iterator in bodyData) {
                        switch (iterator) {
                              case 'pageSize':
                                    break;
                              case 'pageNo':
                                    break;
                              case 'start_startTime':
                                    selectTxt = selectTxt + ` and createTime <= '${bodyData[iterator]}'`
                                    break;
                              case 'start_endTime':
                                    selectTxt = selectTxt + ` and createTime >= '${bodyData[iterator]}'`
                                    break;
                              case 'end_startTime':
                                    selectTxt = selectTxt + ` and endTime <= '${bodyData[iterator]}'`
                                    break;
                              case 'end_endTime':
                                    selectTxt = selectTxt + ` and endTime >= '${bodyData[iterator]}'`
                                    break;
                              default:
                                    selectTxt = selectTxt + ` and ${iterator} like '%${bodyData[iterator]}%'`
                                    break;
                        }
                  }
                  //查询总条数
                  var totalRecord = await this.app.mysql.query(`select count(id) from users;`);
                  totalRecord = totalRecord[0]["count(id)"];
                  bodyData.pageSize = bodyData.pageSize || 10;
                  bodyData.pageNo = bodyData.pageNo || 1;
                  let limit = (bodyData.pageNo - 1) * bodyData.pageSize;
                       let  result = await this.app.mysql.query(`select * from users where ${selectTxt} limit ?, ? `, [limit, Number(bodyData.pageSize)]);
                  console.log(result);
                  const rTime = (date) => {
                        var json_date = new Date(date).toJSON();
                        console.log(111);
                        return new Date(new Date(json_date) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/.[d]{3}Z/, '')
                  }
                  result = result.map((res) => {
                        let keyList = Object.keys(res)
                        keyList.map((result) => {
                              console.log(result);
                              if (result.indexOf('Time') !== -1 && result !=='delTime') {
                                    // console.log(a.length);
                                    let time = res[result];
                                    console.log(time);
                                    res[result] = new Date(time).toISOString().replace(/T/g, ' ').replace(/.[d]{3}Z/, '').substring(0, 19)
                              }
                        })
                        return res
                  })
                  let prams = {
                        pageSize: bodyData.pageSize,
                        // pageNo: bodyData.pageNo,
                        // totalRecord: totalRecord,
                        data: result
                  }
                  return ctx.helper.results(200, "查询成功", prams);
            } catch (error) {
                  console.log(error);
                  if (typeof error != "string") {
                        error = "内部错误,请联系管理人员修复"
                  }
                  return ctx.helper.results(203, error);
            }
      }


导出功能:


导出功能可以导出数据


20210617091819170.png


部分代码如下:


require('script-loader!file-saver');
require('./Blob');
require('script-loader!xlsx/dist/xlsx.core.min');
function generateArray(table) {
    var out = [];
    var rows = table.querySelectorAll('tr');
    var ranges = [];
    for (var R = 0; R < rows.length; ++R) {
        var outRow = [];
        var row = rows[R];
        var columns = row.querySelectorAll('td');
        for (var C = 0; C < columns.length; ++C) {
            var cell = columns[C];
            var colspan = cell.getAttribute('colspan');
            var rowspan = cell.getAttribute('rowspan');
            var cellValue = cell.innerText;
            if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
            //Skip ranges
            ranges.forEach(function (range) {
                if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
                    for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
                }
            });
            //Handle Row Span
            if (rowspan || colspan) {
                rowspan = rowspan || 1;
                colspan = colspan || 1;
                ranges.push({ s: { r: R, c: outRow.length }, e: { r: R + rowspan - 1, c: outRow.length + colspan - 1 } });
            }
            ;
            //Handle Value
            outRow.push(cellValue !== "" ? cellValue : null);
            //Handle Colspan
            if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
        }
        out.push(outRow);
    }
    return [out, ranges];
};
function datenum(v, date1904) {
    if (date1904) v += 1462;
    var epoch = Date.parse(v);
    return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
    var ws = {};
    var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } };
    for (var R = 0; R != data.length; ++R) {
        for (var C = 0; C != data[R].length; ++C) {
            if (range.s.r > R) range.s.r = R;
            if (range.s.c > C) range.s.c = C;
            if (range.e.r < R) range.e.r = R;
            if (range.e.c < C) range.e.c = C;
            var cell = { v: data[R][C] };
            if (cell.v == null) continue;
            var cell_ref = XLSX.utils.encode_cell({ c: C, r: R });
            if (typeof cell.v === 'number') cell.t = 'n';
            else if (typeof cell.v === 'boolean') cell.t = 'b';
            else if (cell.v instanceof Date) {
                cell.t = 'n';
                cell.z = XLSX.SSF._table[14];
                cell.v = datenum(cell.v);
            }
            else cell.t = 's';
            ws[cell_ref] = cell;
        }
    }
    if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
    return ws;
}
function Workbook() {
    if (!(this instanceof Workbook)) return new Workbook();
    this.SheetNames = [];
    this.Sheets = {};
}
function s2ab(s) {
    var buf = new ArrayBuffer(s.length);
    var view = new Uint8Array(buf);
    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    return buf;
}
export function export_table_to_excel(id) {
    var theTable = document.getElementById(id);
    console.log('a')
    var oo = generateArray(theTable);
    var ranges = oo[1];
    /* original data */
    var data = oo[0];
    var ws_name = "SheetJS";
    console.log(data);
    var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
    /* add ranges to worksheet */
    // ws['!cols'] = ['apple', 'banan'];
    ws['!merges'] = ranges;
    /* add worksheet to workbook */
    wb.SheetNames.push(ws_name);
    wb.Sheets[ws_name] = ws;
    var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
    saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), "test.xlsx")
}
function formatJson(jsonData) {
    console.log(jsonData)
}
export function export_json_to_excel(th, jsonData, defaultTitle) {
    /* original data */
    var data = jsonData;
    data.unshift(th);
    var ws_name = "SheetJS";
    var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
    /* add worksheet to workbook */
    wb.SheetNames.push(ws_name);
    wb.Sheets[ws_name] = ws;
    var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
    var title = defaultTitle || '列表'
    saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), title + ".xlsx")
    }


删除用户功能:


通过前端界面,如果用户是管理员用户,则删除用户正常得状态即可。


20210617091859166.png


删除功能部分代码:


 async delUsers() {
            const { ctx } = this;
            try {
                  const bodyData = ctx.request.body;
                  let regularData = await ctx.helper.regularData([{ o: bodyData.id, n: "数据id" }])
                  if (regularData.code !== 200) {
                        throw regularData.msg;
                  }
                  // let now = moment().locale('zh-cn').format('YYYY-MM-DD HH:mm:ss');
                  // await this.app.mysql.query(`UPDATE users SET delTime = ? WHERE id in (${bodyData.id});`, [now]);
                  await this.app.mysql.query(`UPDATE users  WHERE id in (${bodyData.id});`);
                  return ctx.helper.results(200, "删除成功");
            } catch (error) {
                  return ctx.helper.results(203, error);
            }
      }


导出客户资料功能:


20210617091947142.png


能够导出客户得资料,批量导出所有信息。



导出客户功能部分代码:2021061709215611.png


(function (view) {
    "use strict";
    view.URL = view.URL || view.webkitURL;
    if (view.Blob && view.URL) {
        try {
            new Blob;
            return;
        } catch (e) {}
    }
    // Internally we use a BlobBuilder implementation to base Blob off of
    // in order to support older browsers that only have BlobBuilder
    var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
            var
                get_class = function(object) {
                    return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
                }
                , FakeBlobBuilder = function BlobBuilder() {
                    this.data = [];
                }
                , FakeBlob = function Blob(data, type, encoding) {
                    this.data = data;
                    this.size = data.length;
                    this.type = type;
                    this.encoding = encoding;
                }
                , FBB_proto = FakeBlobBuilder.prototype
                , FB_proto = FakeBlob.prototype
                , FileReaderSync = view.FileReaderSync
                , FileException = function(type) {
                    this.code = this[this.name = type];
                }
                , file_ex_codes = (
                    "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
                    + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
                ).split(" ")
                , file_ex_code = file_ex_codes.length
                , real_URL = view.URL || view.webkitURL || view
                , real_create_object_URL = real_URL.createObjectURL
                , real_revoke_object_URL = real_URL.revokeObjectURL
                , URL = real_URL
                , btoa = view.btoa
                , atob = view.atob
                , ArrayBuffer = view.ArrayBuffer
                , Uint8Array = view.Uint8Array
                ;
            FakeBlob.fake = FB_proto.fake = true;
            while (file_ex_code--) {
                FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
            }
            if (!real_URL.createObjectURL) {
                URL = view.URL = {};
            }
            URL.createObjectURL = function(blob) {
                var
                    type = blob.type
                    , data_URI_header
                    ;
                if (type === null) {
                    type = "application/octet-stream";
                }
                if (blob instanceof FakeBlob) {
                    data_URI_header = "data:" + type;
                    if (blob.encoding === "base64") {
                        return data_URI_header + ";base64," + blob.data;
                    } else if (blob.encoding === "URI") {
                        return data_URI_header + "," + decodeURIComponent(blob.data);
                    } if (btoa) {
                        return data_URI_header + ";base64," + btoa(blob.data);
                    } else {
                        return data_URI_header + "," + encodeURIComponent(blob.data);
                    }
                } else if (real_create_object_URL) {
                    return real_create_object_URL.call(real_URL, blob);
                }
            };
            URL.revokeObjectURL = function(object_URL) {
                if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
                    real_revoke_object_URL.call(real_URL, object_URL);
                }
            };
            FBB_proto.append = function(data/*, endings*/) {
                var bb = this.data;
                // decode data to a binary string
                if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
                    var
                        str = ""
                        , buf = new Uint8Array(data)
                        , i = 0
                        , buf_len = buf.length
                        ;
                    for (; i < buf_len; i++) {
                        str += String.fromCharCode(buf[i]);
                    }
                    bb.push(str);
                } else if (get_class(data) === "Blob" || get_class(data) === "File") {
                    if (FileReaderSync) {
                        var fr = new FileReaderSync;
                        bb.push(fr.readAsBinaryString(data));
                    } else {
                        // async FileReader won't work as BlobBuilder is sync
                        throw new FileException("NOT_READABLE_ERR");
                    }
                } else if (data instanceof FakeBlob) {
                    if (data.encoding === "base64" && atob) {
                        bb.push(atob(data.data));
                    } else if (data.encoding === "URI") {
                        bb.push(decodeURIComponent(data.data));
                    } else if (data.encoding === "raw") {
                        bb.push(data.data);
                    }
                } else {
                    if (typeof data !== "string") {
                        data += ""; // convert unsupported types to strings
                    }
                    // decode UTF-16 to binary string
                    bb.push(unescape(encodeURIComponent(data)));
                }
            };
            FBB_proto.getBlob = function(type) {
                if (!arguments.length) {
                    type = null;
                }
                return new FakeBlob(this.data.join(""), type, "raw");
            };
            FBB_proto.toString = function() {
                return "[object BlobBuilder]";
            };
            FB_proto.slice = function(start, end, type) {
                var args = arguments.length;
                if (args < 3) {
                    type = null;
                }
                return new FakeBlob(
                    this.data.slice(start, args > 1 ? end : this.data.length)
                    , type
                    , this.encoding
                );
            };
            FB_proto.toString = function() {
                return "[object Blob]";
            };
            FB_proto.close = function() {
                this.size = this.data.length = 0;
            };
            return FakeBlobBuilder;
        }(view));
    view.Blob = function Blob(blobParts, options) {
        var type = options ? (options.type || "") : "";
        var builder = new BlobBuilder();
        if (blobParts) {
            for (var i = 0, len = blobParts.length; i < len; i++) {
                builder.append(blobParts[i]);
            }
        }
        return builder.getBlob(type);
    };
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));


用户信息新增:


能够新增用户信息。


2021061709215611.png


新增用户代码如下:


async addUsers() {
            const { ctx } = this;
            const bodyData = ctx.request.body;
            delete bodyData.createTime;
            delete bodyData.lastFunTime;
            let keyList = Object.keys(bodyData)
            keyList.map((result) => {
                  console.log(result);
                  if (result.indexOf('Id') !== -1) {
                        bodyData[result] = new Date().getTime() + Math.random().toString().substr(2, 4);
                  }
            })
            const result = await this.app.mysql.insert('users', bodyData);
            return ctx.helper.results(200, "增加成功", result);
      }
      async editUsers() {
            const { ctx } = this;
            const bodyData = ctx.request.body;
            try {
                  //判断ID是否存在订单(这是自动生成的,当然ID也可以换成任意的,比如orderId)
                  let regularData = await ctx.helper.regularData([{ o: bodyData.id, n: "数据id" }])
                  if (regularData.code !== 200) {
                        throw regularData.msg;
                  }
                  delete bodyData.delTime;
                  console.log(bodyData);
                  const result = await this.app.mysql.update('users', bodyData);
                  return ctx.helper.results(200, "修改成功");
            } catch (error) {
                  return ctx.helper.results(203, error);
            }
      }


删除用户:


能够对用户进行逻辑删除


20210617092236469.png


用户删除代码如下:


async delUsers() {
            const { ctx } = this;
            try {
                  const bodyData = ctx.request.body;
                  let regularData = await ctx.helper.regularData([{ o: bodyData.id, n: "数据id" }])
                  if (regularData.code !== 200) {
                        throw regularData.msg;
                  }
                  // let now = moment().locale('zh-cn').format('YYYY-MM-DD HH:mm:ss');
                  // await this.app.mysql.query(`UPDATE users SET delTime = ? WHERE id in (${bodyData.id});`, [now]);
                  await this.app.mysql.query(`UPDATE users  WHERE id in (${bodyData.id});`);
                  return ctx.helper.results(200, "删除成功");
            } catch (error) {
                  return ctx.helper.results(203, error);
            }
      }
}


🍑1.3.3、数据设计


数据库建模指的是对现实世界各类数据的抽象组织,确定数据库需管辖的范围、数据的组织形式等直至转化成现实的数据库。

将经过系统分析后抽象出来的概念模型转化为物理模型后,在visio 等工具建立数据库实体以及各实体之间关系的过程。


数据库设计(Database Design)是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,使之能够有效地存储数据,满足各种用户的应用需求(信息要求和处理要求)。在数据库领域内,常常把使用数据库的各类系统统称为数据库应用系统。


数据库设计的设计内容包括:需求分析、概念结构设计、逻辑结构设计、物理结构设计、数据库的实施和数据库的运行和维护。


系统的E-R图如下:


20210617092357564.png


数据库模型图如下:


用户表:


20210617092410177.png


系统的总体功能:


CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` varchar(100) NOT NULL COMMENT '用户Id',
  `userName` varchar(100) DEFAULT NULL COMMENT '用户名字',
  `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `lastFunTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '上次登录操作时间',
  `phone` varchar(100) NOT NULL COMMENT '手机号码',
  `type` varchar(100) NOT NULL DEFAULT '1' COMMENT '类型',
  `gender` int(11) DEFAULT '3' COMMENT '性别||1:男,2:女,3:未知',
  `password` varchar(100) NOT NULL COMMENT '密码',
  `addres` varchar(100) DEFAULT '中国北京' COMMENT '地址',
  `delTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '删除时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8


🍒1.3.4、系统用途介绍


客户管理系统后台数据库管理类型,具有数据流量非常大的数据处理任务,而且还要达到使用方便、操作灵活的操作理念。本在线视频系统在设计时对客户管理系统使用达到如下几个目标:


1、方便基本信息的录入,实现录入的数据的高校验性;


2、处理速度的提高;


3、使系统更人性化以方便用户使用;


4、人力与设备费用的减少;


5、高安全性、保密性;


系统的总体功能:


1、用户登陆


2、工单系统


3、功能包括权限验证


4、登陆


5、修改客户信息


6、增加客户


7、删除客户非物理删除


8、条件查询


9、导出客户资料


🍓1.3.5系统界面设计


页面的设计和制作就是用Notepad++软件进行,用 html语言搭好基本的框架,然后用CSS完成页面的美工效果。当然,在网页上加入图片也是一个重要的方法,无论是动态图片还是静态绚烂的图片都能使页面做的引人入胜,散发出魅力。


无论使用何种方法对画面中的元素进行搭配,有以下几个基本原则:


第一、统一设计作品的整体效果是很重要的,不可分离的部分,不然会使画面呈现出一种复杂混乱的效果。


第二、联系,主要指页面和页面之间的关系。设计中应该运用各组成部分在内容上的相互呼应,并注意整个页面与局部页面设计风格的一致性,以便实现视觉上的连贯效果,使整个页面和每个部分组合极为融洽,浑然天成,无缝连接。


第三、板块,将页面分成若干板块,各板块之间在视觉上又有不同,这样可以使观者不至于看的视觉疲惫。在信息量很多时,就要注意到将画面切割成有效的成分。分割不光是表现形式的需求,分割更被看做对于页面内容的一种分类。


第四、协调,是指整个页面符合美观的法则,使页面有艺术感,使设计更加富有生气。如果一件视图设计只是色彩、图形、线条等的随意混合,不讲求搭配的美感,那么最后给人呈现的不但没有“生命感”,而且也连基本需要传达给用户的信息也无法实现。


🏳️‍🌈1.4、开发语言介绍


🥝1.4.1、NodeJS介绍


V8引擎本身使用了一些最新的编译技术。这使得用Javascript这类脚本语言编写出来的代码运行速度获得了极大提升,又节省了开发成本。对性能的苛求是Node的一个关键因素。 Javascript是一个事件驱动语言,Node利用了这个优点,编写出可扩展性高的服务器。Node采用了一个称为“事件循环(event loop)”的架构,使得编写可扩展性高的服务器变得既容易又安全。提高服务器性能的技巧有多种多样。Node选择了一种既能提高性能,又能减低开发复杂度的架构。这是一个非常重要的特性。并发编程通常很复杂且布满地雷。Node绕过了这些,但仍提供很好的性能。


Node采用一系列“非阻塞”库来支持事件循环的方式。本质上就是为文件系统、数据库之类的资源提供接口。向文件系统发送一个请求时,无需等待硬盘(寻址并检索文件),硬盘准备好的时候非阻塞接口会通知Node。该模型以可扩展的方式简化了对慢资源的访问, 直观,易懂。尤其是对于熟悉onmouseover、onclick等DOM事件的用户,更有一种似曾相识的感觉。


虽然让Javascript运行于服务器端不是Node的独特之处,但却是其一强大功能。不得不承认,浏览器环境限制了我们选择编程语言的自由。任何服务器与日益复杂的浏览器客户端应用程序间共享代码的愿望只能通过Javascript来实现。虽然还存在其他一些支持Javascript在服务器端 运行的平台,但因为上述特性,Node发展迅猛,成为事实上的平台。


在Node启动的很短时间内,社区就已经贡献了大量的扩展库(模块)。其中很多是连接数据库或是其他软件的驱动,但还有很多是凭他们的实力制作出来的非常有用的软件。


Node.js使用Module模块去划分不同的功能,以简化应用的开发。Modules模块有点像C++语言中的类库。每一个Node.js的类库都包含了十分丰富的各类函数,比如http模块就包含了和http功能相关的很多函数,可以帮助开发者很容易地对比如http,tcp/udp等进行操作,还可以很容易的创建http和tcp/udp的服务器。


要在程序中使用模块是十分方便的,只需要如下:


在这里,引入了http类库,并且对http类库的引用存放在http变量中了。这个时候,node.js会在我们应用中搜索是否存在node_modules的目录,并且搜索这个目录中是否存在http的模块。如果node.js找不到这个目录,则会到全局模块缓存中去寻找,用户可以通过相对或者绝对路径,指定模块的位置,


比如:var myModule = require(&apos;./myModule.js&apos;);


模块中包含了很多功能代码片断,在模块中的代码大部分都是私有的,意思是在模块中定义的函数方法和变量,都只能在同一个模块中被调用。当然,可以将某些方法和变量暴露到模块外,这个时候可以使用exports对象去实现。


最后,不得不提到的是Node社区。虽然Node项目还非常年轻,但很少看到对一个项目如此狂热的社区。不管是新手,还是专家,大家都围绕着项目,使用并贡献自己的能力,致力于打造一个探索、支持、分享、听取建议的乐土。


🏳️‍🌈1.5、HTML和 CSS网页编程语言介绍


🍅1.5.1、html 语言的介绍


超文本标记语言,即 HTM(L Hypertext Markup Language),是用于描述网页文档的一种标记语言。在 WWW上的一个超媒体文档称之为一个页面(page)。作为一个组织或个人在万维网上放置开始点的页面称为主页Homepage,或首页,主页中通常包括有指向其他相关页面或其他节点的指针(超级链接。HTML是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分。HTML之所以称为超文本标记语 言,是因为文本中包含了所谓“超级链接”点。所谓超级链接,就是一种URL指针,通过激活(点击)它,可使浏览器方便地获取新的网页。Html 的主要特点如下:简易性、可扩展性、平台无关性。


万维网上的一个 超媒体文档称之为一个 页面( 外语:page)。作为一个组织或者个人在 万维网上放置开始点的 页面称为 主页(外语:Homepage)或首页,主页中通常包括有指向其他相关页面或其他节点的 指针( 超级链接),所谓 超级链接,就是一种 统一资源定位器(Uniform Resource Locator, 外语 缩写: URL)指针,通过激活(点击)它,可使 浏览器方便地获取新的网页。这也是HTML获得广泛应用的最重要的原因之一。在逻辑上将视为一个整体的一系列 页面的有机集合称为 网站( Website或Site)。超级文本标记语言(英文缩写:HTML)是为“ 网页创建和其它可在 网页浏览器中看到的信息”设计的一种 标记语言。

网页的本质就是超级文本标记语言,通过结合使用其他的 Web技术(如: 脚本语言、 公共网关接口、 组件等),可以创造出功能强大的网页。因而,超级文本标记语言是万维网( Web)编程的基础,也就是说 万维网是建立在超文本基础之上的。超级文本标记语言之所以称为超文本标记 语言,是因为文本中包含了所谓“ 超级链接”点。


超级文本标记语言是 标准通用标记语言下的一个应用,也是一种规范,一种 标准, HTML(16)它通过标记符号来标记要显示的网页中的各个部分。网页 文件本身是一种文本文件,通过在文本文件中添加标记符,可以告诉 浏览器如何显示其中的内容(如:文字如何处理,画面如何安排,图片如何显示等)。 浏览器按顺序阅读网页 文件,然后根据标记符解释和显示其标记的内容,对书写出错的标记将不指出其错误,且不停止其解释执行过程,编制者只能通过显示效果来分析出错原因和出错部位。但需要注意的是,对于不同的 浏览器,对同一标记符可能会有不完全 相 同的解释,因而可能会有不同的显示效果。


🥥1.5.2、CSS的介绍


CSS是英语 Cascading Style Sheets (层叠样式表单)的缩写,它是一种用来表 现 HTML或 XML 等文件式样的计算机语言。 CSS目前最新版本为 CSS3,能够真正做到网页表现与内容分离的一种样式设计语言。 相对于传统 HTML的表现而言, CSS能够对网页中的对象的位置排版进行像素级的精确控制,支持几乎所有的字体字号样式,拥有对网页对象盒模型的能力,并能够进行初步交互设计,是目前基于文本展示最优秀的表现设计语言。


CSS为HTML标记语言提供了一种样式描述,定义了其中元素的显示方式。CSS在Web设计领域是一个突破。利用它可以实现修改一个小的样式更新与之相关的所有页面元素。


总体来说,CSS具有以下特点:


丰富的样式定义


CSS提供了丰富的文档样式外观,以及设置文本和背景属性的能力;允许为任何元素创建边框,以及元素边框与其他元素间的距离,以及元素边框与元素内容间的距离;允许随意改变文本的大小写方式、修饰方式以及其他页面效果。


易于使用和修改


CSS可以将样式定义在HTML元素的style属性中,也可以将其定义在HTML文档的header部分,也可以将样式声明在一个专门的CSS文件中,以供HTML页面引用。总之,CSS样式表可以将所有的样式声明统一存放,进行统一管理。


另外,可以将相同样式的元素进行归类,使用同一个样式进行定义,也可以将某个样式应用到所有同名的HTML标签中,也可以将一个CSS样式指定到某个页面元素中。如果要修改样式,我们只需要在样式列表中找到相应的样式声明进行修改。


多页面应用


CSS样式表可以单独存放在一个CSS文件中,这样我们就可以在多个页面中使用同一个CSS样式表。CSS样式表理论上不属于任何页面文件,在任何页面文件中都可以将其引用。这样就可以实现多个页面风格的统一。


层叠


简单的说,层叠就是对一个元素多次设置同一个样式,这将使用最后一次设置的属性值。例如对一个站点中的多个页面使用了同一套CSS样式表,而某些页面中的某些元素想使用其他样式,就可以针对这些样式单独定义一个样式表应用到页面中。这些后来定义的样式将对前面的样式设置进行重写,在浏览器中看到的将是最后面设置的样式效果。


页面压缩


在使用HTML定义页面效果的网站中,往往需要大量或重复的表格和font元素形成各种规格的文字样式,这样做的后果就是会产生大量的HTML标签,从而使页面文件的大小增加。而将样式的声明单独放到CSS样式表中,可以大大的减小页面的体积,这样在加载页面时使用的时间也会大大的减少。另外,CSS样式表的复用更大程序的缩减了页面的体积,减少下载的时间。


CSS是一种定义样式结构如字体、颜色、位置等的语言,被用于描述网页上的信息格式化和现实的方式。CSS样式可以直接存储于HTML网页或者单独的样式单文件。无论哪一种方式,样式单包含将样式应用到指定类型的元素的规则。外部使用时,样式单规则被放置在一个带有文件扩展名_css的外部样式单文档中。


样式规则是可应用于网页中元素,如文本段落或链接的格式化指令。样式规则由一个或多个样式属性及其值组成。内部样式单直接放在网页中,外部样式单保存在独立的文档中,网页通过一个特殊标签链接外部样式单。


名称CSS中的“层叠(cascading)”表示样式单规则应用于HTML文档元素的方式。具体地说,CSS样式单中的样式形成一个层次结构,更具体的样式覆盖通用样式。样式规则的优先级由CSS根据这个层次结构决定,从而实现级联效果。


🏳️‍🌈1.6、JavaScript 编程语言介绍


🥑1.6.1、JavaScript介绍


JavaScript(缩写为JS)是一种高级的、多范式、解释型的编程语言,是一门基于原型、函数先行的语言,它支持面向对象编程、命令式编程以及函数式编程。它提供语法来操控文本、数组、日期以及正则表达式,不支持I/O(比如网络、存储和图形等),但可以由它的宿主环境提供支持。它已经由ECMA(欧洲计算机制造商协会)通过ECMAScript实现语言的标准化。它被世界上的绝大多数网站所使用,也被世界主流浏览器支持。


JavaScript是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言。同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如响应用户的各种操作。它最初由网景公司(Netscape)的Brendan Eich设计,是一种动态、弱类型、基于原型的语言,内置支持类。JavaScript是Sun公司的注册商标。Ecma国际以JavaScript为基础制定了ECMAScript标准。JavaScript也可以用于其他场合,如服务器端编程。完整的JavaScript实现包含三个部分:ECMAScript,文档对象模型,字节顺序记号。


Netscape公司在最初将其脚本语言命名为LiveScript。在Netscape在与Sun合作之后将其改名为JavaScript。JavaScript最初受Java启发而开始设计的,目的之一就是“看上去像Java”[2],因此语法上有类似之处,一些名称和命名规范也借自Java。但JavaScript的主要设计原则源自Self和Scheme[3]。JavaScript与Java名称上的近似,是当时网景为了营销[1]考虑与Sun公司达成协议的结果。为了取得技术优势,微软推出了JScript脚本语言。Ecma国际(前身为欧洲计算机制造商协会)创建了ECMA-262标准(ECMAScript)。现两者都属于ECMAScript的实现。尽管JavaScript作为给非程序人员的脚本语言,而非是作为给程序人员的编程语言来推广和宣传,但是JavaScript具有非常丰富的特性。


大概在1992年,一家称作Nombas的公司开始开发一种叫做C减减(C-minus-minus,简称Cmm)的嵌入式脚本语言。这个脚本语言捆绑在一个叫做CEnvi的共享软件产品中,当Netscape Navigator崭露头角时,Nombas开发了一个可以嵌入网页中的CEnvi的版本。这些早期的试验称为EspressoPage(浓咖啡般的页面),它们代表了第一个在万维网上使用的客户端脚本语言。而Nombas丝毫没有料到它的理念将会成为因特网的一块重要基石。


一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:核心(ECMAScript)、文档对象模型(Document Object Model,简称DOM)、浏览器对象模型(Browser Object Model,简称BOM)。


20210617095928155.png


函数


函数是命名的语句段,这个语句段可以被当作一个整体来引用和执行。使用函数要注意以下几点:


1)函数由关键字function定义(也可由Function构造函数构造)


2)使用function关键字定义的函数在一个作用域内是可以在任意处调用的(包括定义函数的语句前);而用var关键字定义的必须定义后才能被调用


3)函数名是调用函数时引用的名称,它对大小写是敏感的,调用函数时不可写错函数名


4)参数表示传递给函数使用或操作的值,它可以是常量,也可以是变量,也可以是函数,在函数内部可以通过arguments对象(arguments对象是一个伪数组,属性callee引用被调用的函数)访问所有参数


5)return语句用于返回表达式的值。


6)yield语句扔出一个表达式,并且中断函数执行直到下一次调用next。


一般的函数都是以下格式:


function myFunction(params){
//执行的语句
}
函数表达式:
var myFunction=function(params){
//执行的语句
}
var myFunction = function(){
//执行的语句
}
myFunction();//调用函数
匿名函数,它常作为参数在其他函数间传递:
window.addEventListener(&apos;load&apos;,function()
{
//执行的语句
},false);


对象


JavaScript的一个重要功能就是面向对象的功能,通过基于对象的程序设计,可以用更直观、模块化和可重复使用的方式进行程序开发。


一组包含数据的属性和对属性中包含数据进行操作的方法,称为对象。比如要设定网页的背景颜色,所针对的对象就是document,所用的属性名是bgcolor,如document.bgcolor=“blue”,就是表示使背景的颜色为蓝色。


事件


用户与网页交互时产生的操作,称为事件。事件可以由用户引发,也可能是页面发生改变,甚至还有你看不见的事件(如Ajax的交互进度改变)。绝大部分事件都由用户的动作所引发,如:用户按鼠标的按键,就产生click事件,若鼠标的指针在链接上移动,就产生mouseover事件等等。在JavaScript中,事件往往与事件处理程序配套使用。


而对事件的处理,W3C的方法是用addEventListener()函数,它有三个参数:事件,引发的函数,是否使用事件捕捉。为了安全性,建议将第三个参数始终设置为false。


传统的方法就是定义元素的on…事件,它就是W3C的方法中的事件参数前加一个“on”。而IE的事件模型使用attachEvent和dettachEvent对事件进行绑定和删除。JavaScript中事件还分捕获和冒泡两个阶段,但是传统绑定只支持冒泡事件。


🏳️‍🌈1.7、系统流程图


🍆1.7.1、系统功能模块图


主要功能包含注册、登录 /注销、修改个人资料、导出客户信息系统,根据特殊条件进行查询等等功能


20210617101303986.png


1.登录模块


(1)用户登录


用户输入用户名和口令后系统根据用户用户登录判断用户类别


检查校验用户的用户名密码以及验证码的正确性。


2.客户信息维护模块


( 1)点击修改按钮,修改用户的信息


(2)点击删除按钮,删除用户的信息


3.客户信息查询模块


( 1)按客户编号查询

选择按编号查询,输入存在的编号即可得到结果


(2)按客户姓名查询

选择按客户姓名查询,输入存在的客户姓名即可得到结果


( 3)按客户信息录入时间查询

选择按客户信息录入时间查询,输入存在的客户信息录入时间即可得到结果


(4)客户可以下载工单信息并且导出


🏳️‍🌈1.8、系统开发工具和运行环境

1) 开发环境


1) 开发环境
●操作系统: Windows 10
●计算机硬件: i5CPU 、4G内存 、2G显存、 256GbSSD
●开发语言: NodeJs编程语言
●网页设计器: Notepad++
●软件编译器:  VsCode
●Web服务器: Tomcat 8.0 以上均可
●Java 开发包: JDK 1.7 以上均可
●数据库: MySQL 5.5 以上均可
●浏览器: Chrome 、 Firefox 、Safari、Edge 均可
●分辨率:最佳效果为  1440× 900 像素


2)运行环境服务器端:
●操作系统: Microsoft  Server  2012
●Web服务器: Tomcat 8.0
●数据库: MySQL5.5
●浏览器: Edge 以上均可
●分辨率:最佳效果为  1440× 900 像 


🏳️‍🌈1.9、软件技术要求


正确性:要求运行结果正确。可靠性:一般条件下,不会死机。效率:各项操作在1~20秒内完成。


完整性:如果出现意外情况,存储的数据不会丢失。


易使用性:界面符合Windows风格,能对照画面提示直接操作。


可维护性:如果将这个系统用到客户管理时,能够准确管理客户信息,或有错误时,能快速修复。


可测试性:设计时尽可能减少测试各项功能时的工作量。


复用性:尽量选用自己有的设计、类来节省开发时间,设计时尽量模块化,方便以后复用。


安全保密性:需要输入用户名和密码登陆系统。


可理解性:要求系统中的菜单,按钮,提示信息直观,—看就懂。可移植性:要求能在PC机,手提电脑上通用。


互联性:没有互联要求。


🏳️‍🌈1.10、系统安全问题


信息系统尽管功能强大,技术先进,但由于受到自身体系结构,设计思路以及运行机制等限制,也隐含许多不安全因素。常见因素有:数据的输入,输出,存取与备份,源程序以及应用软件,数据库,操作系统等漏洞或缺陷,硬件,通信部分的漏洞,企业内部人员的因素,病毒,“黑客”等因素。因此,为使本系统能够真正安全,可靠,稳定地工作,必须考虑如下问题:为保证安全,不致使系统遭到意外事故的损害,系统因该能防止火,盗或其他形式的人为破坏。


(1)系统要能重建


(2〉系统应该是可审查的


(3)系统应能进行有效控制,抗干扰能力强


(4)系统使用者的使用权限是可识别的


🏳️‍🌈2、系统测试

🥔2.1、系统测试目的

总结软件测试的目的有一下几个方面:


第一是确认软件的质量,确认软件能够完成所期望的功能,并且是以正确的方式完成的。要衡量软件质量必须满足:


(1)在正确的时间用正确的的方法保质保量完成一项工作。
(2)符合一些应用标准的要求,例如不同用户有着不同的操作习惯、工程中的能够维护性能、能够测试性能等要求。
(3)质量也代表着它符合客户的需要。作为软件测试的过程,最重要的就是从用户需求出发,从用户的角度去看产品所具备的功能,用户如何使用这个产品,使用的时候会遇到什么问题等。
第二是反馈给开发人员或项目经理,为信息的风险评估。
第三是软件测试不仅在测试软件过程,还包括软件开发的过程。假如一个软件产品实现后出现了很多功能缺陷,说明软件在开发过程中有着缺陷。


软件测试的任务:


(1)找出Bug


(2)避免软件开发过程中的缺陷


(3)衡量软件的质量


(4)时常关注用户的需求


总的目标是:尽量确保软件万无一失。


🥕2.2、软件测试的环境

Apache提供的Web服务器Tomcat8.0(或者以上版本)使得用户可以在 Windows10等操作系统下发布自己设计开发的动态网页。


因此网站的调试工作主要是用运Tomcat 8.0的强大功能在本机下就能够完成。为了在本机下浏览Web页面,必须在创建该系统的站点上,正常情况下系统使用的是 Web的默认站点,将本机―IP地址设定为127.0.0.1,它的缺省域名值为localhost。


然后向E浏览器输入UR Lhttp://localhost/#/,Web服务器在收到浏览器传送的URL之后找到文件路径,并在服务器端显示出自己发布的网页效果。


😊一份完整的毕业设计已经提供给你们。


20210617103743474.gif


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6天前
|
编解码 前端开发
编写代码中常见问题汇总(html和css)
编写代码中常见问题汇总(html和css)
18 0
|
5天前
|
JavaScript Java 测试技术
基于springboot+vue.js的基于HTML5的问卷调查系统附带文章和源代码设计说明文档ppt
基于springboot+vue.js的基于HTML5的问卷调查系统附带文章和源代码设计说明文档ppt
9 0
|
5天前
|
前端开发
HTML CSS
HTML CSS
13 0
|
7天前
|
存储 JavaScript 前端开发
笔.COOL,一个功能完备、使用便捷的在线HTML/CSS/JS以及Vue编辑器和作品分享平台
笔.COOL是一个新兴的在线 HTML/CSS/JS 及 Vue 编辑器,提供实时预览和云端存储功能。用户可以随时随地编写和保存代码,同时分享作品给他人预览和学习。它也是一个实用的 BUG 复现工具,支持嵌入编辑器到博客,促进代码交流。社区活跃,适合开发者展示作品、获取灵感和学习。
|
7天前
|
存储 移动开发 前端开发
使用HTML5和CSS3构建现代网页:技术详解与实践
【5月更文挑战第28天】本文详细介绍了使用HTML5和CSS3构建现代网页的技术与实践。HTML5新增语义化标签、多媒体支持、本地存储和表单验证等功能,提升了网页开发效率和用户体验。CSS3则带来了更多选择器、盒模型改进、背景与边框样式以及动画过渡效果,使网页设计更具视觉冲击力。通过实例展示了如何结合两者创建结构清晰、交互丰富、响应式的现代网页。
|
9天前
|
移动开发 API UED
html5和css3
【5月更文挑战第26天】html5和css3
22 2
尚硅谷html5+css3(4)浮动
尚硅谷html5+css3(4)浮动
|
11天前
|
前端开发
尚硅谷html5+css3(3)布局
尚硅谷html5+css3(3)布局
|
11天前
|
缓存 前端开发 JavaScript
尚硅谷html5+css3(2)CSS5基本知识
尚硅谷html5+css3(2)CSS5基本知识
|
11天前
|
移动开发 搜索推荐 HTML5
尚硅谷html5+css3(1)html相关知识
尚硅谷html5+css3(1)html相关知识