vue+exceljs前端下载、导出xlsx文件
首先安装插件
npm install exceljs file-saver
第一种 简单导出

//页面引入
import ExcelJS from 'exceljs';
import {saveAs} from 'file-saver';
export default {methods: {
/** 导出操作 */async handleExportFun() {let that = this// 获取当前年月日 用户下载xlsx的文件名称设置const now = new Date();const year = now.getFullYear();const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1,并确保两位数const day = String(now.getDate()).padStart(2, '0'); // 确保两位数const hours = String(now.getHours()).padStart(2, '0'); // 确保两位数const minutes = String(now.getMinutes()).padStart(2, '0'); // 确保两位数var currentTime = `${year}${month}${day}${hours}${minutes}`;//创建const workbook = new ExcelJS.Workbook();const worksheet = workbook.addWorksheet('Sheet1');// 假设 exportData 的第一行是列头const headers = this.exportData[0]; // 确保这里是获取的第一行数据作为列头// 填充表头数据 因为我的数据是不固定的二维数组worksheet.columns = headers.map((headerText, index) => ({header: headerText,key: index.toString(),width: 22,}));// 设置表头行高const headerRow = worksheet.getRow(1);headerRow.height = 35; // 设置行高为35(可以根据需要调整)//申明样式let style = {alignment: {vertical: "middle",horizontal: "center",wrapText: true,},fill: {type: "pattern",pattern: "solid",fgColor: {argb: "EEEEEE"},},border: {top: {style: "thin",color: { rgb: 'E3F2D9' } // 设置左边框样式和颜色}, // 设置上边框样式为细线bottom: {style: "thin",color: { rgb: 'E3F2D9' } // 设置左边框样式和颜色}, // 设置下边框样式为细线left: {style: "thin",color: { rgb: 'E3F2D9' } // 设置左边框样式和颜色}, // 设置左边框样式为细线right: {style: "thin",color: { rgb: 'E3F2D9' } // 设置左边框样式和颜色}, // 设置右边框样式为细线},font: {bold: true, // 设置字体加粗name: 'Arial', // 设置字体名称(可选)size: 12 // 设置字体大小(可选)}};// 填充工作表的其他数据,并设置行高for (let rowIndex = 1; rowIndex < this.exportData.length; rowIndex++) {const row = this.exportData[rowIndex];const excelRow = worksheet.getRow(rowIndex + 1);excelRow.height = 30; // 设置其他行的行高为25(可以根据需要调整)row.forEach((cellValue, cellIndex) => {const cell = excelRow.getCell(cellIndex + 1);cell.value = cellValue;});}//给每行设置样式worksheet.eachRow((row, rowNumber) => {if (rowNumber > 0) {row.height = 35;row.alignment = style.alignment;// 你还可以根据单元格的内容或列号执行不同的操作row.eachCell((cell, colNumber) => {if (rowNumber === 1&&colNumber<=that.exportData[0].length) {//对第一列的单元格执行特殊操作cell.font=style.fontcell.fill=style.fill}cell.border = style.border;});}});try {const buffer = await workbook.xlsx.writeBuffer();const blob = new Blob([buffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});saveAs(blob, currentTime + '_设备数据.xlsx'); // 导出的文件名可以根据需要动态设置} catch (err) {console.error('导出Excel时出错:', err);}}}}
第二种复杂的表单导出
如图
数据格式
this.summaryStatistics={"type": null,"xuhao": null,"user": "汇总","timeJson": [{\"bxPrice\":0.00,\"fyPrice\":0.00,\"fyzb\":0.00,\"htPrice\":0.00,\"swPrice\":0.00,\"time\":\"2023年\"},{\"bxPrice\":129584000.80,\"fyPrice\":129592366.80,\"fyzb\":738.96,\"htPrice\":17537026.00,\"swPrice\":8366.00,\"time\":\"2024年\"}],"htXj": 17537026,"htZb": null,"fyXj": 129592366.8,"fyZbXj": 738.96}this.times = this.summaryStatistics.timeJsonthis.userStatistics = [{"type": null,"xuhao": 1,"user": "admin","timeJson": "[{\"bxPrice\":0.00,\"fyPrice\":0.00,\"fyzb\":0.00,\"htPrice\":0.00,\"swPrice\":0.00,\"time\":\"2023年\"},{\"bxPrice\":0.00,\"fyPrice\":0.00,\"fyzb\":0.00,\"htPrice\":274000.00,\"swPrice\":0.00,\"time\":\"2024年\"}]","htXj": 274000,"htZb": 1.56,"fyXj": 0,"fyZbXj": 0},{"type": null,"xuhao": 2,"user": "肖永梅","timeJson": "[{\"bxPrice\":0.00,\"fyPrice\":0.00,\"fyzb\":0.00,\"htPrice\":0.00,\"swPrice\":0.00,\"time\":\"2023年\"},{\"bxPrice\":0.00,\"fyPrice\":0.00,\"fyzb\":0.00,\"htPrice\":0.00,\"swPrice\":0.00,\"time\":\"2024年\"}]","htXj": 0,"htZb": 0,"fyXj": 0,"fyZbXj": 0}]//将数据添在第一行this.userStatistics.unshift(this.summaryStatistics);this.userStatistics.forEach((item) => {if (item.timeJson != null) {JSON.parse(item.timeJson).forEach((child, index) => {item[`htPrice${index}`] = child.htPrice;item[`fyPrice${index}`] = child.fyPrice;item[`fyzb${index}`] = child.fyzb;});}});
数据准备好后就是导出方法了(handleExport)
/** 导出按钮操作 */handleExport() {const loading = this.$loading({lock: true,text: "导出excel中...(若长时间无响应请刷新页面)",spinner: "el-icon-loading",background: "rgba(0, 0, 0, 0.7)",});const Exceljs = require("exceljs"); // 引入exceljsconst workbook = new Exceljs.Workbook(); // 创建工作簿const workSheet = workbook.addWorksheet("sheet1"); // 创建工作表(sheet1)workSheet.getRow(1).height = 60;workSheet.getRow(2).height = 36;workSheet.getRow(3).height = 28;workSheet.getRow(4).height = 28;let style = {alignment: {vertical: "middle",horizontal: "center",wrapText: true,},fill: {type: "pattern",pattern: "solid",fgColor: { argb: "E3F2D9" },},border: {top: { style: "thin" }, // 设置上边框样式为细线bottom: { style: "thin" }, // 设置下边框样式为细线left: { style: "thin" }, // 设置左边框样式为细线right: { style: "thin" }, // 设置右边框样式为细线},};// 获取动态年份条数let years = this.times.length;workSheet.mergeCells(`A1:${this.numberToMatchLetter(3 * years + 6)}1`); //将A1到xx的单元格合并const cell_A1 = workSheet.getCell("A1"); // 获取A1单元格cell_A1.value = "碧朗科技销售员销售额及费用统计表";cell_A1.font = { size: 18, bold: true, name: "宋体" }; // 设置字体大小为16,加粗,仿宋cell_A1.alignment = style.alignment;workSheet.mergeCells(`${this.numberToMatchLetter(3 * years + 7)}1:${this.numberToMatchLetter(3 * years + 10)}1`); //将xx1到xx1的单元格合并const cell_P1 = workSheet.getCell(`${this.numberToMatchLetter(3 * years + 7)}1`); // 获取xx1单元格cell_P1.value = "注:第4行的年份根据筛选条件动态变化";cell_P1.font = {size: 11,name: "Times New Roman",color: { argb: "FF0000" },};cell_P1.alignment = style.alignment;workSheet.mergeCells("A2:E2"); //将A2到E2的单元格合并const cell_A2 = workSheet.getCell("A2"); // 获取A2单元格cell_A2.value = `年份:${this.queryParams.startYear ? this.queryParams.startYear : ""}-${this.queryParams.endYear ? this.queryParams.endYear : ""} 月份:${this.queryParams.startMonth ? this.queryParams.startMonth : ""}-${this.queryParams.endMonth ? this.queryParams.endMonth : ""}`;cell_A2.font = { size: 8, bold: true, name: "宋体" };cell_A2.alignment = {vertical: "middle",wrapText: true,};workSheet.mergeCells("A3:A4"); //将A3到A4的单元格合并const cell_A3 = workSheet.getCell("A3"); // 获取A3单元格cell_A3.value = "序号";cell_A3.style = style;cell_A3.font = { size: 11, bold: true, name: "宋体" };// 遍历合并A3到A4的单元格的区域,为其余部分设置边框for (let row = 3; row <= 4; row++) {for (let col = 1; col <= 1; col++) {const cell = workSheet.getCell(row, col);cell.border = cell_A3.border;}}workSheet.mergeCells("B3:B4"); //将B3到B4的单元格合并const cell_B3 = workSheet.getCell("B3"); // 获取B3单元格cell_B3.value = "销售员";cell_B3.style = style;cell_B3.font = { size: 11, bold: true, name: "宋体" };// 遍历合并B3到B4的单元格的区域,为其余部分设置边框for (let row = 3; row <= 4; row++) {for (let col = 2; col <= 2; col++) {const cell = workSheet.getCell(row, col);cell.border = cell_B3.border;}}workSheet.mergeCells(`C3:${this.numberToMatchLetter(years + 4)}3`);const cell_diy1 = workSheet.getCell("C3");cell_diy1.value = "销售额";cell_diy1.style = style;cell_diy1.font = { size: 11, bold: true, name: "宋体" };// 遍历合并的单元格的区域,为其余部分设置边框for (let row = 3; row <= 3; row++) {for (let col = 3; col <= years + 4; col++) {const cell = workSheet.getCell(row, col);cell.border = cell_diy1.border;}}workSheet.mergeCells(`${this.numberToMatchLetter(years + 5)}3:${this.numberToMatchLetter(2 * years + 5)}3`);const cell_diy2 = workSheet.getCell(`${this.numberToMatchLetter(years + 5)}3`);// 创建富文本内容const richText = [{text: "费用",font: {name: "宋体",size: 11,bold: true,},},{text: "(报销的费用+备案商务费)",font: {name: "宋体",size: 9,bold: true,color: { argb: "FF0000" },},},];cell_diy2.value = { richText: richText };cell_diy2.style = style;// 遍历合并的单元格的区域,为其余部分设置边框for (let row = 3; row <= 3; row++) {for (let col = years + 5; col <= 2 * years + 5; col++) {const cell = workSheet.getCell(row, col);cell.border = cell_diy2.border;}}workSheet.mergeCells(`${this.numberToMatchLetter(2 * years + 6)}3:${this.numberToMatchLetter(3 * years + 6)}3`);const cell_diy3 = workSheet.getCell(`${this.numberToMatchLetter(2 * years + 6)}3`);cell_diy3.value = "费用占比(%)";cell_diy3.style = style;cell_diy3.font = { size: 11, bold: true, name: "宋体" };// 遍历合并的单元格的区域,为其余部分设置边框for (let row = 3; row <= 3; row++) {for (let col = 2 * years + 6; col <= 3 * years + 6; col++) {const cell = workSheet.getCell(row, col);cell.border = cell_diy3.border;}}const cell_XJ1 = workSheet.getCell(`${this.numberToMatchLetter(3 + years)}4`); // 获取单元格cell_XJ1.value = "小计";cell_XJ1.style = style;cell_XJ1.font = { size: 11, bold: true, name: "宋体" };const cell_ZB1 = workSheet.getCell(`${this.numberToMatchLetter(4 + years)}4`); // 获取单元格cell_ZB1.value = "占比(%)";cell_ZB1.style = style;cell_ZB1.font = { size: 11, bold: true, name: "宋体" };const cell_XJ2 = workSheet.getCell(`${this.numberToMatchLetter(5 + 2 * years)}4`); // 获取单元格cell_XJ2.value = "小计";cell_XJ2.style = style;cell_XJ2.font = { size: 11, bold: true, name: "宋体" };const cell_XJ3 = workSheet.getCell(`${this.numberToMatchLetter(6 + 3 * years)}4`); // 获取单元格cell_XJ3.value = "小计";cell_XJ3.style = style;cell_XJ3.font = { size: 11, bold: true, name: "宋体" };// 销售额动态年份填充for (let i = 1; i <= years; i++) {workSheet.getCell(`${this.numberToMatchLetter(2 + i)}4`).value =this.times[i - 1].time;workSheet.getCell(`${this.numberToMatchLetter(2 + i)}4`).style = style;workSheet.getCell(`${this.numberToMatchLetter(2 + i)}4`).font = {size: 11,bold: true,name: "宋体",};workSheet.getCell(`${this.numberToMatchLetter(years + 4 + i)}4`).value =this.times[i - 1].time;workSheet.getCell(`${this.numberToMatchLetter(years + 4 + i)}4`).style =style;workSheet.getCell(`${this.numberToMatchLetter(years + 4 + i)}4`).font ={size: 11,bold: true,name: "宋体",};workSheet.getCell(`${this.numberToMatchLetter(2 * years + 5 + i)}4`).value = this.times[i - 1].time;workSheet.getCell(`${this.numberToMatchLetter(2 * years + 5 + i)}4`).style = style;workSheet.getCell(`${this.numberToMatchLetter(2 * years + 5 + i)}4`).font = {size: 11,bold: true,name: "宋体",};}let exportTableProp = [{ key: "xuhao" },{ key: "user" },{ key: "htXj", width: 18 },{ key: "htZb", width: 18 },{ key: "fyXj", width: 18 },{ key: "fyZbXj", width: 18 },];if (this.times.length > 0) {this.times.forEach((item, index) => {exportTableProp.splice(index + 2, 0, {key: `htPrice${index}`,width: 18,});});this.times.forEach((item, index) => {exportTableProp.splice(index + years + 4, 0, {key: `fyPrice${index}`,width: 18,});});this.times.forEach((item, index) => {exportTableProp.splice(index + 2 * years + 5, 0, {key: `fyzb${index}`,width: 18,});});}workSheet.columns = exportTableProp; // 工作表添加表头workSheet.addRows(this.userStatistics); // 往工作表插入数据workSheet.eachRow((row, rowNumber) => {if (rowNumber > 4) {row.height = 20;row.alignment = style.alignment;row.eachCell({start: 1,end: 3 * years + 6,},(cell, colNumber) => {cell.border = style.border;});}});// 下载工作簿workbook.xlsx.writeBuffer().then((buffer) => {saveAs(new Blob([buffer], { type: "application/octet-stream" }),"销售员销售额及费用表格导出.xlsx");});loading.close();}
相关文章:
vue+exceljs前端下载、导出xlsx文件
首先安装插件 npm install exceljs file-saver第一种 简单导出 //页面引入 import ExcelJS from exceljs; import {saveAs} from file-saver; export default {methods: { /** 导出操作 */async handleExportFun() {let that this// 获取当前年月日 用户下载xlsx的文件名称设…...
算法定制LiteAIServer摄像机实时接入分析平台烟火检测算法的主要功能
在现代社会,随着人工智能技术的飞速发展,智能监控系统在公共安全领域的应用日益广泛。其中,烟火检测作为预防火灾的重要手段,其准确性和实时性对于减少火灾损失、保障人民生命财产安全具有重要意义。而算法定制LiteAIServer烟火检…...
用 Python 从零开始创建神经网络(二)
用 Python 从零开始创建神经网络(二) 引言1. Tensors, Arrays and Vectors:2. Dot Product and Vector Additiona. Dot Product (点积)b. Vector Addition (向量加法) 3. A Single Neuron with …...
嘉吉连续第七年亮相进博会
以“新质绿动,共赢未来”为主题,嘉吉连续第七年亮相进博会舞台。嘉吉带来了超过120款产品与解决方案,展示嘉吉在农业、食品、金融和工业等领域以客户为中心的创新成果。这些产品融合了嘉吉在相关领域的前瞻性思考,以及对本土市场的…...
设计模式之单列模式(7种单例模式案例,Effective Java 作者推荐枚举单例模式)
前言 在设计模式中按照不同的处理方式共包含三大类;创建型模式、结构型模式和行为模式,其中创建型模式目前已经介绍了其中的四个;工厂方法模式、抽象工厂模式、生成器模式和原型模式,除此之外还有最后一个单例模式。 单列模式介绍…...
多个服务器共享同一个Redis Cluster集群,并且可以使用Redisson分布式锁
Redisson 是一个高级的 Redis 客户端,它支持多种分布式 Java 对象和服务。其中之一就是分布式锁(RLock),它可以跨多个应用实例在多个服务器上使用同一个 Redis 集群,为这些实例提供锁服务。 当你在不同服务器上运行的…...
100种算法【Python版】第59篇——滤波算法之扩展卡尔曼滤波
本文目录 1 算法步骤2 算法示例2.1 示例描述2.2 python代码3 算法应用:机器人位姿估计扩展卡尔曼滤波(EKF)是一种处理非线性系统的状态估计算法。它通过线性化非线性系统来实现类似于线性卡尔曼滤波的效果。 1 算法步骤 (1)初始化 初始状态: x ^ 0 ∣ 0 \hat{x}_{0|0}...
制造业数字化转型的强大赋能平台:盘古信息IMS OS工软技术底座
在制造业数字化转型的浪潮中,技术底座的选择与实施至关重要。它不仅决定了企业数字化转型的深度与广度,还影响着企业的生产效率、成本控制和市场竞争力。盘古信息IMS OS作为一款强大的工软技术底座,凭借其高度模块化、可配置的设计理念&#…...
域名+服务器+Nginx+宝塔使用SSL证书配置HTTPS
前言 在我的前面文章里,有写过一篇文章 linux服务器宝塔从头部署别人可访问的网站 在这篇文章,有教学怎么使用宝塔和买的服务器的公网IP,以及教怎么打包vue和springboot去部署不用域名的网站让别人访问 那么,这篇文章将在这个…...
UnityAssetsBundle字体优化解决方案
Unity开发某个项目,打包后的apk包体已经高达1.25G了,这是非常离谱的。为了不影响用户体验,需要将apk包体缩小。因为项目本身不包含很多模型以及其他大型资源,排除法将AB包删除,发现app本身就100多M。 由此可以锁定是AB…...
Go的环境搭建以及GoLand安装教程
目录 一、开发环境Golang安装 二、配置环境变量 三、GoLand安装 四、Go 语言的 Hello World 一、开发环境Golang安装 官方网址: The Go Programming Language 1. 首先进入官网,点击Download,选择版本并进行下载: 2. …...
git clone,用https还是ssh
前言 在使用Git去克隆项目时,会遇到https和ssh等形式,这两种又有何种区别呢,本文将重点讨论在具体使用中的问题。 注:第一次使用Git 时,需要先设置全局用户名和邮箱,否则后续使用命令时会报错,也是提醒先添…...
量化交易系统开发-实时行情自动化交易-Okex行情交易数据
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来聊聊基于Okex交易所API获取行情数…...
【重装系统后重新配置2】pycharm 终端无法激活conda环境
pycharm 终端无法激活 conda 环境,但是 Windows本地终端是可以激活的 原因是pycharm 默认的终端是 Windows PowerShell 解决方法有两个: 一、在设置里,修改为cmd 二、下面直接选择...
【LeetCode每日一题】——802.找到最终的安全状态
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 图 二【题目难度】 中等 三【题目编号】 802.找到最终的安全状态 四【题目描述】 有一个有…...
kafka安装部署--详细教程
2.1 安装部署 每次进入 linux 都会自动进入 base 环境,如何关闭 base conda deactivate 手动关闭 conda config --set auto_activate_base false 关闭自动进入 2.1.1 集群规划 bigdata01 bigdata02 bigdata03 zk zk zk kafka kafka kafka 2.1.2 集群部…...
CMD 查询python 出现 No pyvenv.cfg file 很奇怪 2024/11/9
CMD 查询python 出现 No pyvenv.cfg file 很奇怪 查询得到我有很多个...........版本 删除这个变量就不会 因为 没有安装软件 跳转到 Windows 商店 再把主要使用的python路径置顶 现在运行cmd查询 对比之前的图片 可以发现 这一条商店的没有了! 完整测试效果,问题解决了!...
learnopencv系列二:U2-Net/IS-Net图像分割(背景减除)算法、使用背景减除实现视频转ppt应用
文章目录 一、视频转幻灯片应用1.1 什么是背景减除?1.1.1 背景减除简介1.1.2 bgslibrary 1.2 OpenCV背景减除技术1.3 差异哈希1.3.1 图像哈希技术1.3.2 dHash算法1.3.3 图像哈希的速度和准确性测试 1.4 视频转幻灯片应用的工作流程1.5 项目代码1.5.1 环境准备1.5.2 …...
linux命令详解,文件系统权限相关
文件系统权限相关 linux系统中一切都是文件 查看权限 Is -la /etc/passwd更改文件所有者 chown root file修改文件权限 sudo chmod urwx,grw,o-r file sudo chmod ux,gtw,o-r file chmod 400 <file>一、Linux系统中一切都是文件 在linux系统中,几乎所有的…...
2024-11-5 学习人工智能的Day22 openCV(4)
face_recognition 介绍 face_recognition 是一个非常流行的 Python 库,专门用于人脸识别任务。它基于 dlib 库和 HOG(Histogram of Oriented Gradients)特征以及深度学习模型,提供了简单易用的接口来进行人脸检测、面部特征点定位…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
