电影院购票管理系统

news2024/11/16 21:45:30

文章目录

  • 电影院购票管理系统
    • 一、项目演示
    • 二、项目介绍
    • 三、部分功能截图
    • 四、部分代码展示
    • 五、底部获取项目源码(9.9¥带走)

电影院购票管理系统

一、项目演示

电影院售票管理系统

二、项目介绍

基于springboot+vue的前后端分离电影院购票管理系统
(1)用户功能

登录、退出、注册、修改个人信息、上映|即将上映|热播影片浏览、搜索、上映|即将上映|热播榜单浏览、选座购票、订单查看

(2)管理员功能

影院信息管理、影片管理:电影信息、电影类型、影厅管理:影厅信息、场次信息管理、订单管理、用户管理

2、项目技术
语言:java
前端技术:Vue、Element-Plus
后端技术:SpringBoot、Mybatis-Plus
数据库:MySQL

三、部分功能截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、部分代码展示

package com.movie.web.controller.system;

import com.movie.common.exception.DataNotFoundException;
import com.movie.common.response.ResponseResult;
import com.movie.common.utils.ApplicationContextUtils;
import com.movie.system.domin.SysBill;
import com.movie.system.domin.SysMovie;
import com.movie.system.domin.SysSession;
import com.movie.system.domin.vo.SysBillVo;
import com.movie.system.service.impl.SysBillServiceImpl;
import com.movie.system.service.impl.SysMovieServiceImpl;
import com.movie.system.service.impl.SysSessionServiceImpl;
import com.movie.web.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Random;


@RestController
public class SysBillController extends BaseController {

    @Autowired
    private SysBillServiceImpl sysBillService;

    @Autowired
    private SysSessionServiceImpl sysSessionService;

    @Autowired
    private SysMovieServiceImpl sysMovieService;

    @GetMapping("/sysBill")
    public ResponseResult findAllBills(SysBill sysBill) {
        startPage();
        // 取消所有超时订单并释放占座资源
        ApplicationContextUtils.getBean("cancelTimeoutBill");
        List<SysBill> data = sysBillService.findAllBills(sysBill);
        return getResult(data);
    }

    @GetMapping("/sysBill/{id}")
    public ResponseResult findBillById(@PathVariable Long id) {
        return getResult(sysBillService.findBillById(id));
    }

    @PostMapping("/sysBill")
    public ResponseResult addBill(@Validated @RequestBody SysBillVo sysBillVo) {
        // 获取当前场次信息
        SysSession curSession = sysSessionService.findOneSession(sysBillVo.getSysBill().getSessionId());
        if (curSession == null) {
            throw new DataNotFoundException("添加订单的场次没找到");
        }
        System.out.println(curSession.getSessionSeats());
        curSession.setSessionSeats(sysBillVo.getSessionSeats());

        int addSallNums = sysBillVo.getSysBill().getSeats().split(",").length;
        curSession.setSallNums(curSession.getSallNums() + addSallNums);
        // 更新场次座位信息
        sysSessionService.updateSession(curSession);
        Random random = new Random();
        int temp = random.nextInt(6);
        Object obj = sysBillService.addBill(sysBillVo.getSysBill());
        if (obj instanceof Integer) {
            return getResult((Integer) obj);
        }
        return getResult(obj);
    }

    @PutMapping("/sysBill")
    public ResponseResult pay(@RequestBody SysBill sysBill) {
        int rows = sysBillService.updateBill(sysBill);
        if (rows > 0 && sysBill.getPayState()) {
            //更新场次的座位状态
            SysSession curSession = sysSessionService.findOneSession(sysBill.getSessionId());
            if (curSession == null) {
                throw new DataNotFoundException("支付订单的场次没找到");
            }
            //更新电影票房
            SysMovie curMovie = sysMovieService.findOneMovie(curSession.getMovieId());
            if (curMovie == null) {
                throw new DataNotFoundException("支付订单的电影没找到");
            }
            //订单的座位数
            int seatNum = sysBill.getSeats().split(",").length;
            double price = curSession.getSessionPrice();
            curMovie.setMovieBoxOffice(curMovie.getMovieBoxOffice() + seatNum * price);
            sysMovieService.updateMovie(curMovie);
        }
        return getResult(rows);
    }

    @PutMapping("/sysBill/cancel")
    public ResponseResult cancel(@RequestBody SysBillVo sysBillVo) {
        // 订单取消,更新订单状态
        int rows = sysBillService.updateBill(sysBillVo.getSysBill());
        if (rows > 0 && sysBillVo.getSysBill().getCancelState()) {
            // 订单取消座位不再占用,更新场次的座位状态
            SysSession curSession = sysSessionService.findOneSession(sysBillVo.getSysBill().getSessionId());
            // 取消的订单座位数
            int cancelSallNums = sysBillVo.getSysBill().getSeats().split(",").length;
            curSession.setSallNums(curSession.getSallNums() - cancelSallNums);
            if (curSession == null) {
                throw new DataNotFoundException("添加订单的场次没找到");
            }
            curSession.setSessionSeats(sysBillVo.getSessionSeats());
            sysSessionService.updateSession(curSession);
        }
        return getResult(rows);
    }

    @DeleteMapping("/sysBill/{ids}")
    public ResponseResult deleteBill(@PathVariable Long[] ids) {
        return getResult(sysBillService.deleteBill(ids));
    }

}

package com.movie.web.controller.system;

import com.movie.common.response.ResponseResult;
import com.movie.system.domin.SysCinema;
import com.movie.system.domin.SysSession;
import com.movie.system.service.impl.SysCinemaServiceImpl;
import com.movie.system.service.impl.SysSessionServiceImpl;
import com.movie.web.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;


@RestController
public class SysCinemaController extends BaseController {

    @Autowired
    private SysCinemaServiceImpl sysCinemaService;

    @Autowired
    private SysSessionServiceImpl sysSessionService;

    @GetMapping("/sysCinema")
    public ResponseResult findCinema() {
        return getResult(sysCinemaService.findCinema());
    }

    @PutMapping("/sysCinema/update")
    public ResponseResult updateCinema(@Validated @RequestBody SysCinema sysCinema) {
        return getResult(sysCinemaService.updateCinema(sysCinema));
    }

    @GetMapping(value = {"/sysCinema/find/{cinemaId}/{movieId}", "/sysCinema/find/{cinemaId}"})
    public ResponseResult findCinemaById(@PathVariable Long cinemaId, @PathVariable(required = false) Long movieId) {
        SysCinema cinema = sysCinemaService.findCinemaById(cinemaId);
        if (movieId == null || movieId == 0) {
            movieId = cinema.getSysMovieList().size() > 0 ? cinema.getSysMovieList().get(0).getMovieId() : 0;
        }
        List<SysSession> sessions = null;
        if (movieId != null && movieId != 0) {
            sessions = sysSessionService.findSessionByMovieId(movieId);
        }

        HashMap<String, Object> response = new HashMap<>();
        response.put("cinema", cinema);
        response.put("sessions", sessions);
        return getResult(response);
    }

}

package com.movie.common.controller;

import com.movie.common.file.FileUploadUtils;
import com.movie.common.response.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 封装图片上传请求
 */
@Slf4j
@RestController
@RequestMapping("/upload")
public class FileUploadController {

    @PostMapping("/user")
    public ResponseResult uploadUser(@RequestParam("file") MultipartFile file) throws IOException {
        FileUploadUtils.setDefaultBaseDir(FileUploadUtils.userPath);
        String filename = FileUploadUtils.upload(file);
        log.debug("上传文件名 : " + filename);
        return ResponseResult.success((Object) filename);
    }

    @PostMapping("/movie")
    public ResponseResult uploadMovie(@RequestParam("file") MultipartFile file) throws IOException {
        FileUploadUtils.setDefaultBaseDir(FileUploadUtils.moviePath);
        String filename = FileUploadUtils.upload(file);
        log.debug("上传文件名 : " + filename);
        return ResponseResult.success((Object) filename);
    }

    @PostMapping("/cinema")
    public ResponseResult uploadCinema(@RequestParam("file") MultipartFile file) throws IOException {
        FileUploadUtils.setDefaultBaseDir(FileUploadUtils.cinemaPath);
        String filename = FileUploadUtils.upload(file);
        log.debug("上传文件名 : " + filename);
        return ResponseResult.success((Object) filename);
    }

    @PostMapping("/actor")
    public ResponseResult uploadActor(@RequestParam("file") MultipartFile file) throws IOException {
        FileUploadUtils.setDefaultBaseDir(FileUploadUtils.actorPath);
        String filename = FileUploadUtils.upload(file);
        log.debug("上传文件名 : " + filename);
        return ResponseResult.success((Object) filename);
    }

    @RequestMapping("/delete")
    public ResponseResult deletePicture(String filePath) {
        try {
            String path = ResourceUtils.getURL("classpath:").getPath().substring(1) + "static" + filePath;
            log.debug("删除文件路径为:" + path);
            boolean flag = FileUploadUtils.deleteFile(path);
            log.debug(flag ? "删除成功" : "删除失败");
        } catch (FileNotFoundException e) {
            System.out.println("删除文件不存在");
        } finally {
            return ResponseResult.success();
        }
    }

}

package com.movie.common.file;

import com.movie.common.exception.FileNameLengthLimitExceededException;
import com.movie.common.exception.FileSizeLimitExceededException;
import com.movie.common.exception.InvalidExtensionException;
import com.movie.common.utils.StringUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.util.ClassUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;

/**
 * 文件上传工具类
 */
public class FileUploadUtils {
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 默认存储图片目录
     */
    private static final String parentPath = ClassUtils.getDefaultClassLoader().getResource("static/images").getPath();

    public static final String actorPath = "/actor";
    public static final String cinemaPath = "/cinema";
    public static final String moviePath = "/movie";
    public static final String userPath = "/user";


    /**
     * 默认上传的地址
     */
    private static String defaultBaseDir = userPath;

    public static void setDefaultBaseDir(String defaultBaseDir) {
        FileUploadUtils.defaultBaseDir = defaultBaseDir;
    }

    public static String getDefaultBaseDir() {
        return defaultBaseDir;
    }

    public static String getParentPath() {
        return parentPath;
    }

    /**
     * 以默认配置进行文件上传
     *
     * @param file 上传的文件
     * @return 文件名称
     * @throws Exception
     */
    public static final String upload(MultipartFile file) throws IOException {
        try {
            return upload(getParentPath() + getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 文件上传
     *
     * @param baseDir          相对应用的基目录
     * @param file             上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws FileSizeLimitExceededException       如果超出最大大小
     * @throws FileNameLengthLimitExceededException 文件名太长
     * @throws IOException                          比如读写文件出错时
     * @throws InvalidExtensionException            文件校验异常
     */
    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException {
        int fileNamelength = file.getOriginalFilename().length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException("文件名称长度不能超过" + FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);

        String fileName = extractFilename(file);

        File desc = getAbsoluteFile(baseDir, fileName);
        System.err.println("baseDir"+": "+baseDir);
        file.transferTo(desc);
        String pathFileName = getPathFileName(baseDir, fileName);
        System.err.println("pathFileName"+": "+baseDir);
        return pathFileName;
    }

    /**
     * 编码文件名 如 : images/user/2021/3/4/***.png
     */
    public static final String extractFilename(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        fileName = DateFormatUtils.format(new Date(), "yyyy/MM/dd") + "/" + UUID.randomUUID().toString().replaceAll("-", "") + "." + extension;
        System.err.println("fileName"+": "+fileName);
        return fileName;
    }

    /**
     * 判断文件名是否存在 不存在创建一个
     * @param uploadDir
     * @param fileName
     * @return
     * @throws IOException
     */
    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
        File desc = new File(uploadDir + File.separator + fileName);
        if (!desc.getParentFile().exists()) {
            desc.getParentFile().mkdirs();
        }
        if (!desc.exists()) {
            desc.createNewFile();
        }
        return desc;
    }

    private static final String getPathFileName(String uploadDir, String fileName) throws IOException {
        int dirLastIndex = parentPath.length() + 1;
        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
        String pathFileName = "/images/" + currentDir + "/" + fileName;
        return pathFileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException {
        long size = file.getSize();
        if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) {
            throw new FileSizeLimitExceededException("文件大小不能超过" + DEFAULT_MAX_SIZE / 1024 / 1024 + "MB");
        }

        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
                throw new InvalidExtensionException("图片格式不支持" + extension + "格式");
            }
        }

    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension
     * @param allowedExtension
     * @return
     */
    public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
        for (String str : allowedExtension) {
            if (str.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static final String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (!StringUtil.isNotEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }

    /**
     * 删除文件
     *
     * @param filePath 文件
     * @return
     */
    public static boolean deleteFile(String filePath) {
        boolean flag = false;
        File file = new File(filePath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

}

五、底部获取项目源码(9.9¥带走)

有问题,或者需要协助调试运行项目的也可以

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1665473.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.分布式-理论

目录 一、什么是分布式系统 二、CAP理论 1.一致性Consisency 2.可用性(Availability) 3.分区容错性(Partition tolrance) 三、BASE理论 1.Basically Available(基本可用) 2.Soft state&#xff08;软状态&#xff09; 3.Eventually consistent&#xff08;最终一致性&a…

天机学堂—学习辅助功能(含场景问答和作业)

我的课表 需求分析 原型图 管理后台 用户端 流程图 数据设计 接口设计 支付成功报名课程后, 加入到我的课表(MQ)分页查询我的课表查询我正在学习的课程根据id查询指定课程的学习状态删除课表中的某课程 代码实现 数据表设计 添加课程到课表&#xff08;非标准接口&#x…

ApiHug Official Website

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | MarketplaceApiHug-H…

OpenHarmony 实战开发——分布式硬件管理详解

前言 分布式硬件是 OpenHarmony 提供的一个分布式能力&#xff0c;能将多种设备组成一个“超级终端”&#xff0c;使用户根据现实需要和硬件能力&#xff0c;选择合适的硬件提供服务&#xff0c;灵活运用硬件进行资源分配和按需组合&#xff0c;充分发挥各类硬件设备的能力&am…

Jenkins android 自动打包安卓 centos8.5 运维系列五

1 新建项目android #cat android.sh #!/bin/bash rm -rf /data/.jenkins/workspace/android/app/build/outputs/apk/debug/* rm -rf /data/.jenkins/workspace/android/app/build/outputs/apk/release/* cd /data/.jenkins/workspace/android/app source /etc/profile g…

WEB前端复习——CSS

CSS:层叠样式表 将显示样式与内容分开 基本语法&#xff1a; 选择器{ 规则; } ①标签选择器&#xff1a;以HTML标签名为选择 <style>p{color: red;} </style> <body><p>你好</p> </body> ②id选择器&#xff1a;一次性的 以#号定义 &l…

在做题中学习(57):寻找数组的中心下标

724. 寻找数组的中心下标 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;前缀和后缀和 思路&#xff1a;要看一个数是不是中心下标&#xff0c;就看他前面数的和 与 后面数的和 相不相等。 1.i前面数的和&#xff0c;是[0,i-1] 的前缀和&#xff0c;i后面数的和&am…

音视频入门基础:像素格式专题(2)——不通过第三方库将RGB24格式视频转换为BMP格式图片

音视频入门基础&#xff1a;像素格式专题系列文章&#xff1a; 音视频入门基础&#xff1a;像素格式专题&#xff08;1&#xff09;——RGB简介 音视频入门基础&#xff1a;像素格式专题&#xff08;2&#xff09;——不通过第三方库将RGB24格式视频转换为BMP格式图片 一、引…

STM32-07-STM32_外部中断

文章目录 STM32 中断系统1. 中断2. NVIC3. EXTI4. AFIO5. 中断配置步骤6. 外部中断代码 STM32 中断系统 1. 中断 目的&#xff1a;中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。中断过程&#xff1a;当CPU正在处理某事件的时候外界发生了紧急事件请求 &#…

ESP-01S刷固件ESP8266_NonOS_AT_Bin_V1.7.5_1 笔记240510

ESP-01S刷固件ESP8266_NonOS_AT_Bin_V1.7.5_1 笔记240510 固件下载地址 ESP-AT固件页面: https://www.espressif.com.cn/zh-hans/products/sdks/esp-at/resource 直接下载ESP8266 NonOS AT Bin V1.7.5.zip: https://www.espressif.com.cn/sites/default/files/ap/ESP8266_No…

32.768kHz晶振的时间精度问题及其解决方法

32.768kHz晶振因其稳定性高、功耗低&#xff0c;被广泛应用于实时时钟(RTC)、计时电路及低功耗电子产品中。然而&#xff0c;在某些情况下&#xff0c;这些晶振可能出现时间偏差&#xff0c;影响设备正常工作。以下是可能导致32.768kHz晶振时间误差的原因及相应的解决策略。 温…

Snort规则编写

1&#xff09;TCP NULL端口扫描的特征&#xff1a; 扫描者发送一个TCP SYN包到目标主机的某个端口&#xff0c;但不设置任何TCP标志位&#xff08;即flag为NULL&#xff09;。 如果端口关闭&#xff0c;目标主机会回应一个RST&#xff08;复位&#xff09;和ACK&#xff08;确认…

数据结构之图——探索图论的奥秘

前言 在这篇文章中&#xff0c;我们一起来看看我们生活中都会用到&#xff0c;但却不那么熟悉的数据结构——图&#xff08;英语&#xff1a;graph&#xff09;。我们看下百科定义&#xff1a; 在计算机科学中&#xff0c;图&#xff08;英语&#xff1a;graph&#xff09;是一…

py黑帽子学习笔记_网络编程工具

tcp客户端 socket.AF_INET表示使用标准IPV4地址和主机名 SOCK_STREAM表示这是一个TCP客户端 udp客户端 udp无需连接&#xff0c;因此不需要client.connect这种代码 socket.SOCK_DGRAM是udp的 tcp服务端 server.listen(5)表示设置最大连接数为5 发现kill server后端口仍占用…

大模型微调之 在亚马逊AWS上实战LlaMA案例(九)

大模型微调之 在亚马逊AWS上实战LlaMA案例&#xff08;九&#xff09; 代码阅读 src/llama_recipes/inference/prompt_format_utils.py 这段代码是一个Python模块&#xff0c;它定义了几个类和模板&#xff0c;用于生成安全评估的提示文本。以下是对每一行代码的注释和提示词…

Datax数据采集

一、Datax介绍 官网&#xff1a; DataX/introduction.md at master alibaba/DataX GitHub DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。 DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、…

MySQL innodb_buffer_pool_size 相关常用语句

对于MySQL速度慢的问题&#xff0c;除了优化 SQL 以外&#xff0c;应该必须优先想到的即使 MySQL 数据库的 innodb_buffer_pool_size 配置问题。 一般来说&#xff0c;innodb_buffer_pool_size 的默认大小都是很小的&#xff0c;尤其是 win 下其默认大小更是只有离谱的 8M。Li…

2024 年最新本地、云服务器安装部署 miniconda 环境详细教程(更新中)

Anaconda 概述 Anaconda 是专门为了方便使用 Python 进行数据科学研究而建立的一组软件包&#xff0c;涵盖了数据科学领域常见的 Python 库&#xff0c;并且自带了专门用来解决软件环境依赖问题的 conda 包管理系统。主要是提供了包管理与环境管理的功能&#xff0c;可以很方便…

土壤墒情自动监测站—墒情异常数据报警提示

TH-TS600土壤墒情自动监测站通常配备有预警提示功能&#xff0c;用于在墒情出现异常情况时及时向用户发出警告。这一功能对于农业生产至关重要&#xff0c;因为它可以帮助农民或农田管理者及时发现土壤墒情的变化&#xff0c;并采取相应的措施来确保作物健康生长。 土壤墒情自动…

Excel实用技巧持续学习

1、Excel高效设置图标格式&#xff1a; 2、饼图可以统一设置数据标签在图外面&#xff01;&#xff01; 环形图不可以&#xff0c;但是可以中间手动加上白色圆形&#xff0c;将饼图变为圆环。 可以设置标签的文本显示&#xff1a; 3、饼图和环形图最好进行排序&#xff01;显得…