首页 > 其他分享 >基于前端技术实现的全面预算编制系统

基于前端技术实现的全面预算编制系统

时间:2024-03-25 09:57:18浏览次数:18  
标签:基于 菜单 预算编制 text 前端 let context 预算 selectBudgetType

前言

在现代商业环境中,预测销售数据和实际成本是每个公司CEO和领导都极为重视的关键指标。然而,由于市场的不断变化,准确地预测和管理这些数据变得愈发具有挑战性。为了应对这一挑战,建立一个高效的系统来管理和审查销售数据的重要性不言而喻。今天小编就将为大家介绍一下如何使用葡萄城公司的纯前端表格控件SpreadJS实现一个预算编制系统。

环境准备

Node.js

VSCode代码编辑器

完整代码Github地址(可在阅读本文时配合参考使用)

使用代码实现的在线Demo地址(可在阅读本文时配合参考使用)

实现步骤

1)自定义菜单栏

上图中红色方框划出来的菜单栏叫做在线表格编辑器(Designer),Designer的菜单提供了各种定制化的能力,如新增菜单,修改菜单执行的逻辑,修改图标,修改文字以及删除菜单等功能。

观察上图中,首先新建了一个“预算操作(定制按钮)”tab ,此tab内容包括了三部分,分别是“预算类型”、“预算编制”、“数据”。对应的代码如下:

let config = JSON.parse(JSON.stringify(GC.Spread.Sheets.Designer.DefaultConfig));
config.ribbon.push(
    {
    id: "fill-custom",
    text: "预算操作(定制按钮)",
    buttonGroups: [
    {
        label:"预算类型",commandGroup:{}  
    },    
    {
        label: "预算编制", commandGroup:{}
       
    },
    {
        label: "数据", commandGroup:{}
      
    }]
})
designer.setConfig(config)

通过上述代码,我们来看看实现结果:

Ok ,发现添加了一个“预算操作(定制按钮)”tab,点击此tab,已经有了基础框架

接下来,继续,我们设置当前tab为激活状态,加上active属性,这样子页面初始化后看到的当前tab就是“预算操作(定制按钮)”

{
    id: "fill-custom",
    text: "预算操作(定制按钮)",
    active: true,
    buttonGroups: []
}

接下来,我们设置预算模型command, 我们再次看上面的第一张图,发现预算类型只有一个节点,且该节点是一个下拉框。对应的代码实现方式如下:

{
    label:"预算类型",
    commandGroup: {
        children: ["selectBudgetType"]
    }
}, 

接下来定义“selectBudgetType”,代码如下所示:( 关于定义下拉框子菜单的实现方法详细解释,可以参考此篇文章

const budgetType = {
    cost: 'cost' ,   //成本预算
    sales: 'sales'   //销售预算
}
let selectBudgetType = {
    text: "选择预算类型",
    comboWidth: 120,
    type:"comboBox",
    commandName: "selectBudgetType",
    dropdownList:[
        {
            text:"成本预算",
            value: budgetType.cost
        },{
            text:"销售预算",
            value:budgetType.sales
        },
    ],
    execute:(context,propertyName) => {
        console.log('选择',propertyName)
    },
}
config.commandMap = {selectBudgetType}
designer.setConfig(config)

上述代码为子菜单“selectBudgetType”定义了text,type ,以及dropdownList以及点击事件。exexute方法中propertyName对应的是dropdownList中的value值。

结果如下:

上述代码已经熟悉了如何定义菜单以及子菜单,接下来的两个子菜单(预算编制和数据)就不重复详细介绍,直接上代码:

config.ribbon.push(
    {
    id: "fill-custom",
    text: "预算操作(定制按钮)",
    active: true,
    buttonGroups: [
    {
        label:"预算类型",
        commandGroup: {
            children: ["selectBudgetType"]
        }
    },    
    {
        label: "预算编制",
        thumbnailClass: "ribbon-thumbnail-editing",
        commandGroup: {
            children: [ "distributeTask"]
        }
    },
    {
        label: "数据",
        commandGroup: {
            children: ["clearLocalData"]
        }
    }]
})
config.commandMap = {
    selectBudgetType:{
        text: "选择预算类型",
        comboWidth: 120,
        type:"comboBox",
        commandName: "selectBudgetType",
        dropdownList:[
            {
                text:"成本预算",
                value: budgetType.cost
            },{
                text:"销售预算",
                value:budgetType.sales
            },
        ],
        execute:(context,propertyName) => {
              console.log('选择',propertyName)
        }
    },
    distributeTask: {
        title: "下发预算任务",
        text: "预算编制",
        iconClass: "distribute-icon",
        bigButton: true,
        commandName: "distributeTask",
        execute: function (context) {
           
        }
    },
    clearLocalData: {
        title: "清除本地缓存",
        text: "清除本地缓存",
        iconClass: "clear-local-icon",
        bigButton: true,
        commandName: "clearLocalData",
        execute: function () {
            localStorage.clear()
        }
    },
}
designer.setConfig(config)

icon相关代码,注意iconClass要添加相应的背景图片。

.clear-local-icon {
  background: url("../assets/clear.png");
  background-size: 35px 35px;
}
.distribute-icon {
  background: url("../assets/distribute.png");
  background-size: 35px 35px;
}

上述三个子菜单中的execute方法需要自定义,如选择选择预算类型后,模板需要进行切换。

2)设置模板

当“选择预算类型”选择“成本预算”时,加载cost.json文件

当“选择预算类型”选择“销售预算”时,加载sales.json文件

let selectBudgetType = {
    text: "选择预算类型",
    comboWidth: 120,
    type:"comboBox",
    commandName: "selectBudgetType",
    dropdownList:[
        {
            text:"成本预算",
            value: budgetType.cost
        },{
            text:"销售预算",
            value:budgetType.sales
        },
    ],
    execute:(context,propertyName) => {
        if(propertyName){
            selectedBudget.value = propertyName
            loadTemplate(context,propertyName,taskId)
         }  
    },
    getState:(context)=>{
        return selectedBudget.value
    },
}

const loadTemplate = async (designer,fileName,taskId) => {
    let templateStr = await BusinessType.getTemplate(fileName)
    let template = JSON.parse(templateStr)
    let spread = designer.getWorkbook()
    spread.fromJSON(template)  
}

上述代码介绍了【选择预算类型】下拉框选中的事件,选中后,导入对应的json文件,通过fromJSON进行导入。

对于需要设置的模板,可以通过Designer中菜单快速设计,其菜单基本与Excel一致,对于熟悉Excel的用户来说,真的很友好。

3)设置数据源

下面小编以“销售预算”模板为例,介绍如何设置数据源:

点击“数据”tab,接下来点击“工作表绑定”,此时出现右侧字段列表Panel。发现字段列表中存在“id”和“name ",这是因为在模板(sales.json)中已经设置好字段。

此时进行数据绑定setDataSource():

const bindInitialData = (spread,type,taskId) => {
    // 绑定初始数据
    let data = defaultBudgetData[type]
    let source = new GC.Spread.Sheets.Bindings.CellBindingSource(data)
    spread.suspendPaint()
    let sheetCount = spread.getSheetCount()
    for(let i=0; i<sheetCount;i++){
        let sheet = spread.getSheet(i)
        sheet.setDataSource(source)
    }
    spread.resumePaint()
    taskId.value = data.id
}
const defaultBudgetData = {
  [budgetType.cost]: {
    id:`成本NV-${getNowTime()}`,//项目编号
    name:'',    //项目名称
    city: '',   //项目所在地
    customer: '',    //客户名称
    price: 0        //本次报价
},
  [budgetType.sales]:{
    id: `销售NV-${getNowTime()}`,
    name:''
  }
}

4)任务下发

(1)在任务下发前 ,需要确认预测因子,预测因子基于往年数据,确认接下来的销售计划。

(2)填写预算名称 。

(3)点击“预算编制”菜单。

distributeTask: {
    title: "下发预算任务",
    text: "预算编制",
    iconClass: "distribute-icon",
    bigButton: true,
    commandName: "distributeTask",
    execute: function (context) {
        confirmDistribute(context,selectedBudget,distributeVisible)
    }
},

const confirmDistribute = (context,selectBudgetType,distributeVisible) => {
    /**预算任务下发时必填信息校验 */
    let sheet = context.getWorkbook().getSheet(0)
    let source = sheet.getDataSource().getSource()
    for(let key in source){
        if(!source[key]){
            ElMessage.error("红色区域必填项信息缺失")
            return
        }
    }
    // 确认是否下发编制任务
    ElMessageBox.confirm("确认下发预算编制任务吗?","下发确认",{
        confirmButtonText:'确认',
        cancelButtonText:"取消",
        type:'warning'
    }).then(() => {
        // 确认下发,存储当前预算模板,下发部门信息
        saveBudgetRecord(context, selectBudgetType)
        distributeBudgetTask(context,distributeVisible)
    }).catch(() => {
        ElMessage({
            type:'error',
            message:'取消发布'
        })
    })
}

在上述代码confirmDistribute()中,通过getDataSource()获取数据源,来判断红色区域的必填项是否填写。当确认下发任务后,执行saveBudgetRecord 、distributeBudgetTask方法。

5)填写任务

当确定下发任务后,对不同部门生成不同的编制链接。此弹窗可以参考代码中的OnlineDesigner.vue文件。

部门经理获取链接,打开链接,显示内容是自己部门区域预算明细填写和实际填写,此时,部门经理可以在左侧蓝色区域填写,而其他单元格不能编辑,这个是怎么做到的呢?具体可以参考这篇文章中第二点对少部分单元格可以编辑。

var defaultStyle = new GC.Spread.Sheets.Style();
defaultStyle.locked = false;
sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
// 设置第1行不可编辑
var style = new GC.Spread.Sheets.Style();
style.locked = true;
style.backColor = "red";
sheet.setStyle(0, -1, style);
// 设置表单保护
sheet.options.isProtected = true;  

介绍完单元格的权限后,我们再来看下上图中还有哪些值得说一说的功能。

(1)添加签名

当经理设置完预算后,可以在区域总监单元格右键,看到多出来两个菜单“添加签名”和“添加手写签名”。

所以接下来介绍如何在右键菜单中新增菜单并定义其事件,代码如下:

let signMenu = {
    text:"添加签名",
    name:"signName",
    command:"signMenuCommand",
    workArea: "viewport"
}
spread.contextMenu.menuData.push(signMenu)

上述代码在spread.contextMenu.menuData中push了一条对象,结果就是可以在右键菜单中看见“添加签名菜单” ,观察到上述对象定义了command属性,接下来定义“signMenuCommand”:

let signMenuCommand = {
    canUndo: true,
    execute: function(context,options,isUndo){
        if(isUndo){
            GC.Spread.Sheets.Commands.undoTransaction(context,options)
            return true
        }else{
            GC.Spread.Sheets.Commands.startTransaction(context,options)
            let {activeRow,activeCol,sheetName} = options
            let sheet = context.getSheetFromName(sheetName)
            sheet.getCell(activeRow,activeCol).value(user).backColor('#F7A711').font('bold normal 15px normal')
            GC.Spread.Sheets.Commands.endTransaction(context,options)
            return true
        }
    }
}
commandManager.register("signMenuCommand",signMenuCommand,null, false, false, false, false)

上述代码是SpreadJS中注册命令的方法,并提供了撤销机制。我们主要看else里面的内容:首先从上下文context中获取sheet对象,接着获取单元格并设置内容、背景色、字体等。上述两段代码就实现了在SpreadJS中在右键菜单中添加菜单,并完整相应的点击逻辑。

(2)添加手写签名

接下来,我们看看如何设置“添加手写签名”:

// 注册签名的右键菜单
let commandManager = spread.commandManager()
let signMenu = {
    text:"添加手写签名",
    name:"handWriteName",
    command:"handWriteCommand",
    workArea: "viewport"
}
spread.contextMenu.menuData.push(signMenu)
let handWriteCommand = {
    canUndo: false,
    execute: function(context,options,isUndo){
        showWriteDialog.value = true
    }
}
commandManager.register("handWriteCommand",handWriteCommand,null, false, false, false, false)

添加菜单和菜单命令的方式与前文一致,不同的就是execute的执行逻辑。

最后,签名设置后,就可以点击“提交预算”按钮。

对了,如果数据不符合预期,可能会有红色预警,比如

这个是SpreadJS的数据验证功能,我们可以通过UI方式设置。如下图所示:

6)编制完成

当所有部门经理填写完预算后,就可以点击“编制完成”

此时点击“预算审核”,预算类型设置为“销售预算”,可以看到有一条待审核的标签,点进去看看。

看到了我们熟悉的页面

此时点击“华东”sheet看看

这个时候就看到了华东部门经理填写的销售预测数据,这个时候点击右上角的“导入年度实际销售数据”看看。

嗯,表格内容基本上填写完整了,这时候审核员(副总经理)如果对销售数据表示满意,可以签上自己的大名,就可以点击“审核完毕了”

当四个sheet都“审核完毕”,此时返回首页,发现标签变了。

这时候可以进行打印了。

最后

简单的全面预算编制系统就算介绍完了。大家可以在Demo地址实际体验下。总结下本文介绍的SpreadJS的几个知识点:

1、自定义Designer菜单

2、导入模板

3、设置数据源

4、获取数据源

5、自定义右键菜单

6、单元格权限

如果您想了解更多的信息,欢迎点击这篇参考资料查看。

扩展链接:

【干货放送】财务报表勾稽分析要点,一文读尽!

为什么你的财务报表不出色?推荐你了解这四个设计要点和!

纯前端类 Excel 表格控件在报表勾稽分析领域的应用场景解析

标签:基于,菜单,预算编制,text,前端,let,context,预算,selectBudgetType
From: https://www.cnblogs.com/powertoolsteam/p/18080540

相关文章

  • 【转载】基于Ado.Net多个关系型数据库DbHelper封装
    主要是记录一下,后续有用的时候再翻看。publicclassDbHelper{privatereadonlyDataBase_dataBase;publicDbHelper(DataBasedataBase){_dataBase=dataBase;}publicDataBaseGetDataBase(){......
  • 基于R语言的GD库实现地理探测器并自动将连续变量转为类别变量
      本文介绍基于R语言中的GD包,依据栅格影像数据,实现自变量最优离散化方法选取与执行,并进行地理探测器(Geodetector)操作的方法。  首先,在R语言中进行地理探测器操作,可通过geodetector包、GD包等2个包实现。其中,geodetector包是地理探测器模型的原作者团队开发的,其需要保证输入的......
  • 基于springboot+vue+Mysql的留守儿童爱心网站
    开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9系统展示系统首页界面宣传新闻界面志愿活动界面爱心捐赠界面个人中心界面用户注册界面管理员登录界面......
  • 基于架构的软件开发方法
          ......
  • 【前端素材】推荐优质多用途生活家具购物商城网站设计Glee平台模板(附源码)
    一、需求分析在线生活家具商店网站是指专门销售各类家具和家居用品的网上商店。这类网站提供用户浏览、选择并购买各种家具产品的平台。以下是在线生活家具商店网站的一般功能:产品展示与购买: 网站展示各种家具产品,如沙发、床、桌子、椅子、柜子等,用户可以查看详细信息、图......
  • 【前端素材】推荐优质多用途肉类品商城网站设计Meatza平台模板(附源码)
    一、需求分析多用途肉类品商城网页是一个在线平台,专门销售各种肉类及相关产品的电子商城。以下是这类网页通常具备的具体功能:产品分类:网页会根据不同种类的肉类进行分类,如牛肉、猪肉、禽类、海鲜等,方便用户查找所需产品。产品展示:网页会展示各种肉类产品的图片、价格、产......
  • 前端学习-vue视频学习013-pinia
    尚硅谷视频教程了解pinia集中式状态(数据)管理的工具,主要管理各组件之间的共享数据准备一个效果学到的几个点html下拉选择框,可以使用v-model双向绑定v-modle获取的值为字符串,可以写为v-model.number,会尽量转为数字<selectname="num"v-model.number="n"><optionval......
  • 基于Spring Boot+Vue的高校学科竞赛平台
    末尾获取源码作者介绍:大家好,我是墨韵,本人4年开发经验,专注定制项目开发更多项目:CSDN主页YAML墨韵学如逆水行舟,不进则退。学习如赶路,不能慢一步。目录一、项目简介二、开发技术与环境配置2.1SpringBoot框架2.2Java语言简介2.3Vue的介绍2.4mysql数据库介绍2.5B/S......
  • 基于Spring Boot+Vue的高校办公室行政事务管理系统
    末尾获取源码作者介绍:大家好,我是墨韵,本人4年开发经验,专注定制项目开发更多项目:CSDN主页YAML墨韵学如逆水行舟,不进则退。学习如赶路,不能慢一步。目录一、项目简介二、开发技术与环境配置2.1SpringBoot框架2.2Java语言简介2.3Vue的介绍2.4mysql数据库介绍2.5B/S......
  • 基于GD32E230C8T6的数字示波器
    基于GD32E230C8T6的数字示波器文章目录基于GD32E230C8T6的数字示波器基于GD32E230C8T6的数字示波器实物演示电路原理**模拟前端处理电路**image.png**交直流耦合电路****输入信号衰减电路****信号调理电路****虚断:****虚短:****电压跟随器****反相......