可白嫖源码-基于Python的豆瓣电影数据分析与可视化分析

摘 要

随着电影行业的迅猛发展,两者之间的联系也会更加的紧密,诞生了不少互联网新服务。豆瓣电影为您提供包括最新影片推荐、观影感受在内的全方面电影咨询。豆瓣电影评论区是一个让每个人都能够表达自己观点并听取他人建议的地方,这导致了这里拥有庞大的信息量,并且呈现出碎片化的特征。所以可视化这样一个网络电影平台的数据分析,研究的意义是很多的。首先,豆瓣电影上面的数据虽然全面但是分散没有直观的观赏性,那么我们创建数据分析可视化系统的意义就是将数据以图片的形式直观生动的表现出来,这样做的意义是便于人们可以更快速更明了的发现近几年电影流行的内容以及流行的趋势,为观影人提供了一个良好的观影参考。

在这个专题中,我首先深入分析了豆瓣电影数据分析可视化系统的需求,制定了完整的设计理念。接下来,我们将详细阐述电影数据库的构建、查询功能以及展示方式,最后,我们将对核心代码进行详细的分析。通过MySQL数据库存储和python编程语言的应用,本文能够实现网站与数据库之间的动态交互,并将电影信息的数据可视化,以便读者能够快速、准确地掌握最新的电影资讯,同时也能够通过折线图、柱形图等多种形式,将不同国家的电影资讯进行对比,以便读者能够更好地理解当前的电影市场,掌握最新的电影资讯,并做出正确的决策。通过使用图像和视频,我们可以更好地了解电影。

关键词:数据分析可视化;Python;MySQL;Data Crawling

ABSTRACT

In the era of the rapid development of the film industry and the Internet industry, the connection between the two is getting closer and closer, and many Internet websites emerge as a result. Douban Film provides the latest film introduction and reviews, including movie information. In Douban film reviews, everyone can express his or her own views and obtain others' opinions, thus forming a huge amount of information and information fragmentation. Therefore, the data analysis and visualization of such an online movie platform has a lot of research significance. First of all, although the data on Douban film is comprehensive but scattered, it is not intuitive for viewing, so the significance of creating a data analysis visualization system is to present the data in the form of pictures directly and vividly. The significance of this is to facilitate people to discover the popular content and trend of movies in recent years more quickly and clearly. It provides a good reference for moviegoers.

The article first provides a background analysis of the project requirements for the Douban Film Data Analysis Visualization System, followed by an introduction to the overall design concept of the project. Then, it specifically elaborates on the design of the movie database, query of movie data, display of movie data, and analyzes the core code. In this paper, the MySQL database is used to store movie data crawled from the official website, the python technology is used to query movie information data in the MySQL database, to achieve dynamic interaction between the web page and the database, the technology is used to visualize movie information analysis, and the movie line chart is made to show the recent trend of the movie, and the movie column chart is made to show the comparison of movies in various countries, Enable the public to more intuitively and clearly access key movie information, understand the movie situation, and judge the movie trend, providing intuitive and vivid data support for movie data.

Keywords: Douban Movie Data Analysis and Visualization System ;Python ;MySQL

    录

第一章 引言

第一节 研究背景与意义

第二节 研究现状

第三节 开发技术和开发特点

第四节  论文结构说明

第二章 需求分析

第一节 系统可行性分析

第二节 系统需求分析

第三节 系统流程

第四节 系统用例分析

第三章 系统总体设计

第一节 系统架构设计

第二节 系统顺序图设计

第三节 系统功能模块设计

第四节 数据库设计

第四章 关键模块的设计与实现

第一节 首页模块

第二节 注册模块

第三节 登录模块

第四节 用户管理模块

第五节 电影信息模块

第六节 密码修改模块

第五章 系统测试

第一节 系统测试的目的

第二节 系统测试用例

第三节 系统测试结果

第六章 结论

参考文献

致谢

第一章 引言

第一节 研究背景与意义

随着计算机和手机的普及,越来越多的用户选择在家看电影,这样既节省了时间也让用户可以享受到良好的个人体验,不过近年来各类题材的电影层出不穷,电影质量也是参差不齐,观众稍不留意就可能遭受低评分影片的侵扰。豆瓣网就很好地利用这一点,让所有网民都可以对影片进行打分,并且做出客观评价,网民可以通过对评分评价的分析,来判断自己是否观看此片。在大数据时代,研究网络爬虫原理的丰富的标准库,而电影网络数据正是利用这一原理获得的。我们希望通过可视化的数据分析,帮助用户找到最适合的电影。

第二节 研究现状

近年来,中国电影和TV业迅速崛起,并且受益于互联网技术的飞速发展。电影和TV业已经开始与大数据紧密结合,实现了交互式的电影和TV制作。随着数据技术的不断发展,《小时代》、《失恋 33天》等国产电影在票房上取得了巨大的成功。数据技术的不断发展下,票房一路高歌猛进。由于越来越多的优秀和巨大的电影问世,一部电影通常具有许多独特的特点,而这些特征会产生不同程度的影响。随着电影数据量的不断增加,利用计算机技术对这些数据进行深入的分析,从而更好地了解其中的价值,并从中提取出有益的信息,从而为国内电影产业的发展提供有效的支持。

第三节 开发技术和开发特点

一、爬虫技术

网络是搜索引擎获取Internet资讯的重要渠道。爬虫可以分为两类:传统型和聚焦型。传统爬虫通常会先收集一个或多个初始网页URL,然后根据这些URL进行爬取,并在队列中不断加入新的URL,直到到达一个具体的停留时间。也就是说需要的功能可以通过源代码分析技术来实现。

重点关注网页分析算法,通过过滤掉与主题无关的网页,只保留有价值的网页,然后把它们加入搜索引擎的URL队列中。接下来,它会根据特定的搜索策略,从队列中选择下一个要爬取的网页网址,并在系统设定的最终目标前不断重复这一过程。此外,系统还会对所有被爬虫抓取的网页进行存储,为方便爬虫查询检索的用户提供索引,并对其进行分析筛选。通过对FoucusCloud的分析,获取有价值的信息,从而有效地指导和建议今后的抓取工作。

二、JavaScript 运行模式

作为一种具有重要意义的高级脚本语言,JavaScript已经普遍应用于Web,它能够实现多种动态功能,让用户体验到更加流畅精致的浏览体验。JavaScript脚本通常被嵌入到HTML中,以实现其特有的功能和用户体验。

(1)是一种不需要预先编译的解释性脚本语言,

(2)它可以提供丰富的信息和功能。可以在HTML页面上增加交互性,从而提升用户体验。

(3)它可以自动生成代码。这种脚本语言不需要预先编译,可以用来解释数据。嵌入HTML页面可以大大提高效率,而将其转换为js文件则能够更好地实现结构与行为的分离。

(4)一种跨平台特性使得它能够在多种浏览器环境中运行,从Windows到Linux,从Mac到Android,再到iOS,满足用户的多样化需求。

(5) JavaScript脚本语言与众不同,具备独特的基础数据类型、复杂的表达式、精确的算法以及完善的编程结构。JavaScript可以支持四种常见的数据类别,以及两种独特的数据类别,以便更有效地处理图像和文档。变量可以用来存储信息,而表达式则可以用来处理更复杂的数据。

三、B/S体系工作原理

采用B/S架构,浏览器为满足用户需求而发出请求,服务器响应迅速。

Internet上的用户可以轻松获取各种内容,包括文字、图像、动画、视频、音乐、游戏、社区、应用程序、搜索引擎、社区论坛等;

每台Web服务器可以通过多种方式与数据库服务器连接,从而更好地管理和分析数据库中存储大量的数据。

Web服务器可以将程序从外部下载到本地,当遇到与数据库相关的指令时,它会将其传递给数据库服务器,以便进行解释和执行,最终将结果反馈给用户。通过建立一个庞大的联系网络,使得世界各地的人们能够相互联系、共同分享信息和资源。通过这种架构,各家公司都能够创建属于自己的Internet网络。

B/S 模式下,用户可以从多台服务器发出请求,而这些服务器会根据用户的要求,自动处理和反馈,而其余的任务则交由Web Server来实现。随着该框架结构的普及,加上其内建的浏览器,在应用和使用广泛的当今软件应用领域,已经成为一种主流的架构。

图1-1 B/S 模式

四、 Mysql

Mysql数据库已经成为了一种强大的工具,能够在多个用户之间进行数据交换,同时还能够根据需要进行灵活的配置。在这种情况下,服务器与客户端的区别仅仅是软件层面的概念,与硬件设备并无直接联系。

Mysql是一款受推崇的关系型数据库管理系统,其优异的性能和易于操作的特性,以及跨越多个平台的能力,使Mysql成为了众多软件开发人员的第一选择。这种数据库不同于其他关系型数据库,它通过对用户权限和角色的设定,对数据库进行有效的控制和管理,具有一套独特的管理机制。Mysql显然是一款具有出色的容错能力、可靠性和高效率的数据库管理工具。

优势一:MySQL拥有独特的权限分配机制,能够根据用户的身份和业务逻辑为用户提供更多的选择,从而使MySQL的安全性和完整性大大提高,远超其它关系型数据库。

优势二:MySQL功能强大,可支持多种动画、图形、声音等多种数据类型,说明能满足多种数据处理需求。

优势三:MySQL具有多种功能,可以支持多种平台的开发,支持多种编程语言,让用户可以方便的访问和使用MySQL数据库。

五、 Navicat

Navicat是一套专为简化数据库的管理系统管理成本而设计的可靠的比那个还便宜的数据库管理工具。它的设计满足了中小型企业的数据库管理员,开发者和他们的需求。Navicat是以直觉化的图形用户界面而建的,让你可以以安全并且简单的方式创建、组织、访问并共用信息。NavicatforMySQL是一套理想的管理和开发MySQL或MariaDB的解决方案,支持单一程序,可同时连接MySQL和MariaDB,这种功能齐备的前端软件提供了直观、强大的数据库管理、开发和维护的图形界面,为MySQL或MariaDB新手和专业人员提供了一套综合的工具。Navicat for  Mysql可连接到任何本机或远程Mysql和MariaDB服务器。它可以用于Mysql数据库服务器版本3.21或以上和MariaDB5.0或以上,与Drizzle、OurDelta和Percona Server兼容。

六、前后端分离

(一)前端vue

Vue是一款轻巧、高效、渐进式的JavaScript框架,主要用于用户界面的构建,尤其适用于SPA开发。VueFramework采用组件化开发,可以让代码变得更加模块化,易于维护和使用,而且还支持双向绑定数据,虚拟DOM,模板渲染等高级特性,让开发更高效。Vue框架有以下几个优点:

优势一:VueFramework以简单易懂、入门门槛极低、无需太多前置知识基础、较为平缓的学习曲线为设计理念。

优势二:VueFramework采用了虚拟DOM技术,因此在数据更新时只会对改变的部分进行渲染,性能大幅提升。

优势三:VueFramework尺寸只有20KB左右,非常小巧,可以根据项目需要有选择的加载一些特性和插件。

优势四:基于VUE框架的插件和工具非常多,社群活跃,遇到问题可以快速解答并支持。

优势五:VUE框架的核心思想是组件化,可以把一个大的应用分成多个小的部件,这样既有利于代码的取用,又便于代码的维护。

总之,VUE框架非常适合中小型项目的快速搭建,还可以和其他框架、库进行组合,扩大使用前景。

(二)后端Flask

Flask是一个轻量级的Python Web框架,它基于Werkzeug WSGI工具箱和Jinja2模板引擎,可以快速、灵活地构建Web应用程序。下面是Flask的一些优点:

优势一:设计目标是简洁而灵活或,没有过多的框架层级和代码结构约束,可以快速上手。

优势二:是轻巧的框架,对功能简单但不失灵活性,能够根据项目需求对组件进行有选择的加载。

优势三:提供了极为丰富的可快速实现复杂功能的扩展库,使用起来十分方便。

优势四:Flask默认采用了Jinja2模板引擎,能够实现强大的模板继承、滤镜、宏等功能,在开发Web应用时非常实用。

优势五:Flask提供了非常好的单元测试支持以及整合的测试支持,能够帮助开发人员及时发现问题并改善代码质量。

总的来说,Flask是一款非常灵活、易学易用、可拓展性很强的PythonWeb框架,适用于构建和开发小型项目或中小型API服务,同时也能满足一定的高级特性需求。

第四节  论文结构说明

本文一共分为六章,每章具体内容介绍如下:

第一章,引言,首先介绍了在线教育平台的背景,通过传统教育和在线教育的对比,指出开发在线教育平台的意义,接着对该论文的结构进行说明。

第二章,需求分析,对系统进行可行性分析、系统功能需求分析以及非功能性需求分析等。

第三章,系统总体设计,通过对当前用户的需求分析来阐述该系统的整体架构以及数据库分析设计,确定各功能模块以及最终系统需要实现的功能。

第四章,关键模块的设计与实现,根据设计目标对各个主要功能模块分别进行详细设计,主要功能代码及其实现过程和功能界面设计。

第五章,系统测试,根据用户实际需求,对该系统主要功能模块进行测试。

第六章,结论

第二章 需求分析

第一节 系统可行性分析

一、技术可行性分析

豆瓣电影数据分析可视化系统在数据的存储上使用的MYSQL数据库,在豆瓣电影数据分析可视化系统开发中使用了了python、HTML、pycharm、python这些开发工具的使用,能够给我们的编写工作带来许多的便利。系统采用B/S模式开发,使系统的可扩展性和维护性更好,减少系统配置代码以及编程代码,目前最流行的是B/S模式(B/SModel)

二、经济可行性分析

在开发豆瓣电影数据分析可视化系统中所使用的开发软件像pycharm开发工具、tomcat服务器、python开发框架、MySQL5.7数据库、Photoshop图片处理软件等,这些环境从网上就能免费下载,而且网上都有安装的教程,根据教程一步一步的操作,就可以安装成功,不需要花任何费用,并且豆瓣电影数据分析可视化系统是自己设计并编码实现的,数据库是使用流行mysql进行数据的存储,开源的mysql等技术的使用,减少系统开发费用。

三、操作可行性分析

首先,技术方面,豆瓣电影数据分析与可视化系统需要使用到大量的数据采集,数据处理,数据存储等方面的技术支持。因此,在技术实现上需要较高的水平和丰富的经验。其次,数据采集方面,豆瓣网站对于数据的爬取有一定的限制,需要进行反爬虫处理。因此,在数据采集上需要有相应的技术手段,具有一定的难度。再次,在数据处理方面,采集到的数据需要经过筛选、转化、分析等环节的处理。需要使用一些数据处理和分析的工具,例如Python中的pandas、numpy等数据分析库。最后,还要平菇目标市场、分析系统使用用户是否充足,商业模式是否充足等等。

在这个项目的设计中,我借鉴了大量的成功案例,深入分析了它们的操作界面和功能,并结合了多个案例,以人为本,简化了操作,使本项目即使计算机基础知识的人也能轻而易举地完成。由于这些原因,这个操作是可行的。

第二节 系统需求分析

一、功能需求分析

豆瓣电影数据分析可视化系统分为两大部分:管理员模块(AdminModule)和用户模块(UserModule)

(一)管理员:

(1)登录:在数据库中直接设置管理员的同户名和密码,管理员可以在后台输入用户名+密码进行登陆操作。

(2)个人中心:个人资料的修改和个人账号登陆的密码修改,在经过登录之后可由自己管理。

(3)用户管理:对于存在于系统中的用户,管理员可以通过点击“用户管理”菜单的方式进行管理。

(4)电影信息:管理员点击“影片信息”会显示出所有的电影信息,支持输入片名或者导演查询影片信息,如欲新增影片信息,点击“添加”按钮,输入影片名称、导演、编剧、主演、类型、语言、上映日期、评分、封面等信息,点击“提交”按钮就可以添加了,同时可以选择某一条电影信息,点击“删除”也可以控制用户提交的评论的信息。

(5)系统管理:管理员点击“系统管理”这一菜单会显示系统简介、轮播图、电影资讯、联系我们以及关于我们这五个子菜单,管理员可以对前台展示的电影资讯和轮播图进行设置;

(二)用户:

(1)首页信息:当用户登录或者注册成功之后,进入后端信息系统的前台,就可以看到导航栏,轮播图等信息,用户可以根据自己个人的需求进行查看;

(2)请使用“登录”或“登录”两个按钮来完成注册。“登录”按钮需要填写您的用户名+密码,并且系统将检查您是否已经完成登录。“登录”按钮则需要您输入您的用户信息,并获取您的账号和密码。“注册”按钮则需要您输入您的个人资料,才能完成登录;

(3)“电影资讯”是一款可以为用户提供包括最新资讯,最新动态等在内的资讯的应用,该应用功能众多,支持用户收藏,点赞,添加评论等功能。

(4)电影信息:用户在查询想要了解的影片时,可以进入查看影片的详细介绍,这样就可以更加清楚全面的了解影片信息。

(5)通过“个人中心”按钮,用户可以轻松访问和控制个人中心的所有内容,包括账号、密码和其他重要信息,从而实现更加便捷的管理功能;

二、非功能性需求分析

豆瓣电影数据分析可视化系统的安全性、可靠性、性能和可扩展性是其重要的考量因素,它们不仅满足了用户对于功能性的要求,还为用户提供了更多的便利。根据表格2-1,我们可以清楚地看到这一点:

2-1 豆瓣电影数据分析可视化系统非功能需求表

安全性

主要指豆瓣电影数据分析可视化系统数据库的安装,数据库的使用和密码的设定必须合乎规范。

可靠性

可靠性是指豆瓣电影数据分析可视化系统能够安装用户的指示进行操作,经过测试,可靠性90%以上。

性能

性能是影响豆瓣电影数据分析可视化系统占据市场的必要条件,所以性能最好要佳才好。

可扩展性

比如数据库预留多个属性,比如接口的使用等确保了系统的非功能性需求。

易用性

用户只要跟着豆瓣电影数据分析可视化系统的页面展示内容进行操作,就可以了。

可维护性

豆瓣电影数据分析可视化系统开发的可维护性是非常重要的,经过测试,可维护性没有问题

第三节 系统流程

豆瓣电影数据分析与可视化系统的系统流程可以分以下几个主要步骤:

  1. 数据采集:从豆瓣电影网站通过爬虫的等方式获取包括片名、导演、演员、上映日期、评分、评论等在内的电影资料。
  2. 数据清洗:处理所收集的资料,除去复杂无用的数据,格式化变换,清洗数据等,以保证资料的质量及准确性。
  3. 数据分析:对清洗后的数据进行分析,包扩电影评分的分布,不同类型电影占比,热门电影的排名等。可以使用Python中的数据分析库进行数据分析,例如pandas、numpy等。
  4. 可视化展示:通过图表、图像等方式进行数据可视化展示,如用Matplotlib、Seaborn等库绘制可视化图表,例如条形图,饼图,热力图等。

    5.系统测试:对系统进行功能测试和性能测试,确保系统稳定性和可靠性。

开发人员可以通过对上述业务流程的运用,以符合和线条的方式,对系统的运行机制进行更好的理解,并对用户在使用系统时的体验进行演示。另外,业务流程也能帮助开发者找到系统中的bug并且加以完善一、新增数据

一、增添数据

当用户成功登录系统,即可获得指定的编号,这些编号由系统生成,而用户无权更改,只需要提供指定的编号,而其余的信息则需要由用户自行完成,完成之后,系统会对所提交的信息进行审核,如果审核结果符合要求,则表明增加数据已获得成功;否则,则说明未获得成功,如图2-1所示。

图2-1  数据增加流程图

二、修改数据

在数据修改过程中,与之前提到的数据增加过程相似,如图2-2所示。

图2-2  数据修改流程图

三、删除数据

当系统中出现了一些无效信息时,管理人员应采取措施将其删除处理,而图2-3则提供了删除这些无效信息过程的流程图。

图2-3  数据删除流程图

第四节 系统用例分析

用户角色在豆瓣电影数据分析可视化系统中的使用示意图如图2.4所示:

图2-4用户角色用例图

豆瓣电影数据分析可视化系统中管理员角色用例图如图2-5所示:

图2-5管理员角色用例图

第三章 系统总体设计

本章将深入探究豆瓣电影数据分析可视化系统的各种功能模块,以及如何构建一个高效的数据库。

第一节 系统架构设计

基于WEB的豆瓣电影的数据分析可视化系统由用户界面(UI)、业务流程层(BLL)、数据层(DL)三个层次组成。

图3-1豆瓣电影数据分析可视化系统架构设计图

表现层(UI):UI层是豆瓣电影数据分析可视化系统的核心部分,负责实现用户界面的交互,在使用该系统的过程中,为用户带来便捷的操作体验,让用户感受到更舒适的氛围。UI界面设计应该灵活应对各种不同的豆瓣电影数据分析可视化系统和尺寸,以确保良好的兼容性和可用性。UI交互功能必须具有合理性,以便用户能够获得与之相匹配的交互结果,因此,表现层必须与业务逻辑层紧密结合,以实现良好的交互体验。

业务逻辑层(BLL):BLL层(BLL)负责处理本豆瓣电影数据,并将其可视化处理,使电影内容得到更好的理解和分析。通过业务逻辑层,用户将数据转换为可供应用的格式,而系统则将这些格式转换为可供应用的格式,并将其发送到表现层。

数据层(DL):通过将mysql数据库作为数据层,实现豆瓣带你应数据分析可视化系统的全面架构,既负责数据的存储,又负责有效管理数据,使系统运行更加地稳定。

第二节 系统顺序图设计

一、登录模块

该模块旨在为管理人员和用户提供权限登录功能,其登录顺序如图3-2所示。

图3-2登录顺序图

二、添加信息模块

在登录之前,无论是管理员还是用户都能够轻松地完成添加信息的任务,具体的步骤请参考图3-3。

图3-3 添加信息顺序图

第三节 系统功能模块设计

豆瓣电影数据分析可视化系统整体的功能模块包括管理员这个模块,实现了对电影数据相关信息的查询管理,系统功能模块如图所示。

图3-4豆瓣电影数据分析可视化系统功能模块图

第四节 数据库设计

在数据库设计的三个主要步骤中,第一个是需求的分析,第二个是设计概念模型,最后是建立数据库表(datable-list)。在这三个步骤之间,需求分析是必不可少的,而概念模型的设计则涉及到概念模型与逻辑结构的设计。

一、数据库概念结构设计

下面是整个豆瓣电影数据分析可视化系统中主要的数据库表总E-R实体关系图。

           

图3-5 豆瓣电影数据分析可视化系统总E-R关系图

通过豆瓣电影数据分析可视化系统,我们发现它需要大量的E-R图表,其中包括一些重要的数据库模型图,它们能够帮助我们更好地理解和分析数据。

图3-6 评论E-R图

图3-7 电影信息E-R图

二、数据库逻辑结构设计

经过豆瓣电影的数据分析,我们发现,为了更好地展示E-R关系图,我们需要创建大量的数据表。我将重点介绍几种常见的数据库表结构设计方法。

表名:yonghu,用户

表3-1 yonghu

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

yonghuzhanghao

varchar

200

用户账号

mima

varchar

200

密码

yonghuxingming

varchar

200

用户姓名

xingbie

varchar

200

性别

yonghudianhua

varchar

200

用户电话

touxiang

longtext

4294967295

头像

表名:users,管理员用户表

表3-2 users

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

username

varchar

100

用户名

password

varchar

100

密码

role

varchar

100

角色

管理员

addtime

timestamp

新增时间

CURRENT_TIMESTAMP

表名:systemintro,介绍表

表3-3 systemintro

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

title

varchar

200

标题

subtitle

varchar

200

副标题

content

longtext

4294967295

内容

picture1

longtext

4294967295

图片1

picture2

longtext

4294967295

图片2

picture3

longtext

4294967295

图片3

表名:storeup,收藏表

表3-4 storeup

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

userid

bigint

用户id

refid

bigint

商品id

tablename

varchar

200

表名

name

varchar

200

名称

picture

longtext

4294967295

图片

type

varchar

200

类型(1:收藏,21:赞,22:踩,31:竞拍参与,41:关注)

1

inteltype

varchar

200

推荐类型

remark

varchar

200

备注

表名:news,电影资讯

表3-5 news

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

title

varchar

200

标题

introduction

longtext

4294967295

简介

picture

longtext

4294967295

图片

content

longtext

4294967295

内容

表名:discussdianyingxinxi,评论表

表3-6 discussdianyingxinxi

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

refid

bigint

关联表id

userid

bigint

用户id

avatarurl

longtext

4294967295

头像

nickname

varchar

200

用户名

content

longtext

4294967295

评论内容

reply

longtext

4294967295

回复内容

表名:dianyingxinxi

功能:电影信息

表3-7 dianyingxinxi

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

dianyingming

varchar

200

电影名

daoyan

varchar

200

导演

bianju

varchar

200

编剧

zhuyan

varchar

200

主演

leixing

varchar

200

类型

yuyan

varchar

200

语言

syrq

varchar

200

上映日期

pianchang

int

片长

pingfen

float

评分

detail

longtext

4294967295

剧情介绍

remenpinglun

longtext

4294967295

热门评论

fengmian

longtext

4294967295

封面

clicktime

datetime

最近点击时间

clicknum

int

点击次数

0

表名:chat 联系我们

表3-8 chat

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

userid

bigint

用户id

adminid

bigint

管理员id

ask

longtext

4294967295

提问

reply

longtext

4294967295

回复

isreply

int

是否回复

表名:aboutus  关于我们

字段名称

类型

长度

字段说明

主键

默认值

id

bigint

主键

主键

addtime

timestamp

创建时间

CURRENT_TIMESTAMP

title

varchar

200

标题

subtitle

varchar

200

副标题

content

longtext

4294967295

内容

picture1

longtext

4294967295

图片1

picture2

longtext

4294967295

图片2

picture3

longtext

4294967295

图片3

第四章 关键模块的设计与实现

基于前期对豆瓣电影数据分析可视化系统的需求分析以及整体架构,我们精心设计了一个页面,以便更好地展示出用户的行为,并且能够更加有效地实现业务逻辑。本文将重点介绍豆瓣电影数据分析的可视化系统界面和业务逻辑。

第一节 首页模块

该项目的首页页面包含以下几个部分:

导航栏:用于导航网站的各个板块,其中有首页,电影信息,电影咨询,后台管理,联系我们,以及退出登录这几个板块

电影推荐:在首页上展示一些推荐的电影,这些推荐电影系统会随机显示八个,点开可以查看单独的电影信息,包括导演,编剧,主演,类型,语言,上映日期,片长,评分,点击次数统计,以及电影的剧情介绍,热门评论,用户还可以添加评论。

搜索框:在电影信息板块,我们可以通过电影名查询,导演查询,编剧查询,查询数据库中所存的电影数据。在电影咨询板块可以通过对标题的查询,查看相关电影的咨询,这些咨询是由豆瓣网提供,随机选择了八个进行插入排版。

首页主要分别展示各个模块的最新动态,浏览者可以很清楚地看到不同模块的最新更新内容。并且系统首页每个部分可以跳转到相对应的模块,方便浏览者选择感兴趣的地方。

首页载入流程图如下所示。

图4-1 首页载入流程

首页如下图所示。

图4-2 首页界面

首页逻辑代码如下。

</div>

        <div style="display: flex;align-items: center;width: 100%;margin-bottom: 10px;">

            <el-card style="width: 20%;margin: 0 10px;" v-if="isAuth('dianyingxinxi','首页统计')">

                <div id="dianyingxinxiChart1" style="width:100%;height:400px;"></div>

            </el-card>

            <el-card style="width: 20%;margin: 0 10px;" v-if="isAuth('dianyingxinxi','首页统计')">

                <div id="dianyingxinxiChart2" style="width:100%;height:400px;"></div>

            </el-card>

            <el-card style="width: 20%;margin: 0 10px;" v-if="isAuth('dianyingxinxi','首页统计')">

                <div id="dianyingxinxiChart3" style="width:100%;height:400px;"></div>

            </el-card>

            <el-card style="width: 20%;margin: 0 10px;" v-if="isAuth('dianyingxinxi','首页统计')">

                <div id="dianyingxinxiChart4" style="width:100%;height:400px;"></div>

            </el-card>

            <el-card style="width: 20%;margin: 0 10px;" v-if="isAuth('dianyingxinxi','首页统计')">

                <div id="dianyingxinxiChart5" style="width:100%;height:400px;"></div>

            </el-card>

        </div>

    </div>

</div>

</template>

<script>

//5

import router from '@/router/router-static'

import * as echarts from 'echarts'

export default {

data() {

return {

            dianyingxinxiCount: 0,

};

},

  mounted(){

    this.init();

    this.getdianyingxinxiCount();

    this.dianyingxinxiChat1();

    this.dianyingxinxiChat2();

    this.dianyingxinxiChat3();

    this.dianyingxinxiChat4();

    this.dianyingxinxiChat5();

  },

  methods:{

    init(){

        if(this.$storage.get('Token')){

        this.$http({

            url: `${this.$storage.get('sessionTable')}/session`,

            method: "get"

        }).then(({ data }) => {

            if (data && data.code != 0) {

            router.push({ name: 'login' })

            }

        });

        }else{

            router.push({ name: 'login' })

        }

    },

    getdianyingxinxiCount() {

        this.$http({

            url: `dianyingxinxi/count`,

            method: "get"

        }).then(({

            data

        }) => {

            if (data && data.code == 0) {

                this.dianyingxinxiCount = data.data

            }

        })

    },

    dianyingxinxiChat1() {

      this.$nextTick(()=>{

        var dianyingxinxiChart1 = echarts.init(document.getElementById("dianyingxinxiChart1"),'macarons');

        this.$http({

            url: `dianyingxinxi/value/dianyingming/pingfen`,

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].dianyingming);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].dianyingming

                    })

                }

                var option = {};

                option = {

                    title: {

                        text: '评分',

                        left: 'center'

                    },

                    tooltip: {

                      trigger: 'item',

                      formatter: '{b} : {c}'

                    },

                    xAxis: {

                        type: 'category',

                        data: xAxis,

                        axisLabel : {

                            rotate:70

                        }

                    },

                    yAxis: {

                        type: 'value'

                    },

                    series: [{

                        data: yAxis,

                        type: 'bar'

                    }]

                };

                // 使用刚指定的配置项和数据显示图表。

                dianyingxinxiChart1.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    dianyingxinxiChart1.resize();

                };

            }

        });

      })

    },

    dianyingxinxiChat2() {

      this.$nextTick(()=>{

        var dianyingxinxiChart2 = echarts.init(document.getElementById("dianyingxinxiChart2"),'macarons');

        this.$http({

            url: `dianyingxinxi/value/dianyingming/pianchang`,

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].dianyingming);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].dianyingming

                    })

                }

                var option = {};

                option = {

                    title: {

                        text: '片长',

                        left: 'center'

                    },

                    tooltip: {

                      trigger: 'item',

                      formatter: '{b} : {c}'

                    },

                    xAxis: {

                        type: 'category',

                        boundaryGap: false,

                        data: xAxis

                    },

                    yAxis: {

                        type: 'value'

                    },

                    series: [{

                        data: yAxis,

                        type: 'line',

                        areaStyle: {},

                        smooth: true

                    }]

                };

                // 使用刚指定的配置项和数据显示图表。

                dianyingxinxiChart2.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    dianyingxinxiChart2.resize();

                };

            }

        });

      })

    },

    dianyingxinxiChat3() {

      this.$nextTick(()=>{

        var dianyingxinxiChart3 = echarts.init(document.getElementById("dianyingxinxiChart3"),'macarons');

        this.$http({

            url: "dianyingxinxi/group/dianyingming",

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].dianyingming);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].dianyingming

                    })

                }

                var option = {};

                // 使用刚指定的配置项和数据显示图表。

                dianyingxinxiChart3.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    dianyingxinxiChart3.resize();

                };

            }

        });

      })

    },

    dianyingxinxiChat4() {

      this.$nextTick(()=>{

        var dianyingxinxiChart4 = echarts.init(document.getElementById("dianyingxinxiChart4"),'macarons');

        this.$http({

            url: "dianyingxinxi/group/daoyan",

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].daoyan);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].daoyan

                    })

                }

                var option = {};

                option = {

                        title: {

                            text: '导演',

                            left: 'center'

                        },

                        tooltip: {

                          trigger: 'item',

                          formatter: '{b} : {c} ({d}%)'

                        },

                        series: [

                            {

                                type: 'pie',

                                radius: '55%',

                                center: ['50%', '60%'],

                                data: pArray,

                                emphasis: {

                                    itemStyle: {

                                        shadowBlur: 10,

                                        shadowOffsetX: 0,

                                        shadowColor: 'rgba(0, 0, 0, 0.5)'

                                    }

                                }

                            }

                        ]

                };

                // 使用刚指定的配置项和数据显示图表。

                dianyingxinxiChart4.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    dianyingxinxiChart4.resize();

                };

            }

        });

      })

    },

    dianyingxinxiChat5() {

      this.$nextTick(()=>{

        var dianyingxinxiChart5 = echarts.init(document.getElementById("dianyingxinxiChart5"),'macarons');

        this.$http({

            url: "dianyingxinxi/group/leixing",

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].leixing);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].leixing

                    })

                }

                var option = {};

                option = {

                        title: {

                            text: '类型',

                            left: 'center'

                        },

                        tooltip: {

                          trigger: 'item',

                          formatter: '{b} : {c} ({d}%)'

                        },

                        series: [

                            {

                                type: 'pie',

                                radius: ['25%', '55%'],

                                center: ['50%', '60%'],

                                data: pArray,

                                emphasis: {

                                    itemStyle: {

                                        shadowBlur: 10,

                                        shadowOffsetX: 0,

                                        shadowColor: 'rgba(0, 0, 0, 0.5)'

                                    }

                                }

                            }

                        ]

                };

                // 使用刚指定的配置项和数据显示图表。

                dianyingxinxiChart5.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    dianyingxinxiChart5.resize();

                };

            }

        });

      })

    },

  }

};

</script>

<style lang="scss" scoped>

    .cardView {

        display: flex;

        flex-wrap: wrap;

        width: 100%;

        .cards {

            display: flex;

            align-items: center;

            width: 100%;

            margin-bottom: 10px;

            justify-content: center;

            .card {

                width: calc(25% - 20px);

                margin: 0 10px;

                /deep/.el-card__body{

                    padding: 0;

                }

            }

        }

    }

</style>

第二节 注册模块

豆瓣电影数据分析可视化系统的注册登录操作,用户都是从同一个注册登录页面进行注册登录,若是还未有系统账号,则进行注册操作;若是已注册账号,则用户在操作时,输入账号、密码,再选择相应的角色,如“用户”等。

用户注册流程图如下所示。

图4-3 用户注册流程

用户注册界面如下图所示。

图4-4 用户注册界面

注册逻辑代码如下。

<template>

<div>

<div class="container" :style='{"minHeight":"100vh","alignItems":"center","background":"url(http://codegen.caihongy.cn/20220730/2b81bdd12fb44d16b132a4c823eb2f7d.png)","display":"flex","width":"100%","backgroundSize":"cover","backgroundPosition":"center center","backgroundRepeat":"no-repeat","justifyContent":"center"}'>

<el-form v-if="pageFlag=='register'" :style='{"padding":"30px","boxShadow":"0px 4px 10px 0px #B8DE4B","margin":"0 0 0 500px","borderRadius":"10px","background":"#fff","width":"450px","height":"auto"}' ref="rgsForm" class="rgs-form" :model="rgsForm">

<div v-if="true" :style='{"padding":"10px","margin":"0 0 20px 0","color":"rgba(121, 149, 43, 1)","textAlign":"center","width":"100%","lineHeight":"44px","fontSize":"24px","fontWeight":"600","height":"auto"}' class="title">豆瓣电影数据分析可视化系统注册</div>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">用户账号</div>

<el-input  v-model="ruleForm.yonghuzhanghao"  autocomplete="off" placeholder="用户账号"  type="text"  />

</el-form-item>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">密码</div>

<el-input  v-model="ruleForm.mima"  autocomplete="off" placeholder="密码"  type="password"  />

</el-form-item>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">确认密码</div>

<el-input  v-model="ruleForm.mima2" autocomplete="off" placeholder="确认密码" type="password" />

</el-form-item>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">用户姓名</div>

<el-input  v-model="ruleForm.yonghuxingming"  autocomplete="off" placeholder="用户姓名"  type="text"  />

</el-form-item>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">性别</div>

                    <el-select v-model="ruleForm.xingbie" placeholder="请选择性别" >

                        <el-option

                            v-for="(item,index) in yonghuxingbieOptions"

                            v-bind:key="index"

                            :label="item"

                            :value="item">

                        </el-option>

                    </el-select>

</el-form-item>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">用户电话</div>

<el-input  v-model="ruleForm.yonghudianhua"  autocomplete="off" placeholder="用户电话"  type="text"  />

</el-form-item>

<el-form-item :style='{"width":"80%","padding":"0","margin":"0 auto 15px","height":"auto"}' class="list-item" v-if="tableName=='yonghu'">

<div v-if="false" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}' class="lable">头像</div>

                    <file-upload

                        tip="点击上传头像"

                        action="file/upload"

                        :limit="3"

                        :multiple="true"

                        :fileUrls="ruleForm.touxiang?ruleForm.touxiang:''"

                        @change="yonghutouxiangUploadChange"

                    ></file-upload>

</el-form-item>

<button :style='{"border":"0","cursor":"pointer","padding":"0 10px","margin":"20px auto 11px","outline":"none","color":"rgba(0, 0, 0, 1)","borderRadius":"8px","background":"rgba(193, 227, 97, 1)","display":"block","width":"80%","fontSize":"18px","height":"44px"}' type="button" class="r-btn" @click="login()">注册</button>

<div :style='{"cursor":"pointer","padding":"0 10%","color":"#666","textAlign":"center","display":"inline-block","width":"100%","lineHeight":"1","fontSize":"12px","textDecoration":"underline"}' class="r-login" @click="close()">已有账号,直接登录</div>

</el-form>

</div>

</div>

</template>

<script>

export default {

data() {

return {

ruleForm: {

                xingbie: '',

},

            pageFlag : '',

tableName:"",

rules: {},

            yonghuxingbieOptions: [],

};

},

mounted(){

        this.pageFlag = this.$storage.get("pageFlag");

let table = this.$storage.get("loginTable");

this.tableName = table;

        this.yonghuxingbieOptions = "男,女".split(',')

},

created() {

    

},

destroyed() {

   },

methods: {

// 获取uuid

getUUID () {

return new Date().getTime();

},

close(){

this.$router.push({ path: "/login" });

},

        yonghutouxiangUploadChange(fileUrls) {

            this.ruleForm.touxiang = fileUrls;

        },

        // 多级联动参数

// 注册

login() {

var url=this.tableName+"/register";

if((!this.ruleForm.yonghuzhanghao) && `yonghu` == this.tableName){

this.$message.error(`用户账号不能为空`);

return

}

if((!this.ruleForm.mima) && `yonghu` == this.tableName){

this.$message.error(`密码不能为空`);

return

}

if((this.ruleForm.mima!=this.ruleForm.mima2) && `yonghu` == this.tableName){

this.$message.error(`两次密码输入不一致`);

return

}

if((!this.ruleForm.yonghuxingming) && `yonghu` == this.tableName){

this.$message.error(`用户姓名不能为空`);

return

}

第三节 登录模块

管理员在电影信息模块输入账号+密码,点击“登录”按钮,系统在用户数据库表中会对管理员的账号进行匹配,账号+密码正确的话,就会登录到系统中各个用户的主管理界面,否则提示对应的信息,返回到登录的界面。

用户登录流程图如下所示。

        

图4-5 登录流程图

登录界面如下图所示。

图4-6 登录界面图

登录逻辑代码如下。

<template>

  <div>

    <div class="container" :style='{"minHeight":"100vh","alignItems":"center","background":"url(http://codegen.caihongy.cn/20220730/38d36c312f24490289b90e09f4add1b9.png)","display":"flex","width":"100%","backgroundSize":"cover","backgroundPosition":"center center","backgroundRepeat":"no-repeat","justifyContent":"center"}'>

      <el-form :style='{"padding":"40px 50px 20px","boxShadow":"0px 4px 10px 0px #B8DE4B","margin":"-50px 0 0 500px","borderRadius":"0 0 10px 10px","background":"#fff","width":"480px","height":"677px"}'>

        <div v-if="true" :style='{"padding":"10px","margin":"0 0 30px 0","color":"rgba(121, 149, 43, 1)","textAlign":"center","width":"100%","lineHeight":"44px","fontSize":"24px","fontWeight":"600","height":"auto"}' class="title-container">豆瓣电影数据分析可视化系统登录</div>

        <div v-if="loginType==1" class="list-item" :style='{"width":"100%","margin":"0 auto 10px","alignItems":"center","flexWrap":"wrap","display":"flex"}'>

          <div v-if="false" class="lable" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}'>用户名:</div>

          <input :style='{"border":"0","padding":"0 10px","boxShadow":"0px 4px 10px 0px rgba(0,0,0,0.3020)","color":"#333","width":"100%","fontSize":"14px","height":"44px"}' placeholder="请输入用户名" name="username" type="text" v-model="rulesForm.username">

        </div>

        <div v-if="loginType==1" class="list-item" :style='{"width":"100%","margin":"0 auto 10px","alignItems":"center","flexWrap":"wrap","display":"flex"}'>

          <div v-if="false" class="lable" :style='{"width":"64px","lineHeight":"44px","fontSize":"14px","color":"rgba(64, 158, 255, 1)"}'>密码:</div>

          <input :style='{"border":"0","padding":"0 10px","boxShadow":"0px 4px 10px 0px rgba(0,0,0,0.3020)","color":"#333","width":"100%","fontSize":"14px","height":"44px"}' placeholder="请输入密码" name="password" type="password" v-model="rulesForm.password">

        </div>

        <div :style='{"width":"100%","margin":"20px auto","flexWrap":"wrap","display":"flex"}' v-if="roles.length>1" prop="loginInRole" class="list-type">

          <el-radio v-for="item in roles" v-bind:key="item.roleName" v-model="rulesForm.role" :label="item.roleName">{ {item.roleName}}</el-radio>

        </div>

        <div :style='{"width":"100%","margin":"20px auto","alignItems":"center","flexWrap":"wrap","justifyContent":"flex-start","display":"flex"}'>

          <el-button v-if="loginType==1" :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px","outline":"none","color":"#fff","borderRadius":"2px","background":"rgba(193, 227, 97, 1)","width":"100%","fontSize":"18px","fontWeight":"600","height":"50px"}' type="primary" @click="login()" class="loginInBt">登录</el-button>

        </div>

      </el-form>

    </div>

  </div>

</template>

<script>

import menu from "@/utils/menu";

export default {

  data() {

    return {

      baseUrl:this.$base.url,

      loginType: 1,

      rulesForm: {

        username: "",

        password: "",

        role: "",

        code: '',

      },

      menus: [],

      roles: [],

      tableName: "",

      codes: [{

        num: 1,

        color: '#000',

        rotate: '10deg',

        size: '16px'

      },{

        num: 2,

        color: '#000',

        rotate: '10deg',

        size: '16px'

      },{

        num: 3,

        color: '#000',

        rotate: '10deg',

        size: '16px'

      },{

        num: 4,

        color: '#000',

        rotate: '10deg',

        size: '16px'

      }],

    };

  },

  mounted() {

    let menus = menu.list();

    this.menus = menus;

    for (let i = 0; i < this.menus.length; i++) {

      if (this.menus[i].hasBackLogin=='是') {

        this.roles.push(this.menus[i])

      }

    }

  },

  created() {

    this.getRandCode()

  },

  destroyed() {

    },

  components: {

  },

  methods: {

    //注册

    register(tableName){

this.$storage.set("loginTable", tableName);

        this.$storage.set("pageFlag", "register");

this.$router.push({path:'/register'})

    },

    // 登陆

    login() {

if (!this.rulesForm.username) {

this.$message.error("请输入用户名");

return;

}

if (!this.rulesForm.password) {

this.$message.error("请输入密码");

return;

}

if(this.roles.length>1) {

if (!this.rulesForm.role) {

this.$message.error("请选择角色");

return;

}

let menus = this.menus;

for (let i = 0; i < menus.length; i++) {

if (menus[i].roleName == this.rulesForm.role) {

this.tableName = menus[i].tableName;

}

}

} else {

this.tableName = this.roles[0].tableName;

this.rulesForm.role = this.roles[0].roleName;

}

this.$http({

url: `${this.tableName}/login?username=${this.rulesForm.username}&password=${this.rulesForm.password}`,

method: "post"

}).then(({ data }) => {

if (data && data.code === 0) {

this.$storage.set("Token", data.token);

this.$storage.set("role", this.rulesForm.role);

this.$storage.set("sessionTable", this.tableName);

this.$storage.set("adminName", this.rulesForm.username);

this.$router.replace({ path: "/index/" });

} else {

this.$message.error(data.msg);

}

});

    },

    getRandCode(len = 4){

this.randomString(len)

    },

    randomString(len = 4) {

      let chars = [

          "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",

          "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",

          "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",

          "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",

          "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",

          "3", "4", "5", "6", "7", "8", "9"

      ]

      let colors = ["0", "1", "2","3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]

      let sizes = ['14', '15', '16', '17', '18']

      let output = [];

      for (let i = 0; i < len; i++) {

        // 随机验证码

        let key = Math.floor(Math.random()*chars.length)

        this.codes[i].num = chars[key]

        // 随机验证码颜色

        let code = '#'

        for (let j = 0; j < 6; j++) {

          let key = Math.floor(Math.random()*colors.length)

          code += colors[key]

        }

        this.codes[i].color = code

        // 随机验证码方向

        let rotate = Math.floor(Math.random()*60)

        let plus = Math.floor(Math.random()*2)

        if(plus == 1) rotate = '-'+rotate

        this.codes[i].rotate = 'rotate('+rotate+'deg)'

        // 随机验证码字体大小

        let size = Math.floor(Math.random()*sizes.length)

        this.codes[i].size = sizes[size]+'px'

      }

    },

  }

};

</script>

<style lang="scss" scoped>

.container {

  min-height: 100vh;

  position: relative;

  background-repeat: no-repeat;

  background-position: center center;

  background-size: cover;

      background: url(http://codegen.caihongy.cn/20220730/38d36c312f24490289b90e09f4add1b9.png);

        

  .list-item /deep/ .el-input .el-input__inner {

border: 0;

padding: 0 10px;

box-shadow: 0px 4px 10px 0px rgba(0,0,0,0.3020);

color: #333;

width: 100%;

font-size: 14px;

height: 44px;

  }

  

  .list-code /deep/ .el-input .el-input__inner {

      border: 0px solid rgba(64, 158, 255, 1);

      border-radius: 0;

      padding: 0 10px;

      box-shadow: 0px 4px 10px 0px rgba(0,0,0,0.3020);

      outline: none;

      color: #333;

      width: 100%;

      font-size: 14px;

      height: 44px;

     }

  .list-type /deep/ .el-radio__input .el-radio__inner {

background: rgba(53, 53, 53, 0);

border-color: #666666;

position: absolute;

  }

  .list-type /deep/ .el-radio__input.is-checked .el-radio__inner {

        background: rgba(121, 149, 43, 1);

        border-color: rgba(121, 149, 43, 1);

        position: absolute;

      }

  .list-type /deep/ .el-radio__label {

margin: -5px 0 0 10px;

color: #666666;

display: block;

width: 85px;

font-size: 14px;

  }

  .list-type /deep/ .el-radio__input.is-checked+.el-radio__label {

        margin: -5px 0 0 10px;

        color: rgba(121, 149, 43, 1);

        display: block;

        width: 85px;

        font-size: 14px;

      }

}

</style>

第四节 用户管理模块

用户只有注册后才能获得登录使用权限,此时选择注册用户选项,系统会自动转到用户注册。在注册该部分信息时,系统会自动调用ADD函数,然后在给出的文本框中填写完该用户的基本信息后,选择确认即可完成注册。注册后系统会自动转到检索用户信息,在新增用户信息以后,在检索工具栏中填写对应的用户信息,系统就会将该用户有关的所有信息展示出来。

用户管理流程图如下所示。

图4-7 用户管理流程图

用户管理界面如下图所示。

图4-8 用户管理模块图

用户管理逻辑代码如下。

<template>

<div class="main-content" :style='{"minHeight":"100vh","padding":"0px 3%","background":"url(http://codegen.caihongy.cn/20230417/f15cd3c95ab74db6bb97dd6d6b40180e.png) no-repeat center bottom / 100% 100%"}'>

<!-- 列表页 -->

<template v-if="showFlag">

<el-form class="center-form-pv" :style='{"margin":"20px 0 20px 0","position":"relative"}' :inline="true" :model="searchForm">

<el-row :style='{"width":"150px","position":"absolute","top":"20px","left":"0","display":"block","zIndex":"1003"}' >

<div :style='{"margin":"0 0 5px","display":"inline-block"}'>

<label :style='{"margin":"0 10px 0 0","color":"#666","textAlign":"left","display":"inline-block","width":"100px","lineHeight":"40px","fontSize":"14px","fontWeight":"600","height":"40px"}' class="item-label">用户账号</label>

<el-input v-model="searchForm.yonghuzhanghao" placeholder="用户账号" clearable></el-input>

</div>

<div :style='{"margin":"0 0 5px","display":"inline-block"}' class="select" label="性别" prop="xingbie">

<label :style='{"margin":"0 10px 0 0","color":"#666","textAlign":"left","display":"inline-block","width":"100px","lineHeight":"40px","fontSize":"14px","fontWeight":"600","height":"40px"}' class="item-label">性别</label>

<el-select  @change="xingbieChange" clearable v-model="searchForm.xingbie" placeholder="请选择性别">

<el-option v-for="(item,index) in xingbieOptions" v-bind:key="index" :label="item" :value="item"></el-option>

</el-select>

</div>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","outline":"none","margin":"10px 0 0 0","color":"#fff","borderRadius":"4px","background":"rgba(184, 222, 74, 1)","width":"150px","fontSize":"14px","height":"40px"}' type="success" @click="search()">查询</el-button>

</el-row>

<el-row :style='{"margin":"0","justifyContent":"flex-end","display":"flex"}'>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('yonghu','新增')" type="success" @click="addOrUpdateHandler()">新增</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('yonghu','删除')" :disabled="dataListSelections.length <= 0" type="danger" @click="deleteHandler()">删除</el-button>

</el-row>

</el-form>

<!-- <div> -->

<el-table class="tables"

:stripe='false'

:style='{"padding":"0","borderColor":"#eee","margin":"0 0 0 180px","borderWidth":"1px","background":"#fff","flex":"1","width":"auto","borderStyle":"solid"}'

v-if="isAuth('yonghu','查看')"

:data="dataList"

v-loading="dataListLoading"

@selection-change="selectionChangeHandler">

<el-table-column :resizable='true' type="selection" align="center" width="50"></el-table-column>

<el-table-column :resizable='true' :sortable='true' label="序号" type="index" width="50" />

<el-table-column :resizable='true' :sortable='true'  

prop="yonghuzhanghao"

label="用户账号">

<template slot-scope="scope">

{ {scope.row.yonghuzhanghao}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="yonghuxingming"

label="用户姓名">

<template slot-scope="scope">

{ {scope.row.yonghuxingming}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="xingbie"

label="性别">

<template slot-scope="scope">

{ {scope.row.xingbie}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="yonghudianhua"

label="用户电话">

<template slot-scope="scope">

{ {scope.row.yonghudianhua}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true' prop="touxiang" width="200" label="头像">

<template slot-scope="scope">

<div v-if="scope.row.touxiang">

<img v-if="scope.row.touxiang.substring(0,4)=='http'" :src="scope.row.touxiang.split(',')[0]" width="100" height="100">

<img v-else :src="$base.url+scope.row.touxiang.split(',')[0]" width="100" height="100">

</div>

<div v-else>无图片</div>

</template>

</el-table-column>

<el-table-column width="300" label="操作">

<template slot-scope="scope">

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if=" isAuth('yonghu','查看')" type="success" size="mini" @click="addOrUpdateHandler(scope.row.id,'info')">详情</el-button>

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if=" isAuth('yonghu','修改')" type="primary" size="mini" @click="addOrUpdateHandler(scope.row.id)">修改</el-button>

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if="isAuth('yonghu','删除') " type="danger" size="mini" @click="deleteHandler(scope.row.id)">删除</el-button>

</template>

</el-table-column>

</el-table>

<el-pagination

@size-change="sizeChangeHandle"

@current-change="currentChangeHandle"

:current-page="pageIndex"

background

:page-sizes="[10, 20, 30, 50]"

:page-size="pageSize"

:layout="layouts.join()"

:total="totalPage"

prev-text="<"

next-text=">"

:hide-on-single-page="false"

:style='{"padding":"0","margin":"20px 0 0 180px","whiteSpace":"nowrap","color":"#333","textAlign":"center","background":"none","width":"auto","fontWeight":"500"}'

></el-pagination>

<!-- </div> -->

</template>

<!-- 添加/修改页面  将父组件的search方法传递给子组件-->

<add-or-update v-if="addOrUpdateFlag" :parent="this" ref="addOrUpdate"></add-or-update>

</div>

</template>

<script>

//$graphType1

//$buttonName1

//$subNameList1

import axios from 'axios'

import AddOrUpdate from "./add-or-update";

export default {

  data() {

    return {

      searchForm: {

        key: ""

      },

      form:{},

      dataList: [],

      pageIndex: 1,

      pageSize: 10,

      totalPage: 0,

      dataListLoading: false,

      dataListSelections: [],

      showFlag: true,

      sfshVisiable: false,

      shForm: {},

      chartVisiable: false,

      chartVisiable1: false,

      chartVisiable2: false,

      chartVisiable3: false,

      chartVisiable4: false,

      chartVisiable5: false,

      addOrUpdateFlag:false,

      layouts: ["total","prev","pager","next","sizes","jumper"],

    };

  },

  created() {

    this.init();

    this.getDataList();

    this.contentStyleChange()

  },

  mounted() {

  },

  filters: {

    htmlfilter: function (val) {

      return val.replace(/<[^>]*>/g).replace(/undefined/g,'');

    }

  },

  components: {

    AddOrUpdate,

  },

  methods: {

    contentStyleChange() {

      this.contentPageStyleChange()

    },

    // 分页

    contentPageStyleChange(){

      let arr = []

      // if(this.contents.pageTotal) arr.push('total')

      // if(this.contents.pageSizes) arr.push('sizes')

      // if(this.contents.pagePrevNext){

      //   arr.push('prev')

      //   if(this.contents.pagePager) arr.push('pager')

      //   arr.push('next')

      // }

      // if(this.contents.pageJumper) arr.push('jumper')

      // this.layouts = arr.join()

      // this.contents.pageEachNum = 10

    },

    init () {

          this.xingbieOptions = "男,女".split(',')

    },

    search() {

      this.pageIndex = 1;

      this.getDataList();

    },

    // 获取数据列表

    getDataList() {

      this.dataListLoading = true;

      let params = {

        page: this.pageIndex,

        limit: this.pageSize,

        sort: 'id',

        order: 'desc',

      }

           if(this.searchForm.yonghuzhanghao!='' && this.searchForm.yonghuzhanghao!=undefined){

            params['yonghuzhanghao'] = '%' + this.searchForm.yonghuzhanghao + '%'

          }

           if(this.searchForm.xingbie!='' && this.searchForm.xingbie!=undefined){

            params['xingbie'] = this.searchForm.xingbie

          }

      this.$http({

        url: "yonghu/page",

        method: "get",

        params: params

      }).then(({ data }) => {

        if (data && data.code === 0) {

          this.dataList = data.data.list;

          this.totalPage = data.data.total;

        } else {

          this.dataList = [];

          this.totalPage = 0;

        }

        this.dataListLoading = false;

      });

    },

    // 每页数

    sizeChangeHandle(val) {

      this.pageSize = val;

      this.pageIndex = 1;

      this.getDataList();

    },

    // 当前页

    currentChangeHandle(val) {

      this.pageIndex = val;

      this.getDataList();

    },

    // 多选

    selectionChangeHandler(val) {

      this.dataListSelections = val;

    },

    // 添加/修改

    addOrUpdateHandler(id,type) {

      this.showFlag = false;

      this.addOrUpdateFlag = true;

      this.crossAddOrUpdateFlag = false;

      if(type!='info'){

        type = 'else';

      }

      this.$nextTick(() => {

        this.$refs.addOrUpdate.init(id,type);

      });

    },

    // 下载

    download(file){

      window.open(`${file}`)

    },

    // 删除

    deleteHandler(id) {

      var ids = id

        ? [Number(id)]

        : this.dataListSelections.map(item => {

            return Number(item.id);

          });

      this.$confirm(`确定进行[${id ? "删除" : "批量删除"}]操作?`, "提示", {

        confirmButtonText: "确定",

        cancelButtonText: "取消",

        type: "warning"

      }).then(() => {

        this.$http({

          url: "yonghu/delete",

          method: "post",

          data: ids

        }).then(({ data }) => {

          if (data && data.code === 0) {

            this.$message({

              message: "操作成功",

              type: "success",

              duration: 1500,

              onClose: () => {

                this.search();

              }

            });

          } else {

            this.$message.error(data.msg);

          }

        });

      });

    },

  }

};

</script>

<style lang="scss" scoped>

.center-form-pv {

  .el-date-editor.el-input {

    width: auto;

  }

}

.el-input {

  width: auto;

}

// form

.center-form-pv .el-input /deep/ .el-input__inner {

border: 2px solid #B8DE4A;

border-radius: 4px;

padding: 0 12px;

outline: none;

color: rgba(0, 0, 0, 1);

width: 150px;

font-size: 14px;

height: 40px;

}

.center-form-pv .el-select /deep/ .el-input__inner {

border: 2px solid #B8DE4A;

border-radius: 4px;

padding: 0 10px;

outline: none;

color: rgba(0, 0, 0, 1);

width: 150px;

font-size: 14px;

height: 40px;

}

.center-form-pv .el-date-editor /deep/ .el-input__inner {

border: 2px solid #B8DE4A;

border-radius: 4px;

padding: 0 10px 0 30px;

outline: none;

color: rgba(0, 0, 0, 1);

width: 150px;

font-size: 14px;

height: 40px;

}

// table

.el-table /deep/ .el-table__header-wrapper thead {

color: #333;

font-weight: 500;

width: 100%;

}

.el-table /deep/ .el-table__header-wrapper thead tr {

background: #fff;

}

.el-table /deep/ .el-table__header-wrapper thead tr th {

padding: 12px 0;

background: rgba(226, 226, 226, 1);

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__header-wrapper thead tr th .cell {

padding: 0 10px;

word-wrap: normal;

word-break: break-all;

white-space: normal;

font-weight: bold;

display: inline-block;

vertical-align: middle;

width: 100%;

line-height: 24px;

position: relative;

text-overflow: ellipsis;

}

.el-table /deep/ .el-table__body-wrapper tbody {

width: 100%;

}

.el-table /deep/ .el-table__body-wrapper tbody tr {

background: #fff;

}

.el-table /deep/ .el-table__body-wrapper tbody tr td {

padding: 6px 0;

color: #999;

background: #fff;

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__body-wrapper tbody tr:hover td {

padding: 6px 0;

color: #333;

background: rgba(226, 226, 226, .2);

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__body-wrapper tbody tr td {

padding: 6px 0;

color: #999;

background: #fff;

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__body-wrapper tbody tr td .cell {

padding: 0 10px;

overflow: hidden;

word-break: break-all;

white-space: normal;

line-height: 24px;

text-overflow: ellipsis;

}

// pagination

.main-content .el-pagination /deep/ .el-pagination__total {

margin: 0 10px 0 0;

color: #666;

font-weight: 400;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-prev {

border: none;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #666;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

min-width: 35px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-next {

border: none;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #666;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

min-width: 35px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-prev:disabled {

border: none;

cursor: not-allowed;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #C0C4CC;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-next:disabled {

border: none;

cursor: not-allowed;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #C0C4CC;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pager {

padding: 0;

margin: 0;

display: inline-block;

vertical-align: top;

}

.main-content .el-pagination /deep/ .el-pager .number {

cursor: pointer;

padding: 0 4px;

margin: 0 5px;

color: #666;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

border-radius: 2px;

background: #f4f4f5;

text-align: center;

min-width: 30px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pager .number:hover {

cursor: pointer;

padding: 0 4px;

margin: 0 5px;

color: #b8de4a;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

border-radius: 2px;

background: #f4f4f5;

text-align: center;

min-width: 30px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pager .number.active {

cursor: default;

padding: 0 4px;

margin: 0 5px;

color: #FFF;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

border-radius: 2px;

background: #b8de4a;

text-align: center;

min-width: 30px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__sizes {

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input {

margin: 0 5px;

width: 100px;

position: relative;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input .el-input__inner {

border: 1px solid #DCDFE6;

cursor: pointer;

padding: 0 25px 0 8px;

color: #606266;

display: inline-block;

font-size: 13px;

line-height: 28px;

border-radius: 3px;

outline: 0;

background: #FFF;

width: 100%;

text-align: center;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input span.el-input__suffix {

top: 0;

position: absolute;

right: 0;

height: 100%;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input .el-input__suffix .el-select__caret {

cursor: pointer;

color: #C0C4CC;

width: 25px;

font-size: 14px;

line-height: 28px;

text-align: center;

}

.main-content .el-pagination /deep/ .el-pagination__jump {

margin: 0 0 0 24px;

color: #606266;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__jump .el-input {

border-radius: 3px;

padding: 0 2px;

margin: 0 2px;

display: inline-block;

width: 50px;

font-size: 14px;

line-height: 18px;

position: relative;

text-align: center;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__jump .el-input .el-input__inner {

border: 1px solid #DCDFE6;

cursor: pointer;

padding: 0 3px;

color: #606266;

display: inline-block;

font-size: 14px;

line-height: 28px;

border-radius: 3px;

outline: 0;

background: #FFF;

width: 100%;

text-align: center;

height: 28px;

}

</style>

第五节 电影信息模块

豆瓣电影数据分析可视化系统的电影信息可以通过ajax技术快速、准确地获取,用户可以根据自己的偏好和需求,快速地调整和更新相关的内容,从而满足用户的需求。此外,用户还可以根据自己的偏好,自由地调整和更新相关的内容,从而更好地满足豆瓣用户的需求。当用户选择进行更新,系统会根据用户的id进行查询,然后将查询结果反馈给用户。用户可以在更新页面上更新所需的信息。用户点击更新按钮,from表单会把更新的内容发送给系统,然后系统会把这些内容保存到数据库中。

电影信息管理如下图所示。

图4-9电影信息管理界面图

对评分数据进行统计,并以柱状图的形式呈现,通过这个柱状图用户可以直观的看到各个电影的评分对比,更加清晰了解每个电影的评分情况,这样的柱状图可以让用户了解电影评价的差异性,并更好地进行比较和选择。

图表可视化界面如下图所示:

图4-10评分数据

该系统还会将各个电影的片长数据进行统计,呈现曲线图。呈现不同电影片长的曲线分布,更好地了解电影市场和观众的需求变化。这样的曲线图结果可以为用户提供更全面的电影信息,帮助用户做出更明智的观影选择。

图4-11片长数据统计

该系统还可以对豆瓣电影网站上的电影名称进行词云统计。它会对所有电影名称进行分词,然后根据每个词出现的频率来生成词云图。词云图中,出现频率高的词汇会以较大的字号和较鲜艳的颜色出现,表示这些词汇在电影名称中出现的频率很高。通过这个词云图,用户可以了解到热门电影所采用的命名方式和命名元素,以及电影名称的风格和特点。这些信息可以为用户提供更多的观影参考和选择建议。

图4-12 词云统计

系统会通过爬取豆瓣电影网站上的影片数据,统计每位导演所导演的电影数量以及平均评分,并形成对应的词云图。词云图中,导演的名字大小和颜色的变化会根据他们所导演的电影数量和平均评分的高低进行相应的调整,较大的字体和深色的颜色表示导演拍摄了较多的电影,并且评分较高。通过这个词云图,用户可以了解到各个导演的电影数量和平均评分情况,并对他们的导演风格和成就进行评估和比较。

图4-13 词云图

通过分析豆瓣电影网站上各位导演所导演的电影数量,该系统可以生成一个导演作品数量的占比饼状图。该图表展示了豆瓣电影网站上数量较多的导演和他们所导演的电影数量,用户可以通过该图表了解作品数量前十的导演占比情况,以更直观地呈现各位导演的整体水平。

图4-14导演作品数量的占比饼状图

系统还可以对豆瓣电影网站上的电影类型进行分类和统计,并生成电影类型分布的占比饼状图。该图表展示了各种电影类型在豆瓣电影网站上的占比情况,例如喜剧、爱情、动作、悬疑、恐怖等不同类型的电影。通过该图表,用户可以了解到当前热门的电影类型和受欢迎的题材,以及豆瓣电影网站用户的观影偏好和口味。在选择观影时,用户可以参考该图表对自己的观影选择进行调整和优化。

图4-15影片分类统计

该条形图可以展示不同语言电影的数量,用户可以根据该图表了解当前各种语言的电影数量的分布情况,并可以根据自己的需求和口味进行观影选择。

图4-16图表可视化界面

数据统计管理页面可查看评分统计、片长、导演、类型、评语言等信息操作如图所示:

图4-17数据统计界面

电影信息逻辑代码如下。

<template>

<div class="main-content" :style='{"minHeight":"100vh","padding":"0px 3%","background":"url(http://codegen.caihongy.cn/20230417/f15cd3c95ab74db6bb97dd6d6b40180e.png) no-repeat center bottom / 100% 100%"}'>

<!-- 列表页 -->

<template v-if="showFlag">

<el-form class="center-form-pv" :style='{"margin":"20px 0 20px 0","position":"relative"}' :inline="true" :model="searchForm">

<el-row :style='{"width":"150px","position":"absolute","top":"20px","left":"0","display":"block","zIndex":"1003"}' >

<div :style='{"margin":"0 0 5px","display":"inline-block"}'>

<label :style='{"margin":"0 10px 0 0","color":"#666","textAlign":"left","display":"inline-block","width":"100px","lineHeight":"40px","fontSize":"14px","fontWeight":"600","height":"40px"}' class="item-label">电影名</label>

<el-input v-model="searchForm.dianyingming" placeholder="电影名" clearable></el-input>

</div>

<div :style='{"margin":"0 0 5px","display":"inline-block"}'>

<label :style='{"margin":"0 10px 0 0","color":"#666","textAlign":"left","display":"inline-block","width":"100px","lineHeight":"40px","fontSize":"14px","fontWeight":"600","height":"40px"}' class="item-label">导演</label>

<el-input v-model="searchForm.daoyan" placeholder="导演" clearable></el-input>

</div>

<div :style='{"margin":"0 0 5px","display":"inline-block"}'>

<label :style='{"margin":"0 10px 0 0","color":"#666","textAlign":"left","display":"inline-block","width":"100px","lineHeight":"40px","fontSize":"14px","fontWeight":"600","height":"40px"}' class="item-label">编剧</label>

<el-input v-model="searchForm.bianju" placeholder="编剧" clearable></el-input>

</div>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","outline":"none","margin":"10px 0 0 0","color":"#fff","borderRadius":"4px","background":"rgba(184, 222, 74, 1)","width":"150px","fontSize":"14px","height":"40px"}' type="success" @click="search()">查询</el-button>

</el-row>

<el-row :style='{"margin":"0","justifyContent":"flex-end","display":"flex"}'>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','新增')" type="success" @click="addOrUpdateHandler()">新增</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','删除')" :disabled="dataListSelections.length <= 0" type="danger" @click="deleteHandler()">删除</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','导入')" type="success" @click="importHandler()">导入</el-button>

                    <el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','上传模板')" type="success" @click="importClcik">上传模板</el-button>

                    <el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','下载模板')" type="success" @click="download($base.url + 'upload/dianyingxinxi_template.xlsx')">下载模板</el-button>

<download-excel v-if="isAuth('dianyingxinxi','导出')" class="export-excel-wrapper" :data = "dataList" :fields = "json_fields" name = "电影信息.xls">

<!-- 导出excel -->

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' type="danger">导出</el-button>

</download-excel>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','爬取数据')" type="success" @click="spider()">爬取数据</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','评分')" type="warning" @click="chartDialog1()">评分</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','片长')" type="warning" @click="chartDialog2()">片长</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','导演')" type="warning" @click="chartDialog4()">导演</el-button>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0 24px","margin":"0 10px 0 0","outline":"none","color":"#333","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"auto","fontSize":"14px","height":"40px"}' v-if="isAuth('dianyingxinxi','类型')" type="warning" @click="chartDialog5()">类型</el-button>

</el-row>

</el-form>

<!-- <div> -->

<el-table class="tables"

:stripe='false'

:style='{"padding":"0","borderColor":"#eee","margin":"0 0 0 180px","borderWidth":"1px","background":"#fff","flex":"1","width":"auto","borderStyle":"solid"}'

v-if="isAuth('dianyingxinxi','查看')"

:data="dataList"

v-loading="dataListLoading"

@selection-change="selectionChangeHandler">

<el-table-column :resizable='true' type="selection" align="center" width="50"></el-table-column>

<el-table-column :resizable='true' :sortable='true' label="序号" type="index" width="50" />

<el-table-column :resizable='true' :sortable='true'  

prop="dianyingming"

label="电影名">

<template slot-scope="scope">

{ {scope.row.dianyingming}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="daoyan"

label="导演">

<template slot-scope="scope">

{ {scope.row.daoyan}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="bianju"

label="编剧">

<template slot-scope="scope">

{ {scope.row.bianju}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="zhuyan"

label="主演">

<template slot-scope="scope">

{ {scope.row.zhuyan}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="leixing"

label="类型">

<template slot-scope="scope">

{ {scope.row.leixing}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="yuyan"

label="语言">

<template slot-scope="scope">

{ {scope.row.yuyan}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="syrq"

label="上映日期">

<template slot-scope="scope">

{ {scope.row.syrq}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="pianchang"

label="片长">

<template slot-scope="scope">

{ {scope.row.pianchang}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="pingfen"

label="评分">

<template slot-scope="scope">

{ {scope.row.pingfen}}

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true' prop="fengmian" width="200" label="封面">

<template slot-scope="scope">

<div v-if="scope.row.fengmian">

<img v-if="scope.row.fengmian.substring(0,4)=='http'" :src="scope.row.fengmian.split(',')[0]" width="100" height="100">

<img v-else :src="$base.url+scope.row.fengmian.split(',')[0]" width="100" height="100">

</div>

<div v-else>无图片</div>

</template>

</el-table-column>

<el-table-column :resizable='true' :sortable='true'  

prop="clicknum"

label="点击次数">

<template slot-scope="scope">

{ {scope.row.clicknum}}

</template>

</el-table-column>

<el-table-column width="300" label="操作">

<template slot-scope="scope">

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if=" isAuth('dianyingxinxi','查看')" type="success" size="mini" @click="addOrUpdateHandler(scope.row.id,'info')">详情</el-button>

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if=" isAuth('dianyingxinxi','修改')" type="primary" size="mini" @click="addOrUpdateHandler(scope.row.id)">修改</el-button>

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if="isAuth('dianyingxinxi','查看评论')" type="primary" size="mini" @click="disscussListHandler(scope.row.id)">查看评论</el-button>

<el-button :style='{"border":"1px solid #AAAAAA","cursor":"pointer","padding":"0 24px","margin":"0 6px 5px 0","outline":"none","color":"#AAAAAA","borderRadius":"20px","background":"#fff","width":"auto","fontSize":"14px","height":"32px"}' v-if="isAuth('dianyingxinxi','删除') " type="danger" size="mini" @click="deleteHandler(scope.row.id)">删除</el-button>

</template>

</el-table-column>

</el-table>

<el-pagination

@size-change="sizeChangeHandle"

@current-change="currentChangeHandle"

:current-page="pageIndex"

background

:page-sizes="[10, 20, 30, 50]"

:page-size="pageSize"

:layout="layouts.join()"

:total="totalPage"

prev-text="<"

next-text=">"

:hide-on-single-page="false"

:style='{"padding":"0","margin":"20px 0 0 180px","whiteSpace":"nowrap","color":"#333","textAlign":"center","background":"none","width":"auto","fontWeight":"500"}'

></el-pagination>

<!-- </div> -->

</template>

<!-- 添加/修改页面  将父组件的search方法传递给子组件-->

<add-or-update v-if="addOrUpdateFlag" :parent="this" ref="addOrUpdate"></add-or-update>

<el-dialog title="导入" :visible.sync="importVisiable" width="50%">

<el-form ref="form" :model="form" label-width="80px">

<el-form-item class="upload" label="文件" prop="excelFile">

  <excel-file-upload

  tip="点击上传直接导入excel文件"

  action="dianyingxinxi/importExcel"

  :limit="1"

                  @change="importChange"

  ></excel-file-upload>

</el-form-item>

</el-form>

<span slot="footer" class="dialog-footer">

<el-button @click="importHandler()">关 闭</el-button>

</span>

</el-dialog>

        <el-dialog title="上传模板" :visible.sync="importVis" width="50%">

            <el-form ref="form" :model="importForm" label-width="80px">

                <el-form-item class="upload" label="文件" prop="excelFile">

                    <el-upload class="upload-demo" drag :action="$base.url + 'file/upload?type=dianyingxinxi_template'"

                        :show-file-list="false" :on-success="importSuccess">

                        <i class="el-icon-upload"></i>

                        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>

                    </el-upload>

                </el-form-item>

            </el-form>

            <span slot="footer" class="dialog-footer">

                <el-button @click="importVis=false">关 闭</el-button>

            </span>

        </el-dialog>

<el-dialog

  :visible.sync="chartVisiable1"

  width="800">

<div id="pingfenChart1" style="width:100%;height:600px;"></div>

  <span slot="footer" class="dialog-footer">

<el-button @click="chartDialog1">返回</el-button>

  </span>

</el-dialog>

<el-dialog

  :visible.sync="chartVisiable2"

  width="800">

<div id="pianchangChart2" style="width:100%;height:600px;"></div>

  <span slot="footer" class="dialog-footer">

<el-button @click="chartDialog2">返回</el-button>

  </span>

</el-dialog>

<el-dialog

  :visible.sync="chartVisiable4"

  width="800">

<div id="daoyanChart4" style="width:100%;height:600px;"></div>

  <span slot="footer" class="dialog-footer">

<el-button @click="chartDialog4">返回</el-button>

  </span>

</el-dialog>

<el-dialog

  :visible.sync="chartVisiable5"

  width="800">

<div id="leixingChart5" style="width:100%;height:600px;"></div>

  <span slot="footer" class="dialog-footer">

<el-button @click="chartDialog5">返回</el-button>

  </span>

</el-dialog>

</div>

</template>

<script>

//竖

//评分

//[]

import * as echarts from 'echarts'

import axios from 'axios'

import AddOrUpdate from "./add-or-update";

export default {

  data() {

    return {

      searchForm: {

        key: ""

      },

      form:{},

      dataList: [],

      pageIndex: 1,

      pageSize: 10,

      totalPage: 0,

      dataListLoading: false,

      dataListSelections: [],

      showFlag: true,

      sfshVisiable: false,

      shForm: {},

      importVisiable: false,

      importVis: false,

      importForm: {},

      chartVisiable: false,

      chartVisiable1: false,

      chartVisiable2: false,

      chartVisiable3: false,

      chartVisiable4: false,

      chartVisiable5: false,

      addOrUpdateFlag:false,

      layouts: ["total","prev","pager","next","sizes","jumper"],

//导出excel

      json_fields: {

      "电影名": "dianyingming",    //常规字段

      "导演": "daoyan",    //常规字段

      "编剧": "bianju",    //常规字段

      "主演": "zhuyan",    //常规字段

      "类型": "leixing",    //常规字段

      "语言": "yuyan",    //常规字段

      "上映日期": "syrq",    //常规字段

      "片长": "pianchang",    //常规字段

      "评分": "pingfen",    //常规字段

      "剧情介绍": "detail",    //常规字段

      "热门评论": "remenpinglun",    //常规字段

      "封面": "fengmian",    //常规字段

      "最近点击时间": "clicktime",    //常规字段

      "点击次数": "clicknum",    //常规字段

      },

      json_meta: [

        [

          {

            " key ": " charset ",

            " value ": " utf- 8 "

          }

        ]

      ],

    };

  },

  created() {

    this.init();

    this.getDataList();

    this.contentStyleChange()

  },

  mounted() {

  },

  filters: {

    htmlfilter: function (val) {

      return val.replace(/<[^>]*>/g).replace(/undefined/g,'');

    }

  },

  components: {

    AddOrUpdate,

  },

  methods: {

    contentStyleChange() {

      this.contentPageStyleChange()

    },

    // 分页

    contentPageStyleChange(){

      let arr = []

      // if(this.contents.pageTotal) arr.push('total')

      // if(this.contents.pageSizes) arr.push('sizes')

      // if(this.contents.pagePrevNext){

      //   arr.push('prev')

      //   if(this.contents.pagePager) arr.push('pager')

      //   arr.push('next')

      // }

      // if(this.contents.pageJumper) arr.push('jumper')

      // this.layouts = arr.join()

      // this.contents.pageEachNum = 10

    },

//统计接口

    chartDialog1() {

      this.chartVisiable1 = !this.chartVisiable1;

      this.$nextTick(()=>{

        var pingfenChart1 = echarts.init(document.getElementById("pingfenChart1"),'macarons');

        this.$http({

            url: `dianyingxinxi/value/dianyingming/pingfen`,

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].dianyingming);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].dianyingming

                    })

                }

                var option = {};

                option = {

                    title: {

                        text: '评分',

                        left: 'center'

                    },

                    tooltip: {

                      trigger: 'item',

                      formatter: '{b} : {c}'

                    },

                    xAxis: {

                        type: 'category',

                        data: xAxis,

                        axisLabel : {

                            rotate:70

                        }

                    },

                    yAxis: {

                        type: 'value'

                    },

                    series: [{

                        data: yAxis,

                        type: 'bar'

                    }]

                };

                // 使用刚指定的配置项和数据显示图表。

                pingfenChart1.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    pingfenChart1.resize();

                };

            }

        });

      })

    },

//统计接口

    chartDialog2() {

      this.chartVisiable2 = !this.chartVisiable2;

      this.$nextTick(()=>{

        // dianyingming dianyingming

        //  pianchang

        var pianchangChart2 = echarts.init(document.getElementById("pianchangChart2"),'macarons');

        this.$http({

            url: `dianyingxinxi/value/dianyingming/pianchang`,

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].dianyingming);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].dianyingming

                    })

                }

                var option = {};

                option = {

                    title: {

                        text: '片长',

                        left: 'center'

                    },

                    tooltip: {

                      trigger: 'item',

                      formatter: '{b} : {c}'

                    },

                    xAxis: {

                        type: 'category',

                        boundaryGap: false,

                        data: xAxis

                    },

                    yAxis: {

                        type: 'value'

                    },

                    series: [{

                        data: yAxis,

                        type: 'line',

                        areaStyle: {},

                        smooth: true

                    }]

                };

                // 使用刚指定的配置项和数据显示图表。

                pianchangChart2.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    pianchangChart2.resize();

                };

            }

        });

      })

    },

//统计接口

    chartDialog4() {

      this.chartVisiable4 = !this.chartVisiable4;

      this.$nextTick(()=>{

        var daoyanChart4 = echarts.init(document.getElementById("daoyanChart4"),'macarons');

        this.$http({

            url: "dianyingxinxi/group/daoyan",

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].daoyan);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].daoyan

                    })

                }

                var option = {};

                option = {

                        title: {

                            text: '导演',

                            left: 'center'

                        },

                        legend: {

                          orient: 'vertical',

                          left: 'left'

                        },

                        tooltip: {

                          trigger: 'item',

                          formatter: '{b} : {c} ({d}%)'

                        },

                        series: [

                            {

                                type: 'pie',

                                radius: '55%',

                                center: ['50%', '60%'],

                                data: pArray,

                                emphasis: {

                                    itemStyle: {

                                        shadowBlur: 10,

                                        shadowOffsetX: 0,

                                        shadowColor: 'rgba(0, 0, 0, 0.5)'

                                    }

                                }

                            }

                        ]

                };

                // 使用刚指定的配置项和数据显示图表。

                daoyanChart4.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    daoyanChart4.resize();

                };

            }

        });

      })

    },

//统计接口

    chartDialog5() {

      this.chartVisiable5 = !this.chartVisiable5;

      this.$nextTick(()=>{

        var leixingChart5 = echarts.init(document.getElementById("leixingChart5"),'macarons');

        this.$http({

            url: "dianyingxinxi/group/leixing",

            method: "get",

        }).then(({ data }) => {

            if (data && data.code === 0) {

                let res = data.data;

                let xAxis = [];

                let yAxis = [];

                let pArray = []

                for(let i=0;i<res.length;i++){

                    xAxis.push(res[i].leixing);

                    yAxis.push(parseFloat((res[i].total)));

                    pArray.push({

                        value: parseFloat((res[i].total)),

                        name: res[i].leixing

                    })

                }

                var option = {};

                option = {

                        title: {

                            text: '类型',

                            left: 'center'

                        },

                        legend: {

                          orient: 'vertical',

                          left: 'left'

                        },

                        tooltip: {

                          trigger: 'item',

                          formatter: '{b} : {c} ({d}%)'

                        },

                        series: [

                            {

                                type: 'pie',

                                radius: ['25%', '55%'],

                                center: ['50%', '60%'],

                                data: pArray,

                                emphasis: {

                                    itemStyle: {

                                        shadowBlur: 10,

                                        shadowOffsetX: 0,

                                        shadowColor: 'rgba(0, 0, 0, 0.5)'

                                    }

                                }

                            }

                        ]

                };

                // 使用刚指定的配置项和数据显示图表。

                leixingChart5.setOption(option);

                  //根据窗口的大小变动图表

                window.onresize = function() {

                    leixingChart5.resize();

                };

            }

        });

      })

    },

    init () {

    },

    search() {

      this.pageIndex = 1;

      this.getDataList();

    },

    // 获取数据列表

    getDataList() {

      this.dataListLoading = true;

      let params = {

        page: this.pageIndex,

        limit: this.pageSize,

        sort: 'id',

        order: 'desc',

      }

           if(this.searchForm.dianyingming!='' && this.searchForm.dianyingming!=undefined){

            params['dianyingming'] = '%' + this.searchForm.dianyingming + '%'

          }

           if(this.searchForm.daoyan!='' && this.searchForm.daoyan!=undefined){

            params['daoyan'] = '%' + this.searchForm.daoyan + '%'

          }

           if(this.searchForm.bianju!='' && this.searchForm.bianju!=undefined){

            params['bianju'] = '%' + this.searchForm.bianju + '%'

          }

      this.$http({

        url: "dianyingxinxi/page",

        method: "get",

        params: params

      }).then(({ data }) => {

        if (data && data.code === 0) {

          this.dataList = data.data.list;

          this.totalPage = data.data.total;

        } else {

          this.dataList = [];

          this.totalPage = 0;

        }

        this.dataListLoading = false;

      });

    },

    // 每页数

    sizeChangeHandle(val) {

      this.pageSize = val;

      this.pageIndex = 1;

      this.getDataList();

    },

    // 当前页

    currentChangeHandle(val) {

      this.pageIndex = val;

      this.getDataList();

    },

    // 多选

    selectionChangeHandler(val) {

      this.dataListSelections = val;

    },

    // 添加/修改

    addOrUpdateHandler(id,type) {

      this.showFlag = false;

      this.addOrUpdateFlag = true;

      this.crossAddOrUpdateFlag = false;

      if(type!='info'){

        type = 'else';

      }

      this.$nextTick(() => {

        this.$refs.addOrUpdate.init(id,type);

      });

    },

    importChange(){

        this.importHandler()

        this.getDataList()

    },

    importClcik() {

        this.importVis = true

    },

    importSuccess(e) {

        if(e.code==0){

            this.$message.success('上传成功');

            this.importVis = false

            

        }

    },

    importHandler() {

        this.importVisiable = !this.importVisiable;

    },

    // 查看评论

    disscussListHandler(id,type) {

this.$router.push({path:'/discussdianyingxinxi',query:{refid:id}});

    },

    // 下载

    download(file){

      window.open(`${file}`)

    },

    // 删除

    deleteHandler(id) {

      var ids = id

        ? [Number(id)]

        : this.dataListSelections.map(item => {

            return Number(item.id);

          });

      this.$confirm(`确定进行[${id ? "删除" : "批量删除"}]操作?`, "提示", {

        confirmButtonText: "确定",

        cancelButtonText: "取消",

        type: "warning"

      }).then(() => {

        this.$http({

          url: "dianyingxinxi/delete",

          method: "post",

          data: ids

        }).then(({ data }) => {

          if (data && data.code === 0) {

            this.$message({

              message: "操作成功",

              type: "success",

              duration: 1500,

              onClose: () => {

                this.search();

              }

            });

          } else {

            this.$message.error(data.msg);

          }

        });

      });

    },

    spider() {

        this.$message({

              message: "数据爬取中...",

              type: "success",

              duration: 3000,

              onClose: () => {

                this.search();

              }

            });

        this.$http({

          url: "spider/dianyingxinxi",

          method: "get",

        }).then(({ data }) => {

          if (data && data.code === 0) {

            this.$message({

                message: "爬取完成",

                type: "success",

                duration: 1500,

                onClose: () => {

                    this.getDataList(this.roleName);

                }

            });

          } else {

            this.$alert(data.msg)

          }

        });

    },

  }

};

</script>

<style lang="scss" scoped>

//导出excel

.export-excel-wrapper{

display: inline-block;

}

.center-form-pv {

  .el-date-editor.el-input {

    width: auto;

  }

}

.el-input {

  width: auto;

}

// form

.center-form-pv .el-input /deep/ .el-input__inner {

border: 2px solid #B8DE4A;

border-radius: 4px;

padding: 0 12px;

outline: none;

color: rgba(0, 0, 0, 1);

width: 150px;

font-size: 14px;

height: 40px;

}

.center-form-pv .el-select /deep/ .el-input__inner {

border: 2px solid #B8DE4A;

border-radius: 4px;

padding: 0 10px;

outline: none;

color: rgba(0, 0, 0, 1);

width: 150px;

font-size: 14px;

height: 40px;

}

.center-form-pv .el-date-editor /deep/ .el-input__inner {

border: 2px solid #B8DE4A;

border-radius: 4px;

padding: 0 10px 0 30px;

outline: none;

color: rgba(0, 0, 0, 1);

width: 150px;

font-size: 14px;

height: 40px;

}

// table

.el-table /deep/ .el-table__header-wrapper thead {

color: #333;

font-weight: 500;

width: 100%;

}

.el-table /deep/ .el-table__header-wrapper thead tr {

background: #fff;

}

.el-table /deep/ .el-table__header-wrapper thead tr th {

padding: 12px 0;

background: rgba(226, 226, 226, 1);

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__header-wrapper thead tr th .cell {

padding: 0 10px;

word-wrap: normal;

word-break: break-all;

white-space: normal;

font-weight: bold;

display: inline-block;

vertical-align: middle;

width: 100%;

line-height: 24px;

position: relative;

text-overflow: ellipsis;

}

.el-table /deep/ .el-table__body-wrapper tbody {

width: 100%;

}

.el-table /deep/ .el-table__body-wrapper tbody tr {

background: #fff;

}

.el-table /deep/ .el-table__body-wrapper tbody tr td {

padding: 6px 0;

color: #999;

background: #fff;

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__body-wrapper tbody tr:hover td {

padding: 6px 0;

color: #333;

background: rgba(226, 226, 226, .2);

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__body-wrapper tbody tr td {

padding: 6px 0;

color: #999;

background: #fff;

border-color: #eee;

border-width: 0 1px 1px 0;

border-style: solid;

text-align: center;

}

.el-table /deep/ .el-table__body-wrapper tbody tr td .cell {

padding: 0 10px;

overflow: hidden;

word-break: break-all;

white-space: normal;

line-height: 24px;

text-overflow: ellipsis;

}

// pagination

.main-content .el-pagination /deep/ .el-pagination__total {

margin: 0 10px 0 0;

color: #666;

font-weight: 400;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-prev {

border: none;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #666;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

min-width: 35px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-next {

border: none;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #666;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

min-width: 35px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-prev:disabled {

border: none;

cursor: not-allowed;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #C0C4CC;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .btn-next:disabled {

border: none;

cursor: not-allowed;

border-radius: 2px;

padding: 0;

margin: 0 5px;

color: #C0C4CC;

background: #f4f4f5;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pager {

padding: 0;

margin: 0;

display: inline-block;

vertical-align: top;

}

.main-content .el-pagination /deep/ .el-pager .number {

cursor: pointer;

padding: 0 4px;

margin: 0 5px;

color: #666;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

border-radius: 2px;

background: #f4f4f5;

text-align: center;

min-width: 30px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pager .number:hover {

cursor: pointer;

padding: 0 4px;

margin: 0 5px;

color: #b8de4a;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

border-radius: 2px;

background: #f4f4f5;

text-align: center;

min-width: 30px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pager .number.active {

cursor: default;

padding: 0 4px;

margin: 0 5px;

color: #FFF;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

border-radius: 2px;

background: #b8de4a;

text-align: center;

min-width: 30px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__sizes {

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input {

margin: 0 5px;

width: 100px;

position: relative;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input .el-input__inner {

border: 1px solid #DCDFE6;

cursor: pointer;

padding: 0 25px 0 8px;

color: #606266;

display: inline-block;

font-size: 13px;

line-height: 28px;

border-radius: 3px;

outline: 0;

background: #FFF;

width: 100%;

text-align: center;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input span.el-input__suffix {

top: 0;

position: absolute;

right: 0;

height: 100%;

}

.main-content .el-pagination /deep/ .el-pagination__sizes .el-input .el-input__suffix .el-select__caret {

cursor: pointer;

color: #C0C4CC;

width: 25px;

font-size: 14px;

line-height: 28px;

text-align: center;

}

.main-content .el-pagination /deep/ .el-pagination__jump {

margin: 0 0 0 24px;

color: #606266;

display: inline-block;

vertical-align: top;

font-size: 13px;

line-height: 28px;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__jump .el-input {

border-radius: 3px;

padding: 0 2px;

margin: 0 2px;

display: inline-block;

width: 50px;

font-size: 14px;

line-height: 18px;

position: relative;

text-align: center;

height: 28px;

}

.main-content .el-pagination /deep/ .el-pagination__jump .el-input .el-input__inner {

border: 1px solid #DCDFE6;

cursor: pointer;

padding: 0 3px;

color: #606266;

display: inline-block;

font-size: 14px;

line-height: 28px;

border-radius: 3px;

outline: 0;

background: #FFF;

width: 100%;

text-align: center;

height: 28px;

}

</style>

第六节 密码修改模块

 用户使用该电影数据分析可视化系统注册完成后,用户对登录密码有修改需求时,系统也可以提供用户修改密码权限。系统中所有的操作者能够变更自己的密码信息,执行该功能首先必须要登入系统,然后选择密码变更选项以后在给定的文本框中填写初始密码和新密码来完成修改密码的操作。在填写的时候,假如两次密码填写存在差异,那么此次密码变更操作失败,下面的图片展示的就是该板块对应的工作面。

密码修改流程图如下所示。

              

图4-18 密码修改流程图

个人信息界面如图所示。

图4-19个人信息界面图

个人信息逻辑代码如下。

<template>

  <div :style='{"minHeight":"100vh","padding":"0px 3%","background":"url(http://codegen.caihongy.cn/20230417/f15cd3c95ab74db6bb97dd6d6b40180e.png) no-repeat center bottom / 100% 100%"}'>

    <el-form

  :style='{"borderRadius":"0px","padding":"20px 0 0","margin":"0px"}'

      class="add-update-preview"

      ref="ruleForm"

      :model="ruleForm"

      label-width="140px"

    >  

     <el-row>

        <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}'   v-if="flag=='yonghu'"  label="用户账号" prop="yonghuzhanghao">

          <el-input v-model="ruleForm.yonghuzhanghao" readonly              placeholder="用户账号" clearable></el-input>

        </el-form-item>

        <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}'   v-if="flag=='yonghu'"  label="用户姓名" prop="yonghuxingming">

          <el-input v-model="ruleForm.yonghuxingming"               placeholder="用户姓名" clearable></el-input>

        </el-form-item>

        <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}' v-if="flag=='yonghu'"  label="性别" prop="xingbie">

          <el-select v-model="ruleForm.xingbie"  placeholder="请选择性别">

            <el-option

                v-for="(item,index) in yonghuxingbieOptions"

                v-bind:key="index"

                :label="item"

                :value="item">

            </el-option>

          </el-select>

        </el-form-item>

        <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}'   v-if="flag=='yonghu'"  label="用户电话" prop="yonghudianhua">

          <el-input v-model="ruleForm.yonghudianhua"               placeholder="用户电话" clearable></el-input>

        </el-form-item>

        <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}' v-if="flag=='yonghu'" label="头像" prop="touxiang">

          <file-upload

          tip="点击上传头像"

          action="file/upload"

          :limit="3"

          :multiple="true"

          :fileUrls="ruleForm.touxiang?ruleForm.touxiang:''"

          @change="yonghutouxiangUploadChange"

          ></file-upload>

        </el-form-item>

<el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}' v-if="flag=='users'" label="用户名" prop="username">

<el-input v-model="ruleForm.username" placeholder="用户名"></el-input>

</el-form-item>

<el-form-item :style='{"padding":"0","margin":"0"}'>

<el-button :style='{"border":"0","cursor":"pointer","padding":"0","margin":"0 20px 0 0","outline":"none","color":"rgba(255, 255, 255, 1)","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"128px","lineHeight":"40px","fontSize":"14px","height":"40px"}' type="primary" @click="onUpdateHandler">修 改</el-button>

</el-form-item>

      </el-row>

    </el-form>

  </div>

</template>

<script>

// 数字,邮件,手机,url,身份证校验

import { isNumber,isIntNumer,isEmail,isMobile,isPhone,isURL,checkIdCard } from "@/utils/validate";

export default {

  data() {

    return {

      ruleForm: {},

      flag: '',

      usersFlag: false,

      yonghuxingbieOptions: [],

    };

  },

  mounted() {

    var table = this.$storage.get("sessionTable");

    this.flag = table;

    this.$http({

      url: `${this.$storage.get("sessionTable")}/session`,

      method: "get"

    }).then(({ data }) => {

      if (data && data.code === 0) {

        this.ruleForm = data.data;

      } else {

        this.$message.error(data.msg);

      }

    });

    this.yonghuxingbieOptions = "男,女".split(',')

  },

  methods: {

    yonghutouxiangUploadChange(fileUrls) {

        this.ruleForm.touxiang = fileUrls;

    },

    onUpdateHandler() {

      if((!this.ruleForm.yonghuzhanghao)&& 'yonghu'==this.flag){

        this.$message.error('用户账号不能为空');

        return

      }

      if((!this.ruleForm.mima)&& 'yonghu'==this.flag){

        this.$message.error('密码不能为空');

        return

      }

      if((!this.ruleForm.yonghuxingming)&& 'yonghu'==this.flag){

        this.$message.error('用户姓名不能为空');

        return

      }

      if( 'yonghu' ==this.flag && this.ruleForm.yonghudianhua&&(!isMobile(this.ruleForm.yonghudianhua))){

        this.$message.error(`用户电话应输入手机格式`);

        return

      }

        if(this.ruleForm.touxiang!=null) {

                this.ruleForm.touxiang = this.ruleForm.touxiang.replace(new RegExp(this.$base.url,"g"),"");

        }

      if('users'==this.flag && this.ruleForm.username.trim().length<1) {

this.$message.error(`用户名不能为空`);

        return

      }

      this.$http({

        url: `${this.$storage.get("sessionTable")}/update`,

        method: "post",

        data: this.ruleForm

      }).then(({ data }) => {

        if (data && data.code === 0) {

          this.$message({

            message: "修改信息成功",

            type: "success",

            duration: 1500,

            onClose: () => {

            }

          });

        } else {

          this.$message.error(data.msg);

        }

      });

    }

  }

};

</script>

<style lang="scss" scoped>

.el-date-editor.el-input {

width: auto;

}

.add-update-preview .el-form-item /deep/ .el-form-item__label {

     padding: 0 10px 0 0;

     color: #666;

     font-weight: 600;

     width: 140px;

     font-size: 14px;

     line-height: 40px;

     text-align: right;

   }

.add-update-preview .el-form-item /deep/ .el-form-item__content {

  margin-left: 140px;

}

.add-update-preview .el-input /deep/ .el-input__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 0 12px;

     outline: none;

     color: #333;

     width: auto;

     font-size: 14px;

     min-width: 400px;

     height: 40px;

   }

.add-update-preview .el-select /deep/ .el-input__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 0 10px;

     outline: none;

     color: #333;

     width: auto;

     font-size: 14px;

     min-width: 300px;

     height: 40px;

   }

.add-update-preview .el-date-editor /deep/ .el-input__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 0 10px 0 30px;

     outline: none;

     color: #333;

     width: auto;

     font-size: 14px;

     min-width: 300px;

     height: 40px;

   }

.add-update-preview /deep/ .el-upload--picture-card {

background: transparent;

border: 0;

border-radius: 0;

width: auto;

height: auto;

line-height: initial;

vertical-align: middle;

}

.add-update-preview /deep/ .el-upload-list .el-upload-list__item {

     border: 2px dashed #797979;

     cursor: pointer;

     border-radius: 6px;

     color: #797979;

     width: 100px;

     font-size: 32px;

     line-height: 100px;

     text-align: center;

     height: 100px;

   }

.add-update-preview /deep/ .el-upload .el-icon-plus {

     border: 2px dashed #797979;

     cursor: pointer;

     border-radius: 6px;

     color: #797979;

     width: 100px;

     font-size: 32px;

     line-height: 100px;

     text-align: center;

     height: 100px;

   }

.add-update-preview .el-textarea /deep/ .el-textarea__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 12px;

     outline: none;

     color: #333;

     width: 90%;

     font-size: 14px;

     min-height: 150px;

     min-width: 90%;

     height: auto;

   }

</style>

密码修改界面如图所示。

图4-20密码修改界面图

密码修改逻辑代码如下。

<template>

  <div :style='{"minHeight":"100vh","padding":"0px 3%","background":"url(http://codegen.caihongy.cn/20230417/f15cd3c95ab74db6bb97dd6d6b40180e.png) no-repeat center bottom / 100% 100%"}'>

    <el-form

  :style='{"borderRadius":"0px","padding":"20px 0 0","margin":"0px"}'

      class="add-update-preview"

      ref="ruleForm"

      :rules="rules"

      :model="ruleForm"

      label-width="140px"

    >

      <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}' label="原密码" prop="password">

        <el-input v-model="ruleForm.password" show-password></el-input>

      </el-form-item>

      <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}' label="新密码" prop="newpassword">

        <el-input v-model="ruleForm.newpassword" show-password></el-input>

      </el-form-item>

      <el-form-item :style='{"width":"100%","margin":"0 0 20px","background":"none","display":"inline-block"}' label="确认密码" prop="repassword">

        <el-input v-model="ruleForm.repassword" show-password></el-input>

      </el-form-item>

      <el-form-item :style='{"padding":"0","margin":"0"}'>

        <el-button :style='{"border":"0","cursor":"pointer","padding":"0","margin":"0 20px 0 0","outline":"none","color":"rgba(255, 255, 255, 1)","borderRadius":"40px","background":"rgba(184, 222, 74, 1)","width":"128px","lineHeight":"40px","fontSize":"14px","height":"40px"}' type="primary" @click="onUpdateHandler">确 定</el-button>

      </el-form-item>

    </el-form>

  </div>

</template>

<script>

export default {

  data() {

    return {

      dialogVisible: false,

      ruleForm: {},

      user: {},

      rules: {

        password: [

          {

            required: true,

            message: "密码不能为空",

            trigger: "blur"

          }

        ],

        newpassword: [

          {

            required: true,

            message: "新密码不能为空",

            trigger: "blur"

          }

        ],

        repassword: [

          {

            required: true,

            message: "确认密码不能为空",

            trigger: "blur"

          }

        ]

      }

    };

  },

  mounted() {

    this.$http({

      url: `${this.$storage.get("sessionTable")}/session`,

      method: "get"

    }).then(({ data }) => {

      if (data && data.code === 0) {

        this.user = data.data;

      } else {

        this.$message.error(data.msg);

      }

    });

  },

  methods: {

    onLogout() {

      this.$storage.remove("Token");

      this.$router.replace({ name: "login" });

    },

    // 修改密码

    onUpdateHandler() {

      this.$refs["ruleForm"].validate(valid => {

        if (valid) {

          var password = "";

          if (this.user.mima) {

            password = this.user.mima;

          } else if (this.user.password) {

            password = this.user.password;

          }

          if (this.user.password) {

            password = this.user.password;

          } else if (this.user.password) {

            password = this.user.password;

          }

          if (this.ruleForm.password != password) {

            this.$message.error("原密码错误");

            return;

          }

          if (this.ruleForm.newpassword != this.ruleForm.repassword) {

            this.$message.error("两次密码输入不一致");

            return;

          }

          this.user.password = this.ruleForm.newpassword;

          this.user.mima = this.ruleForm.newpassword;

          this.$http({

            url: `${this.$storage.get("sessionTable")}/update`,

            method: "post",

            data: this.user

          }).then(({ data }) => {

            if (data && data.code === 0) {

              this.$message({

                message: "修改密码成功,下次登录系统生效",

                type: "success",

                duration: 1500,

                onClose: () => {

                }

              });

            } else {

              this.$message.error(data.msg);

            }

          });

        }

      });

    }

  }

};

</script>

<style lang="scss" scoped>

.el-date-editor.el-input {

width: auto;

}

.add-update-preview .el-form-item /deep/ .el-form-item__label {

     padding: 0 10px 0 0;

     color: #666;

     font-weight: 600;

     width: 140px;

     font-size: 14px;

     line-height: 40px;

     text-align: right;

   }

.add-update-preview .el-form-item /deep/ .el-form-item__content {

  margin-left: 140px;

}

.add-update-preview .el-input /deep/ .el-input__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 0 12px;

     outline: none;

     color: #333;

     width: auto;

     font-size: 14px;

     min-width: 400px;

     height: 40px;

   }

.add-update-preview .el-select /deep/ .el-input__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 0 10px;

     outline: none;

     color: #333;

     width: auto;

     font-size: 14px;

     min-width: 300px;

     height: 40px;

   }

.add-update-preview .el-date-editor /deep/ .el-input__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 0 10px 0 30px;

     outline: none;

     color: #333;

     width: auto;

     font-size: 14px;

     min-width: 300px;

     height: 40px;

   }

.add-update-preview /deep/ .el-upload--picture-card {

background: transparent;

border: 0;

border-radius: 0;

width: auto;

height: auto;

line-height: initial;

vertical-align: middle;

}

.add-update-preview /deep/ .el-upload-list .el-upload-list__item {

     border: 2px dashed #797979;

     cursor: pointer;

     border-radius: 6px;

     color: #797979;

     width: 100px;

     font-size: 32px;

     line-height: 100px;

     text-align: center;

     height: 100px;

   }

.add-update-preview /deep/ .el-upload .el-icon-plus {

     border: 2px dashed #797979;

     cursor: pointer;

     border-radius: 6px;

     color: #797979;

     width: 100px;

     font-size: 32px;

     line-height: 100px;

     text-align: center;

     height: 100px;

   }

.add-update-preview .el-textarea /deep/ .el-textarea__inner {

     border: 2px solid #797979;

     border-radius: 4px;

     padding: 12px;

     outline: none;

     color: #333;

     width: 90%;

     font-size: 14px;

     min-height: 150px;

     min-width: 90%;

     height: auto;

   }

</style>

  

第五章 系统测试

第一节 系统测试的目的

在系统开发的最后阶段,系统测试显得尤为重要,它不仅可以帮助我们更好地理解软件的设计,还能提高开发效率。由于系统开发过程中可能存在诸多缺陷,即使是最优秀的系统开发工程师也无法避免这些缺陷。因此,通过进行系统测试,我们可以有效地纠正这些bug,从而为后续的系统维护和升级提供有力的支持。经过严格的系统测试,开发者们能够更加坚定地认识到系统的性能,从而更有动力去推动后续的系统更新。

第二节 系统测试用例

系统测试包括:用户登录功能测试、电影信息展示功能测试、电影信息添加、电影信息搜索、密码修改功能测试,如表5-1、5-2、5-3、5-4、5-5所示:

用户登录功能测试:

表5-1 用户登录功能测试表

用例名称

用户登录系统

目的

测试用户通过正确的用户名和密码可否登录功能

前提

未登录的情况下

测试流程

1) 进入登录页面

2) 输入正确的用户名和密码

预期结果

用户名和密码正确的时候,跳转到登录成功界面,反之则显示错误信息,提示重新输入

实际结果

实际结果与预期结果一致

电影信息查看功能测试:

表5-2 电影信息查看功能测试表

用例名称

电影信息查看

目的

测试电影信息查看功能

前提

用户登录

测试流程

点击电影信息列表

预期结果

可以查看到所有电影信息

实际结果

实际结果与预期结果一致

管理员添加电影信息界面测试:

表5-3 管理员添加电影信息界面测试表

用例名称

电影信息发布测试用例

目的

测试电影信息发布功能

前提

用户正常登录情况下

测试流程

1)点击电影信息管理就,然后点击添加后并填写信息。

2)点击进行提交。

预期结果

提交以后,页面首页会显示新的电影信息 

实际结果

实际结果与预期结果一致

电影信息搜索功能测试:

表5-4电影信息搜索功能测试表

用例名称

电影信息搜索测试

目的

测试电影信息搜索功能

前提

测试流程

1)在搜索框填入搜索关键字。

2)点击搜索按钮。

预期结果

页面显示包含有搜索关键字的电影信息

实际结果

实际结果与预期结果一致

密码修改功能测试:

表5-5 密码修改功能测试表

用例名称

密码修改测试用例

目的

测试管理员密码修改功能

前提

管理员用户正常登录情况下

测试流程

1)管理员密码修改并完成填写。

2)点击进行提交。

预期结果

使用新的密码可以登录

实际结果

实际结果与预期结果一致

第三节 系统测试结果

经过对豆瓣电影数据分析可视化系统的测试,我们已经完成了5大模块的检测,包括用户登录、电影信息查看、电影信息添加、电影信息搜索以及密码修改功能,这些功能为后续的推广运营提供了强有力的技术支持。

第六章 结论

在开发本豆瓣电影数据分析可视化系统之前我胸有成竹,觉得很简单,但在实际的开发中我发现了自身的很多问题,许多编程思想和方法都还没有掌握牢靠,比如python、pycharm、HbuildX等许多python Web开发技术,通过开发这个豆瓣电影数据分析可视化系统我成长了很多,懂得了做什么事情都要脚踏实地,不能眼高手低,在本次豆瓣电影数据分析可视化系统的开发中我逐渐掌握逐渐熟悉的技术。

本次豆瓣电影数据分析可视化系统的开发中我还学会了很多,例如良好的编程思想和完善的规划思想。在着手编程之前需要罗列出程序框架的大概,脑海中构建出程序的主题框架。只有这一步做好了,才能让经行发展的项目胸有成竹。当设计框架了熟于心之后,需要思考本次编程所需的主要知识点和技术点,并充分学习。如此一来项目的开发才能循序渐进、如丝般顺滑,长久以往就能养成良好的开发习惯。一个程序好不好还要看出的bug多不多,如果在项目完成前做好bug的查验与预防可能发生的事故才能保证程序的稳定长久性运行。如果项目在完工后出现各种问题自己,那么在进入社会后,不仅会给公司团队带来麻烦和增加不必要的工作,还会导致客户流失,公司对自己的评价下降。

在本次项目中我也暴露了诸多问题。缺乏一些Python的编程知识,并且在环境配置和算法上的问题也有很多,经常造成项目操作失误,或者没法完成想要实现的功能目标等问题。或者实现想法时算法未优化,使得代码冗长,程序运行不顺畅。

参考文献

  1.  温佐承,贾雪.基于Python的网络爬取 [J].电脑编程技巧与维护,2020(12):23-24+32.
  2.  赵文杰,古荣龙.基于Python的网络爬虫技术 [J].河北农机,2020(8):65-66.
  3.  刘石磊.对反爬虫网站的应对策略 [J].電脑知识与技术,2017,13(15):19-21+23.
  4.  伏康,杜振鹏.网站反爬虫策略的分析与研究 [J].电脑知识与技术,2019,15(28):28-30.
  5.  陈利婷.大数据时代的反爬虫技术 [J].电脑与信息技术,2016,24(6):60-61.
  6.  张岩.大数据反爬虫技术分析 [J].信息系统工程,2018(8):130.
  7.  朱寅非.数据可视化应用领域及作用 [J].电子技术与软件工程,2020(16):149-150.
  8.  Tufte, E. R. (2001). The Visual Display of Quantitative Information. Cheshire, CT:Graphics Press.
  9.  Few, S. (2009). Now You See It: Simple Visuliazation Techniques for Quantitative Analysis. Berkeley, CA:Analytics Press.
  10. High-Confidence Computing,27 July 2021,Volume 2,lssue 1(Coverdate:March2022),Article 100034. Rohit Ranjan,Shashi Shekhar Kumar.
  11. 杨健,陈伟.基于Python的三种网络爬虫技术研究[J].软件工程,2023,26(02):24-27+19.DOI:10.19644/j.cnki.issn2096-1472.2023.002.005.
  12. 沈杰.基于Python的数据分析可视化研究与实现[J].科技资讯,2023,21(02):14-17+54.DOI:10.16661/j.cnki.1672-3791.2206-5042-9371.
  13. 魏炎,孙畅.利用Python技术批量提取文档数据[J].审计月刊,2023(01):27-28.DOI:10.15882/j.cnki.sjyk.2023.01.022.

[14]Information Technology - Data Management; Data on Data Management Reported by Researchers at Port Said University (Performance Evaluation of Iot Data Management Using Mongodb Versus Mysql Databases In Different Cloud Environments)[J]. Computer Technology Journal,2020.

[15]杨一帆.服务于MySQL数据库的在线监测系统设计[J].自动化技术与应用,2022,41(10):179-182.DOI:10.20033/j.1003-7241.(2022)10-0179-04.

[16]Witsarut Sriratana,Vittaya Khagwian,Sutham Satthamsakul. Analysis of Electric Current by Using MySQL Database on Web Server for Machine Performance Evaluation: A Case Study of Air Conditioning System[J]. 제어로봇시스템학회 국제학술대회 논문집,2020.

[17]张海悦,王萃,刘达.中国电影产业基础数据库创建与可视化系统设计实现[J].现代电影技术,2020(09):8-12.

[18]汤颖,徐珊.MDVis:多模态电影数据可视分析系统[J].计算机辅助设计与图形学学报,2020,32(11):1707-1720.

[19]黄剑波,何绍荣.电影大数据的多角度构建与可视化分析[J].现代电影技术,2020(06):31-35.

[20]陈华,王荻.三维可视化系统在港口石化库区中的应用[J].港工技术,2020,57(S1):128-131.DOI:10.16403/j.cnki.ggjs2020S133.

[21]Margaretha Ohyver,Jurike V. Moniaga,Iwa Sungkawa,Bonifasius Edwin Subagyo,Ian Argus Chandra. The Comparison Firebase Realtime Database and MySQL Database Performance using Wilcoxon Signed-Rank Test[J]. Procedia Computer Science,2019,157(C).

[22]Prince Asabere,Francois Sekyere,Willie K Ofosu. Wireless Biometric Fingerprint Attendance System using Arduino and Mysql Database[J]. International Journal of Computer Science, Engineering and Applications,2019,10(5).

致谢

到此,整个豆瓣电影数据分析可视化系统就算完成了,虽然过程十分艰难,但是等到都完成的时候,我感觉无比的自豪,虽然设计的系统还存在许多的纰漏,但是我已经拼劲全力,给自己的大学四年画上了一个圆满的句号。写到这里有许多思绪想要表达,但是回首大学四年的学习生涯,才发现留在记忆里的东西就像无穷无尽的代码一样多,用言语很难表达出所念所想,但是有一些最重要的感谢话还是要表达出来。

在这里我首先要感谢的就是大学四年来所有教过我的老师,是他们教会了我很多的专业知识和做人的道理,从一进校门对开发系统的一窍不通,对于老师所留的结课作业总是抱怨累心难做,到现在能自主开发一个管理系统,里面包含了前台框架、后台框架、业务流程、我非常感激我的指导老师们,在大学期间你们帮助我掌握了数据挖掘,数据结构、操作系统等各种知识,并且让我能够将它们统一运用,最终完成了整个系统。在开发这个系统的过程中,我遇到了无数的问题,但是无论是线上还是线下,我都会向导师寻求帮助,而导师也总是耐心地指导我如何实现这个功能,如何让系统变得更加完善,最终,我也通过自己查阅相关资料,解决了许多问题。通过“老师,谢谢您,您辛苦了”的指导,我大大提升了自身的解决问题的能力,比起传授知识,更重要的是,它让我受益匪浅,我将继续努力,向老师学习,让自己的智慧得到更大的发挥!最后我还要感谢我的室友、同学,在一起学习这四年,他们不但学习上给了我很多建议,在生活上更加给了我帮助,正是有他们的帮助,我的大学生涯才如此完美。

最后,希望自己在未来的道路上能够越走越远,不辜负在大学的学习以及老师们的细致的教导,追风赶月莫停留,平荒尽处是春山。

点赞+收藏+关注  →私信领取本源代码、数据库

关注博主下篇更精彩
一键三连!!!
一键三连!!!
一键三连!!!
感谢一键三连!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值