This commit is contained in:
陈裕财
2024-07-08 05:36:35 +08:00
104 changed files with 3865 additions and 4578 deletions

630
README.md
View File

@@ -4,34 +4,31 @@
</a>
</p>
<p align="center">
<strong>唛盟(mdp-lcode vue3 ):多功能、高效率、低代码(支持0代码) 前后端一体化、智能化的开发工具</strong>
<strong>唛盟xm涵盖项目规划、需求管理、开发迭代、版本控制、缺陷跟踪、测试管理、工时管理、效能分析等环
节,实现项目全过程、全方位管理的一站式企业研发项目管理解决方案</strong>
</p>
<p align="center">
<a target="_blank" href="https://gitee.com/maimengcloud/mdp-lcode-ui-web">
<img src='https://gitee.com/maimengcloud/mdp-lcode-ui-web/badge/star.svg?theme=gvp' alt='gitee star'/>
<a target="_blank" href="https://gitee.com/maimengcloud/xm-ui-web">
<img src='https://gitee.com/maimengcloud/xm-ui-web/badge/star.svg?theme=gvp' alt='gitee star'/>
</a>
</p>
<p align="center">
👉 <a target="_blank" href="https://maimengcloud.com/lcode">https://maimengcloud.com </a> 👈
👉 <a target="_blank" href="https://maimengcloud.com/xm/m1/">https://maimengcloud.com</a> 👈
</p>
## 快速导航
## 快速导航
- [唛盟-后端开发底座](https://gitee.com/maimengcloud/mdp-core)
- [前端组件](https://gitee.com/maimengcloud/mdp-lcode-ui-web)
- [后端服务](https://gitee.com/maimengcloud/mdp-lcode-backend)
- [体验环境](https://maimengcloud.com/lcode/)
登陆界面上选择演示账号登陆或者直接扫码登陆,无须注册
- 👉[教程]b站上搜素 [唛盟9哥教你撸前后端代码](https://www.bilibili.com/video/BV111421S72r/?spm_id_from=333.337.search-card.all.click&vd_source=93be23d03863773d50b81112985b9237)
- [前端组件](https://gitee.com/maimengcloud/xm-ui-web)
- [后端服务](https://gitee.com/maimengcloud/xm-backend)
- [体验环境](https://maimengcloud.com/xm/m1/)
登陆界面上选择演示账号登陆(账号密码demo-branch-01 888888)或者直接扫码登陆,无须注册
- 相关教程b站上搜素[唛盟9哥教你撸前后端代码](https://www.bilibili.com/video/BV111421S72r/?spm_id_from=333.337.search-card.all.click&vd_source=93be23d03863773d50b81112985b9237)
## 📢 简介[唛盟低代码开发平台mdp-lcode](/)
唛盟低代码开发平台简称唛盟或者mdp. 👉[唛盟-总体介绍](https://www.bilibili.com/video/BV111421S72r/?spm_id_from=333.337.search-card.all.click&vd_source=93be23d03863773d50b81112985b9237)
唛盟旨在为企业开发业务系统提供一整套解决方案唛盟具有高效率、低代码、支持0代码、功能丰富等特点。企业可以在唛盟工程之上加入更多其它业务功能也可以以唛盟作为模板创建新的工程用于开发其它业务。使用唛盟构建应用您不用考虑多租户、登录、统一认证中心、权限、菜单管理、系统管理、公共组件、公共api、代码冗余、数据字典、图片库、文件库、智能表单、工作流、微服务互相调用、全局跟踪定位bug、多主键crud,复杂sql查询等各种问题这些问题的解决方案都作为扩展功能内置唛盟工程中了。
## 📢 简介[唛盟xm](/)
唛盟企业级研发管理系统简称唛盟xm,属于唛盟生态的专业子系统之一,以研发管理为核心,涵盖项目规划、需求管理、开发迭代、版本控制、缺陷跟踪、测试管理、工时管理、效能分析等环节,实现全过程、全方位的研发管理。通过该系统,企业能够优化研发流程,提高研发效率,降低研发成本,提高市场竞争力。
💪给你一个使用唛盟的理由代码大量减少、开发so easy、前后端MIT协议、全部开源、永久免费
## 📢 唛盟生态
@@ -78,7 +75,7 @@
| 框架 | 说明 | 版本 |
|----------------------------------------------------------------------|------------------|--------|
| spring boot | spring boot 框架 | 2.4.1 |
| spring boot | spring boot 框架 | 2.6.11 |
| mybatis plus | 数据库操作框架 | 3.5.3.1 |
| spring security | 安全框架 | 2.1.7 |
| jsqlparse | sql解析引擎 | 4.7+ |
@@ -110,7 +107,6 @@
| Prettier | 代码格式化 |
| ESLint | 脚本代码检查 |
| DotENV | env 文件高亮 |
| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro)|前端流程ui基于若依修改
@@ -120,513 +116,176 @@
| idea | java 开发工具 社区版、企业版都可 |
## 😭 日常开发中,您是否有以下痛点?
- **团队中缺乏企业级前后端分离的开发底座**,需要在各种框架中进行摸索、整合。
- ai时代开发工具如何去支持未来的软件开发
- 重复造轮子现象严重、浪费人力、对开发者经验要求过高
- 缺乏统一的开发模式缺乏公共组件的抽取和共享机制导致业务代码混乱不堪、代码臃肿、bug多、维护困难
- 缺乏统一的足够灵活的权限管理机制,开发人员不得不写一堆的权限代码混入业务代码中,前端权限、后端权限控制混乱不堪
- 缺乏统一的能够覆盖前后端的、满足前后端分离的代码生成器,代码模板无法按企业现状进行重新编辑、修改
- 缺乏统一的编程规范,或者具有书面编程规范,难以贯彻落实到开发中,代码还是五花八门
- 缺乏统一的元数据(数据字典)管理机制,前后的数据共享调用困难,下拉列表数据混乱不堪
- 缺乏统一的流程管理机制,要想进行流程类业务开发非常困难
- 缺乏统一的国际化机制,国际化实施困难,不得不针对各种语言发布多个版本,无法解决后端国际化、前端国际化等问题
- 缺乏统一的微服务、分布式系统整合机制,微服务互相调用、微服务的权限管理困难
- 缺乏统一的认证中心,单点登录实施困难
- 缺乏统一的支付整合机制接入微信、支付宝、paypal等困难
- 缺乏项目管理工具,项目计划、任务委派、质量管理、需求管理、持续集成等完全没概念
- **让 唛盟-mdp 来帮你解决这些痛点吧!然而,这些只是 唛盟-mdp 解决的最基础的功能。**
## 😁 为什么要使用唛盟产品
- 唛盟所有子系统从前端到后端提供ai支持能力
1. 前端每个字段可以调起ai指令、el表达式
2. 后端每个接口可以支持识别ai指令、el表达式
3. 后端支持接入大模型
4. 具有根据企业数字资产进行ai自训练能力
- 完全开源、永久免费的企业级开发底座
1. 使用mdp能够带来开发效率的大幅提升代码行数大幅减少质量提升明显
2. 使用mdp能够大幅度降低对开发人员的经验要求大幅度降低人力成本
3. mdp对各种开源组件进行了融合改进提供了针对企业开发中各种问题的最佳解决方案
4. 企业使用一套开源软件即同时拥有前端开发框架及后端开发框架
- 统一的开发模式
1. 前后端分离
2. 前后端都分别进行了技术组件、业务组件的抽取、共享,企业可以进行再提炼、抽象,形成更多的公共组件,对后续开发形成强力的支撑作用
- 足够灵活的权限管理机制
1. 前端提供统一的按钮级别的权限判断接口、提供路由菜单的权限控制机制
2. 后端实现api接口的自动注册、自动审核
3. 基于岗位-部门-角色-菜单及按钮-后端api-人员 6要素的权限管理机制可以0编程实现绝大多数的权限需求
- 基于领域驱动设计(DDD)的框架及代码生成器
1. 代码生成器覆盖前端、后端支持任意时刻的重新生成支持命令行、开发工具插件、在线三种方式生成代码生成的代码可以0编程使用
2. 代码生成器代码模板可以按企业现状进行修改、满足不断发展、持续改进的需求
3. 支持多个表一次性生成,也就是可以一次性生成几十到几百张表的增删改查功能,而开发人员仅需要填写表名即可完成
- 提供完整的编程规范说明
1. mdp的框架提供了完备的接口说明、组件说明、组件使用场景等
2. mdp维护团队提供在线支持及时解答、解决开发者使用过程中的问题
- 提供强大的元数据(数据字典)管理机制
1. 内置了元数据管理模块,并实现了元数据的分布式缓存、客户端缓存、元数据分发、缓存清理等
2. 开发者在客户端、任意微服务中、任意单体应用中可以快速获取元数据
3. 元数据的调用效率等同于调用本地map缓存几乎可以忽略使用元数据的性能开销问题
- 整合了最新版本的强大的flowable工作流引擎
1. 基于mdp框架重新开发了流程中心、任务中心、流程的发布、上下架等功能
2. 提供分布式环境下的流程调用、流程整合问题的解决方案
3. 提供vue3版本在线流程设计器并整合了mdp的权限机制
4. 整合了mdp的智能表单
5. 整合了mdp的数据字典通过配置即可实现大部分业务场景真正做到流程设计、部署、运行0耗时0延迟。
4. 任务的提交支持几乎能想到的各种方式:转办、委办、主办、前加签、后加签、减签、发起人处理、驳回任意节点、审批同意、审批不同意但流程继续、拒绝终止流程等,同时提供框架的提交方式可扩展性,让你轻松应对各种变态需求。
5. 会签支持:会签、或签、过半通过、一票否决等等
6. 任务分配到人十来种策略支持并提供扩展接口:按岗位、按部门、按组、按标签、按指定人员、发起人、上一步执行人、上一步执行人临时指定、发起流程时统一指定、转主办、转监控、按高级自定义查询条件、
7. 整合了mdp的消息发送机制轻松发送流程消息到im、站内信、公众号、短信
8. 整合mdp事件模型为将来ai调用流程等创新场景提供底层基础
9. 提供业务模块内嵌页面发起流程的组件和统一的方式,开发几乎可以无视工作流相关的接入工时。
10. 整合mdp附件管理
- 提供强大的国际化解决方案
1. 前后端均支持分别进行国际化
2. 多语言的支持与业务代码完全解耦,彻底解决硬编码进行语言切换的问题
- 整合了强大的微服务框架
1. mdp平台任意组件均同时支持微服务环境、单体应用环境运行开发人员开发的时候可以以单体应用的方式开发然后以微服务方式发布到生产、测试环境
2. 提供微服务的治理
- 强大的DAO层
1. 支持基于xml文件的sql编写
2. 支持无xml方式的数据访问
3. 支持多主键对mybatis plus进行升级解决了多主键、多表联合查询等问题
4. 支持多数据源,通过备注实现数据源切换
5. 支持前端构建任意复杂的查询条件并提供对应的最佳实践,支持前端输入框输入>,=,*,$IS NULL,$IN,$NOT IN等运算操作符支持前端通过 or and 连接符构建任意复杂的条件表达式
- 强大的web ui
1. 提供好用好看的ui组件库
2. 提供页面高级查询功能、可以组装任意复杂的查询条件
3. 提供针对元数据(数据字典)的引用、针对任意表的引用的组件库
4. 提供导入、导出等基础功能
5. 提供按钮权限判断接口、
6. 提供动态菜单功能
- 提供自定义表单解决方案具有0代码0延时发布一个新功能的能力
1. 自定义表单设计
2. 表单展现
3. 表单数据管理
4. 自定义表单与工作流整合使用
5. 自定义表单发布成普通菜单
- 整合了微信支付、支付宝支付、paypal支付
1. 提供支付、订单、支付通知底层框架,可以快速整合各种支付功能
2. 整合了微信支付功能,进行配置文件更新即可使用
3. 整合了支付宝支付功能,进行配置文件更新即可使用
4. 整合了paypal支付进行配置文件更新即可使用
- 整合了oauth2.0框架
1. 提供oauth2.0的整体框架,构建统一认证中心、单点登录等不再是难事
2. 整合了微信、支付宝、手机验证码、账户密码等登录方式
## 💪 内置功能、界面展示
### 组织管理
|功能 |描述|
|-------------------------------|--------------------------|
|机构管理 | 企业信息维护、管理员维护、账户信息维护、企业产品维护、|
|用户管理 | 用户的crud、分配岗位、分配部门、重置密码、邀请|
|部门管理 | 部门curd、分配岗位到部门、查看部门用户|
|公司管理 | 公司curd超级管理员使用|
|岗位管理 | 岗位curd、分配角色到岗位、岗位人员查看|
|注销审核 | 审核用户的注销申请|
![branch-set](./docs/images/module/branch-set.png)
![dept-set](./docs/images/module/dept-set.png)
### 个人中心
|功能 |描述|
|-------------------------------|--------------------------|
|个人信息 | 基本信息、邮箱、手机、企业绑定、微信绑定等|
|我的消息 | 接收个人私信、公告等|
|登录日志 | 查询我的登录日志 |
![user](./docs/images/module/profile-base.png)
### 角色权限
|功能 |描述|
|-------------------------------|--------------------------|
|角色管理 | 角色crud、分配菜单、分配权限|
|权限定义 | 权限crud|
|菜单管理 | 菜单(按钮)crud、分配菜单(按钮)给角色、|
|模块管理 | 模块crud|
|已开模块 | 查看企业(个人)已开通的模块|
![post-set](./docs/images/module/post-set.png)
![role](./docs/images/module/role.png)
### 平台管理
|功能 |描述|
|-------------------------------|--------------------------|
|平台配置 | 配置平台的信息|
|个人认证审核 | 审核个人的实名认证请求|
|企业认证审核 | 审核企业的实名认证请求|
![platform](./docs/images/module/platform.png)
### 元数据管理
|功能 |描述|
|-------------------------------|--------------------------|
|字典管理 | 数据字典的crud|
|列表维护 | 下拉列表数据项的crud|
|参数定义 | 公共系统参数的crud|
![metaItem](./docs/images/module/metaItem.png)
![itemSet](./docs/images/module/itemSet.png)
![optionList](./docs/images/module/optionList.png)
### 数据模型
|功能 |描述|
|-------------------------------|--------------------------|
|模型中心 | 模型的crud|
|表格结构 | 表结构预览、表结构修改、表的字段维护等|
|表格数据 | 表的业务数据crud等|
|数据集市 | 可以快速构造查询sql提供给外部接口、智能表单、数据分析等使用|
|创建数据集 | 数据集的设计、保存、预览数据等|
![dm-table-struct](./docs/images/module/dm-table-struct.png)
![dm-table-data](./docs/images/module/dm-table-data.png)
![dm-sql-exec](./docs/images/module/dm-sql-exec.png)
### 智能表单
支持mdp-ui组件的拖拉拽支持表单0编码0耗时发布形成一个新的功能
|功能 |描述|
|-------------------------------|--------------------------|
|表单中心 |表单列表,权限管理,数据查阅等 |
|创建表单 | 表单设计、预览|
![formDesigner](./docs/images/module/form-designer.png)
### 内容管理
|功能 |描述|
|-------------------------------|--------------------------|
|附件库 | 附件上传、预览、权限配置等|
|图片库 | 图片上传、预览、删除等|
|图标库 | 图标的预览、选用等|
![images](./docs/images/module/images-list.png)
![icon](./docs/images/module/icon-list.png)
### 订单管理
|功能 |描述|
|-------------------------------|--------------------------|
|我的订单 | 订单查看、管理、打折促销等|
|购买产品 | 下单购买应用|
|增购人数 | 增加企业人数|
|续费 | 到期续费|
![order](./docs/images/module/mall-order.png)
### 第三方管理
|功能 |描述|
|-------------------------------|--------------------------|
|邀请管理 | 查询、管理我发起的邀请|
|我邀请的用户 | 查询我邀请的用户列表|
|第三方用户查询 | 查询第三方账户信息 |
### 流程模型
|功能 |描述|
|-------------------------------|--------------------------|
|流程编辑器 | 在线流程编辑器|
|模型发布 | 流程模型发布|
|模型设置 | 设置流程与智能表单的关联、模型的启动条件、审批人、权限等|
![modelflow](./docs/images/module/modelflow.png)
![workflow-model-designer](./docs/images/module/workflow-model-designer.png)
![workflow-model-assignee](./docs/images/module/workflow-task-assignee.png)
![workflow-model-form](./docs/images/module/workflow-task-form.png)
### 审批中心
|功能 |描述|
|-------------------------------|--------------------------|
|待执行 | 我的待执行任务查询、任务执行|
|日历任务 | 我的待执行任务查询、任务执行|
|发起流程 | 发起流程|
## 😭 日常项目管理中,您是否有以下痛点?
### 需求管控困难
- 需求不明确:客户提出一些模糊的需求,这可能导致开发团队对需求的理解存在偏差。
- 信息分散、杂乱需求可能散落在多个地方如邮件、Excel表格、即时通讯工具、不同的项目组等无法进行统一管理。
- 需求追溯困难:提出者、评审者、实施人等不明确,导致责任不清、分工不明等问题产生
- 需求与开发脱节:无法实时跟踪需求完成情况。无法实时定位需求进度落后原因,进而无法做出补救措施。
- 需求与测试不匹配:需求文档与测试用例不匹配导致测试工作无法顺利进行
- 需求变更频发:频繁变更需求,给开发团队带来很大的困扰。
### 任务管理困难
- 任务分配不明确:任务通过口头或邮件形式进行分配,这可能导致任务责任不明确和任务重叠。
- 任务发布、沟通困难:由于涉及的成员和部门众多,信息同步不及时,很容易导致项目协作混乱。
- 任务进度把控难:缺乏有效的工具来跟踪任务进度,团队成员很难准确把握项目的整体完成情况,也无法针对性地进行调整。
- 任务风险管理不充分:常常忽视任务风险管理,导致项目面临较大的风险。
- 工时统计困难:手动记录工时不仅容易出错,而且难以统计和分析,这不仅影响团队成员的个人成果统计,也影响团队之间的凝聚力和协作效果。
![workflow-task-detail](./docs/images/module/workflow-task-detail.png)
![workflow-task-action](./docs/images/module/workflow-task-action.png)
![workflow-task-ruli](./docs/images/module/workflow-task-ruli.png)
![workflow-task-start](./docs/images/module/workflow-task-start.png)
### 质量管理困难
- 质量标准不明确:缺乏明确的质量标准和规范,导致团队成员对质量要求的理解存在差异,从而影响软件质量。
- 质量保证不到位:导致软件存在缺陷和漏洞,影响用户体验和产品可靠性。
- 测试不全面:缺乏缺陷登记跟踪工具、缺乏测试用例管理工具,导致一些潜在问题未被发现和解决,从而影响软件质量。
- 质量管理与开发流程不融合:质量管理与开发流程相互分离,导致质量管理与开发效率相互影响,难以实现高效的软件开发。
### 审批监控
|功能 |描述|
|-------------------------------|--------------------------|
|我发起的流程 | 查询我发起的流程|
|我监控的流程 | 查询我监控的流程、催办|
|我参与的流程 | 查询我参与过的流程|
### 缺乏协作&沟通
- 沟通渠道不统一:在开发团队中,不同的成员可能有不同的沟通渠道,导致信息分散,难以统一管理。
- 沟通不够及时:在开发过程中,有时沟通不够及时,导致一些重要信息滞后的处理,影响了项目进度。
- 沟通不够清晰:由于技术术语或背景知识的不同,团队成员之间的沟通有时不够清晰,导致理解上的偏差。
- 沟通缺乏反馈机制:在沟通中,有时缺乏反馈机制,导致对问题的处理不够及时和有效。
![monitorflow](./docs/images/module/monitorflow.png)
### 缺乏效能分析
- 缺乏组织级、项目级、产品级、团队级、个人级、迭代级等不同组织级别的效能分析:企业在长期项目实施过程中,未构建起从组织级到个人级的效能分析体系,无法全面掌握企业的项目运作全貌,进而无法有效进行资源调配,利益最大化。
- 缺乏对不同职能部门的多维度的效能分析
- 缺乏风险预警、风险分析
- 项目报告不全面、不准确
- 质量报告不全面、不准确
- 进度计划汇总、分解困难
### 低代码
|功能 |描述|
|-------------------------------|--------------------------|
|代码生成器 | 在线生成crud的前端页面代码(表单、表格、api)后端代码控制层、服务层、dao层代码前后端0修改即可正常运行 |
## 解决之道
![解决之道](/docs/images/xm-jg/xm-1-jjzd.png)
### 界面风格切换
### 系统概况
![系统概况](/docs/images/xm-jg/xm-2-xtgk.png)
![black-style](./docs/images/module/black-style.png)
### 系统特点
![系统特点](/docs/images/xm-jg/xm-3-xttd.png)
![black-branch-set](./docs/images/module/black-branch-set.png)
### 系统功能
![系统功能](/docs/images/xm-jg/xm-4-xtgn.png)
![blackdept](./docs/images/module/blackdept.png)
### 技术架构
![技术架构](/docs/images/xm-jg/xm-5-jsjg.png)
## ⚙ 组件库[mdp-ui](/src/components/mdp-ui)
mdp封装了几十个ui组件,使用mdp-ui与不使用mdp-ui的区别写100行代码还是写1行代码的区别代码量的减少立竿见影
- [mdp-ui](/src/components/mdp-ui)
mdp的核心组件该组件库为纯前端页面组件无须配置任何后端api接口即可正确运行
- [mdp-ui-ext](/src/components/mdp-ui-ext)
基于mdp-ui扩展的带有对接后台api业务加载能力的业务组件
### 应用架构
![应用架构](/docs/images/xm-jg/xm-6-yyjg.png)
>⚠️注意:先行体验一把[mdp-ui组件效果预览](https://maimengcloud.com/lcode/#/mdp/lcode/index)
### 非唛盟的子系统如何快速整合mdp-ui组件库
>找到[main.ts](/src/main.ts) 添加下面代码
```js
### 项目总体管理
![项目总体管理](/docs/images/xm-jg/xm-8-ztgl.png)
//mdp-ui 基础组件
import MdpComponents from '@/components/mdp-ui/index.js'
//mdp-ui-ext拓展的组件
import MdpUiExtComponents from '@/components/mdp-ui-ext/index.js'
//唛盟公共api
import MdpPubApi from "@/api/mdp_pub";
const app = createApp(App)
### 需求管理
![需求管理](/docs/images/xm-jg/xm-9-xqgl.png)
app.use(MdpComponents)
app.use(MdpUiExtComponents)
app.config.globalProperties.$mdp=MdpPubApi
```
### 项目计划
![项目计划](/docs/images/xm-jg/xm-10-xmjh.png)
### [mdp-dialog](/src/components/mdp-ui/mdp-dialog)
弹框,可以把任意页面装配成弹框,无须定义多余的变量及函数
- 相对于el-dialog来说要使用弹窗事情还真不少。需要定义visible变量定义showDialog,closeDialog两个函数最关键一点是如果要父页面传递参数到窗口内组件还得在父页面定义一个变量通过props属性传递。相当麻烦。如果某个功能弹窗特别多会有一堆的控制弹窗的变量及函数非常恶心。mdp-dialog则完全解决上述问题。
### [mdp-table](/src/components/mdp-ui/mdp-table)
表格,内置了增、删、改、查、高级查询、重置查询、导出、列配置、分页、批量编辑等功能、内置了对按钮权限的控制机制
功能非常强大,懂的都懂。
### 质量管理
![质量管理](/docs/images/xm-jg/xm-11-zlgl.png)
- 综合管理
![综合管理表格](/docs/images/ui-components/table-mng.jpg)
- 可编辑表格
![可编辑表格](/docs/images/ui-components/edit-table.jpg)
- 可编辑-树状表格
![可编辑-树状表格](/docs/images/ui-components/left-right-tree-table.jpg)
### [mdp-select](/src/components/mdp-ui/mdp-select)
下拉列表,支持对数据字典、元数据的引用,支持对任意小表表格数据的引用,支持参数化加载后台数据,对后台加载的数据进行缓存
![mdp-select](/docs/images/ui-components/select-origin.jpg)
### 迭代管理
![迭代管理](/docs/images/xm-jg/xm-12-ddgl.png)
### [mdp-select-table](/src/components/mdp-ui/mdp-select-table)
超大表格下拉列表与mdp-select相比该组件具有分页查询功能
![分页选择表格数据](/docs/images/ui-components/big-table-select.jpg)
### [mdp-select-user](/src/components/mdp-ui-ext/mdp-select-user)
用户选择下拉列表与mdp-select-table组件类似仅仅针对用户的头像做了特殊处理
![用户选择](/docs/images/ui-components/select-user.jpg)
### 效能分析
![效能分析](/docs/images/xm-jg/xm-13-xnfx.png)
### [mdp-input](/src/components/mdp-ui/mdp-input)
输入框
## 💪 功能展示
### 项目立项
![项目立项](/docs/images/xm-zs/xm-zs-1-xmlx.png)
### [mdp-date](/src/components/mdp-ui/mdp-date)
日期
### [mdp-date-range](/src/components/mdp-ui/mdp-date-range)
区间日期
### 项目总体
![项目总体](/docs/images/xm-zs/xm-zs-2-xmzt.png)
### [mdp-number](/src/components/mdp-ui/mdp-number)
数字输入
### [mdp-hi-query](/src/components/mdp-ui/mdp-hi-query)
高级查询,可以由用户自定义任意复杂的查询条件
![高级查询](/docs/images/ui-components/hi-query.jpg)
### 组织架构
![组织架构](/docs/images/xm-zs/xm-zs-3-zzjg.png)
### [mdp-table-configs](/src/components/mdp-ui/mdp-table-configs)
表格配置,用于控制表格的列显示与否
![表格配置列显示隐藏](/docs/images/ui-components/table-column-configs.jpg)
### [mdp-transfer](/src/components/mdp-ui/mdp-transfer)
穿梭框
### 项目报告
![项目报告](/docs/images/xm-zs/xm-zs-4-xmbg.png)
### [mdp-cate-tree](/src/components/mdp-ui-ext/mdp-cate-tree)
文档、文章目录树
### [mdp-expand](/src/components/mdp-ui-ext/mdp-expand)
智能表单相关组件
### 需求管理
![需求管理](/docs/images/xm-zs/xm-zs-5-xqgl.png)
### [mdp-ext-infos](/src/components/mdp-ui-ext/mdp-ext-infos)
自动扩展字段信息
### 用户故事
![用户故事](/docs/images/xm-zs/xm-zs-6-yhgs.png)
### [mdp-image](/src/components/mdp-ui-ext/mdp-image)
图片库,图片的增删改查、上传、下载
### [mdp-select-image](/src/components/mdp-ui-ext/mdp-select-image)
图片选择器,支持图片的上传下载、上传后的统一管理、共享
### 项目计划
![项目计划](/docs/images/xm-zs/xm-zs-7-xmjh.png)
### [mdp-select-dept](/src/components/mdp-ui-ext/mdp-select-dept)
部门选择,支持树状机构,异步加载,支持分页查询,任意大数据量
### [mdp-select-att](/src/components/mdp-ui-ext/mdp-select-att)
附件库,支持附件的上传下载、上传后的统一管理、共享
### 项目计划-任务
![项目计划-任务](/docs/images/xm-zs/xm-zs-8-jhrw.png)
### [mdp-select-cate](/src/components/mdp-ui-ext/mdp-select-cate)
文档、文章目录树选择器
### [mdp-select-tag](/src/components/mdp-ui-ext/mdp-select-tag)
标签库,支持标签的统一管理、共享
### 迭代概览
![迭代管理](/docs/images/xm-zs/xm-zs-9-ddgl.png)
### [mdp-meta-item](/src/components/mdp-ui-ext/[mdp-meta-item)
元数据管理库、支持元数据的crud
### 迭代维护
![项目立项](/docs/images/xm-zs/xm-zs-10-ddwh.png)
### [mdp-meta-option](/src/components/mdp-ui-ext/mdp-meta-option)
元数据管理库-列表数据组件、支持列表数据的crud
### [mdp-rich-text](/src/components/mdp-ui-ext/mdp-rich-text)
富文本编辑器整合了mdp-select-image作为插件
### 测试管理
![项目立项](/docs/images/xm-zs/xm-zs-11-csgl.png)
## 🔃 api
- [api](/src/api/)
业务api哪里用到哪里就单独引入
### [api/mdp_pub/index.js](/src/api/mdp_pub/index.js)
公共api总入口,注册到vue全局函数中可以在页面中任意地方直接使用,公共api总入口如需要添加公共api,请在此文件添加
### [mdp_api_base.js](/src/api/mdp_pub/mdp_api_base.js)
为mdp框架核心的与后端交互的api,自动注册为全局公共函数,可通过$mdp.xxx调用可改但不要新增删除任何一个api.
### [mdp_api_ext.js](/src/api/mdp_pub/mdp_api_ext.js)
为mdp扩展的组件与后端交互的api,自动注册为全局公共函数,可通过$mdp.xxx调用可改但不要新增删除任何一个api.
### [mdp_api_biz.js](/src/api/mdp_pub/mdp_api_biz.js)
为mdp扩展的组件与后端交互的api,自动注册为全局公共函数,可通过$mdp.xxx调用可改,可新增必要的api.
### [mdp_config.js](/src/api/mdp_pub/mdp_config.js)
前端工程的一些公共配置项主要配置每一类api对接哪个后端微服务
根据不同的环境需要修改部分内容。mdp_config配置项已与vue3工程公共配置打通vue3依赖于VIET_*的全局配置项因此vue3及更高版本之后应该以VITE的配置为准详细查阅 [env.d.ts](/types/env.d.ts)
### 测试报告
![项目立项](/docs/images/xm-zs/xm-zs-12-csbg.png)
```js
### 缺陷管理
![项目立项](/docs/images/xm-zs/xm-zs-13-qxgl.png)
# 固定网址
VITE_FIXED_DOMAIN=https://www.maimengcloud.com
### 财务费用
![项目立项](/docs/images/xm-zs/xm-zs-14-cwfy.png)
# 开源项目地址
VITE_OPEN_SOURCE_LINK=https://gitee.com/qingqinkj218/collections/375320
### 驾驶舱
![项目立项](/docs/images/xm-zs/xm-zs-15-jsc.png)
# 微信开放平台 appid
VITE_WXOPEN_APPID=wx2671d5db8346b6fc
### 效能分析
![项目立项](/docs/images/xm-zs/xm-zs-16-xnfx.png)
#
# 说明 VITE_CTX_# 为定义唛盟各个子系统的context;
# context指向子系统的微服务名称spring.application.name
#
# 1. 用于前端请求路径前缀映射
# 前端页面一般部署在 ./{VITE_CONTEXT}/{VITE_UI_VERSION?}
#
# 2. api导航到对应子系统等
# api一般按以下格式规范组装 ./{VITE_API_BASE_PATH}/{VITE_API_VERSION}/{VITE_CONTEXT}
#
### 燃尽图
![项目立项](/docs/images/xm-zs/xm-zs-17-rjt.png)
# 登录相关如果后端启用oauth2,则返回 oauth2client 如果后端不启用oauth2,后端账户使用mdp-lcode服务则返回 lcode ,如果使用mdp-sys提供服务则返回sys
VITE_CTX_LOGIN=oauth2client
### 每日工作项分布
![项目立项](/docs/images/xm-zs/xm-zs-18-gzxfb.png)
# 项目管理子系统
VITE_CTX_XM=xm
### 任务年龄分布
![项目立项](/docs/images/xm-zs/xm-zs-19-rwnlfb.png)
# 工作流子系统,由于flowable启动限制目前不支持jar集成到lcode需要单独部署
VITE_CTX_WF=workflow
### 任务排行棒
![项目立项](/docs/images/xm-zs/xm-zs-20-rwphb.png)
# 低代码子系统
VITE_CTX_LCODE=lcode
### 测试用例规划分析
![项目立项](/docs/images/xm-zs/xm-zs-21-csylghfx.png)
# 内容管理子系统
VITE_CTX_ARC=arc
## 客户端展示
### 小程序
![项目立项](/docs/images/xm-zs/xm-zs-22-xcx.png)
# 数据模型 由lcode接管
VITE_CTX_DM=lcode
### 审批管理
![项目立项](/docs/images/xm-zs/xm-zs-23-spgl.png)
# 协同办公
VITE_CTX_OA=oa
# 系统管理,目前由lcode接管
VITE_CTX_SYS=lcode
# 智能表单目前由lcode接管
VITE_CTX_FORM=lcode
# 商城-面向消费用户端
VITE_CTX_MALL=mall
# 商城管理端
VITE_CTX_MALLM=mallm
# 即时通讯
VITE_CTX_IM=im
# 短信
VITE_CTX_SMS=sms
# 唛盟内置的应用购买模块订单 目前由lcode接管
VITE_CTX_MO=lcode
# 众包 目前由xm接管
VITE_CTX_CROWD=xm
# 第三方集成系统
VITE_CTX_TPA=tpa
```
#### api的调用方法
```html
<el-button @click="$mdp.xxxApi()"/>
```
```js
//选项式
this.$mdp.xxxApi()
//组合式 由于没有this,需要在顶部引入proxy
const {proxy}: any = getCurrentInstance()
proxy.$mdp.xxxApi()
```
- [login](/src/api/login/index.ts.ts)
登录相关api
## 🔃 指令
- [v-adaptive](./src/components/mdp-ui/directive/adaptive.ts)
让表格、div等自动适应底部始终保持距离视窗底部一定距离(默认 30px)
```html
<el-table v-adaptive="{bottomOffset:30}"/>
<el-table v-adaptive/>
```
### 测试管理
![项目立项](/docs/images/xm-zs/xm-zs-24-csgl.png)
## 💻 样例项目
- [低代码平台] (https://maimengcloud.com/lcode/)
- [系统管理] (https://maimengcloud.com/sys)
- [低代码平台] (https://maimengcloud.com/lcode/)
- [协同办公] (https://maimengcloud.com/oa)
- [项目管理] (https://maimengcloud.com/xm)
- [流程管理] (https://maimengcloud.com/wf)
- [项目管理] (https://maimengcloud.com/xm)
## ⚙ 快速开始
@@ -649,14 +308,11 @@ pnpm install 包 // 安装依赖
### 前序准备
- 当前项目属于网页版前端ui项目后端代码请移步到 [mdp-lcode-backend](https://gitee.com/maimengcloud/mdp-lcode-backend)
- 代码生成器下载 [mdp-code-generator](https://gitee.com/maimengcloud/mdp-code-generator) 也可以在低代码平台在线生成
- 当前项目属于网页版前端ui项目后端代码请移步到 [xm-backend](https://gitee.com/maimengcloud/xm-backend)
### 开发
```bash
# 克隆项目
git clone https://gitee.com/maimengcloud/mdp-lcode-ui-web.git
git clone https://gitee.com/maimengcloud/xm-ui-web.git
# 安装依赖
pnpm install
@@ -664,7 +320,7 @@ pnpm install
# 启动服务
pnpm run dev
```
浏览器访问 http://localhost:8015
浏览器访问 http://localhost:8067
#### 登录相关
登录api对接后台接口有两种方式:
@@ -713,8 +369,16 @@ pnpm run dev
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^/api/m1/lcode`), '/'),
},
['/api/m1/xm']: {
target: 'http://localhost:7067',
ws: false,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^/api/m1/xm`), '/'),
},
```
上述代理实现把以/api/m1/lcode开头的请求地址(举例/api/m1/lcode/user/list)替换为/user/list,并转发到http://localhost:7014地址
上述代理实现把以/api/m1/lcode 开头的请求地址(举例/api/m1/lcode/user/list)替换为/user/list,并转发到http://localhost:7014地址
上述代理实现把以/api/m1/xm 开头的请求地址(举例/api/m1/xm/user/list)替换为/user/list,并转发到http://localhost:7067地址
2. 只启动前端页面工程,后端工程不启动,后端工程使用服务器上的已启动的服务
此种情况下前端如何把请求转发到服务上起的后端服务?主要修改[vite.config.js](vite.config.ts)中的代理实现
@@ -725,8 +389,14 @@ pnpm run dev
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^/api/m1/lcode`), '/'),
},
['/api/m1/xm']: {
target: '服务器上的ip:7067',
ws: false,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^/api/m1/xm`), '/'),
},
```
上述代理实现把以/api/m1/lcode开头的请求地址(举例/api/m1/lcode/user/list)替换为/user/list,并转发到http://服务器上的ip:7014地址
### 构建
@@ -740,11 +410,11 @@ pnpm run build:prod
### 发布
假设:
1. 应用服务器(sit1-backend),ip为192.168.0.222,端口7014
1. 应用服务器(sit1-backend),ip为192.168.0.222,端口7067
2. 静态资源服务器(sit1-static),ip为192.168.0.111
3. 反向代理使用nginx
4. 静态资源部署到服务器sit1-static的/data/nginx/html/lcode/下
5. 本地*ui-web目录在C:/Users/xxx/IdeaProjects/mdp-lcode-ui-web/
4. 静态资源部署到服务器sit1-static的/data/nginx/html/xm/下
5. 本地*ui-web目录在C:/Users/xxx/IdeaProjects/xm-ui-web/
#### 发布静态资源到测试\生产环境
@@ -759,7 +429,7 @@ rm -rf dist.rar
# 2.执行rz命令弹框选择本地dist文件上传到sit1-static服务器
rz
# 3.在弹出的目录选择器中进入C:\Users\xxx\IdeaProjects\mdp-lcode-ui-web\dist\目录下
# 3.在弹出的目录选择器中进入C:\Users\xxx\IdeaProjects\xm-ui-web\dist\目录下
全选所有文件->右键->添加到dist.rar->选中dist.rar->上传到服务器商/data/nginx/html/lcode/目录下
# 4.执行解压缩命令,至此静态资源发布完成
@@ -839,7 +509,7 @@ unrar x dist.rar
```
#### 发布后端服务
具体以[mdp-lcode-backend](https://gitee.com/maimengcloud/mdp-lcode-backend)中发布描述为准
具体以[xm-backend](https://gitee.com/maimengcloud/xm-backend)中发布描述为准
### 运维
#### 日志查询
@@ -881,10 +551,10 @@ consule 的默认控制台
http://ip:8500/
#### 有时候微服务需要人为干预进行下架
可以调用[/bin/service-deregister.sh](https://gitee.com/maimengcloud/mdp-lcode-backend/blob/master/bin/service-deregister.sh)进行
可以调用[/bin/service-deregister.sh](https://gitee.com/maimengcloud/xm-backend/blob/master/bin/service-deregister.sh)进行
#### 日志定时备份清理
可以在crontab中配置定时任务定时调用[bin/clear-log.sh](https://gitee.com/maimengcloud/mdp-lcode-backend/blob/master/bin/clear-log.sh)即可完成7天循环自动清理及备份日志
可以在crontab中配置定时任务定时调用[bin/clear-log.sh](https://gitee.com/maimengcloud/xm-backend/blob/master/bin/clear-log.sh)即可完成7天循环自动清理及备份日志
使用举例:
```bash
@@ -971,7 +641,7 @@ pnpm config set registry https://registry.npmmirror.com/
#### 数据库脚本在哪?
答复: 数据库脚本一般存放在后端工程下的sql/文件夹下
低代码的[mdp-lcode-backend/mdp-lcode/sql/lcode.sql](https://gitee.com/maimengcloud/mdp-lcode-backend/tree/master/mdp-lcode/sql)
低代码的[xm-backend/xm/sql/lcode.sql](https://gitee.com/maimengcloud/xm-backend/tree/master/xm/sql)
#### 数据库的编码是什么?
mysql的话建议character set: utf8mb4, collation: utf8mb4_croatian_ci
@@ -1102,13 +772,13 @@ VITE_MODULE_SCOPE=['模块编号1','模块编号2']
## 💯 实践案例
1. [低代码平台](https://maimengcloud.com/lcode)
1. [系统管理](https://maimengcloud.com/sys)
1. [系统管理](https://maimengcloud.com/lcode)
2. [协同办公](https://maimengcloud.com/oa)
3. [唛盟众包-网页](https://maimengcloud.com)
3. [项目管理-网页](https://maimengcloud.com/xm)
4. 项目管理-小程序
<img src="https://maimengcloud.com/img/77639c6907935d3b699f.png" alt="drawing" width="200"/>
5. [流程管理](https://maimengcloud.com/workflow/)
5. [流程管理](https://maimengcloud.com/lcode/)
### 项目分支说明

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

View File

@@ -105,6 +105,8 @@ export const editCategory = params => { return axios.post(`/${arcBase}/mdp/arc/
//新增一条档案类目
export const addCategory = params => { return axios.post(`/${arcBase}/mdp/arc/pub/category/add`, params); }
export const batchChangeParent= params => { return axios.post(`/${arcBase}/mdp/arc/pub/category/batchChangeParent`, params); }
//查询分类权限
export const listCategoryQx = params => { return axios.get(`/${arcBase}/mdp/arc/pub/categoryQx/list`, { params: params }); }

View File

@@ -65,6 +65,8 @@ addDept: params => { return axios.post(`/${sysBase}/mdp/sys/dept/add`, params )
editDept: params => { return axios.post(`/${sysBase}/mdp/sys/dept/edit`, params ); },
delDept: params => { return axios.post(`/${sysBase}/mdp/sys/dept/del`, params ); },
batchChangeDeptParent: params => { return axios.post(`/${sysBase}/mdp/sys/dept/batchChangeParent`, params ); },
/**
* 角色列表

View File

@@ -27,6 +27,10 @@ export const editXmFunc = params => { return axios.post(`${base}/xm/core/xmFunc/
//新增一条功能模块表
export const addXmFunc = params => { return axios.post(`${base}/xm/core/xmFunc/add`, params); };
//批量更新上级
export const batchChangeParent = params => { return axios.post(`${base}/xm/core/xmFunc/batchChangeParent`, params); };
//批量修改某些字段
export const editSomeFieldsXmFunc = params => { return axios.post(`${base}/xm/core/xmFunc/editSomeFields`, params); };

View File

@@ -1,37 +0,0 @@
import axios from '@/config/maxios'
import config from '@/api/mdp_pub/mdp_config'
let base = config.getXmCtx();
/**-------------------------与后端通讯接口------------------请写在下面-------------------------------------------- */
/**
* 项目人力成本预算
*1 默认只开放普通查询,所有查询,只要上传 分页参数 {pageNum:当前页码从1开始,pageSize:每页记录数,total:总记录【数如果是0后台会自动计算总记录数非0不会自动计算】},后台都会自动按分页查询 其它 api用到再打开没用到的api请注释掉
*2 查询、新增、修改的参数格式 params={id:'主键 主键',projectId:'项目编号',budgetAt:'预算金额',remark:'备注',subjectId:'预算科目',bizSdate:'费用归属周期开始日期',bizEdate:'费用归属周期结束日期',instId:'当前流程实例编号',bizFlowState:'当前流程状态0初始1审批中2审批通过3审批不通过4流程取消或者删除',costType:'成本类型0非人力1内部人力2外购人力',bizMonth:'费用归属月份yyyy-MM',subjectName:'科目名称',branchId:'项目归属企业编号'}
**/
//普通查询 条件之间and关系
export const listXmBudgetNlabor = params => { return axios.get(`${base}/xm/core/xmBudgetNlabor/list`, { params: params }); };
//删除一条项目人力成本预算 params={id:'主键 主键'}
export const delXmBudgetNlabor = params => { return axios.post(`${base}/xm/core/xmBudgetNlabor/del`,params); };
//批量删除项目人力成本预算 params=[{id:'主键 主键'}]
export const batchDelXmBudgetNlabor = params => { return axios.post(`${base}/xm/core/xmBudgetNlabor/batchDel`, params); };
//批量新增项目人力成本预算 params=[{id:'主键 主键'}]
export const batchAddXmBudgetNlabor = params => { return axios.post(`${base}/xm/core/xmBudgetNlabor/batchAdd`, params); };
//修改一条项目人力成本预算记录
export const editXmBudgetNlabor = params => { return axios.post(`${base}/xm/core/xmBudgetNlabor/edit`, params); };
//新增一条项目人力成本预算
export const addXmBudgetNlabor = params => { return axios.post(`${base}/xm/core/xmBudgetNlabor/add`, params); };
//批量修改某些字段
export const editSomeFieldsXmBudgetNlabor = params => { return axios.post(`${base}/xm/core/xmBudgetNlabor/editSomeFields`, params); };
export const listSumXmBudgetNlabor = params => { return axios.get(`${base}/xm/core/xmBudgetNlabor/listSum`, { params: params }); };

View File

@@ -13,25 +13,26 @@ let base = config.getXmCtx();
**/
//普通查询 条件之间and关系
export const listXmBudgetLabor = params => { return axios.get(`${base}/xm/core/xmBudgetLabor/list`, { params: params }); };
export const listXmBudgetRecord = params => { return axios.get(`${base}/xm/core/xmBudgetRecord/list`, { params: params }); };
//删除一条项目人力成本预算 params={id:'主键 主键'}
export const delXmBudgetLabor = params => { return axios.post(`${base}/xm/core/xmBudgetLabor/del`,params); };
export const delXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/del`,params); };
//批量删除项目人力成本预算 params=[{id:'主键 主键'}]
export const batchDelXmBudgetLabor = params => { return axios.post(`${base}/xm/core/xmBudgetLabor/batchDel`, params); };
export const batchDelXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/batchDel`, params); };
//批量新增项目人力成本预算 params=[{id:'主键 主键'}]
export const batchAddXmBudgetLabor = params => { return axios.post(`${base}/xm/core/xmBudgetLabor/batchAdd`, params); };
export const batchAddXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/batchAdd`, params); };
//修改一条项目人力成本预算记录
export const editXmBudgetLabor = params => { return axios.post(`${base}/xm/core/xmBudgetLabor/edit`, params); };
export const editXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/edit`, params); };
//新增一条项目人力成本预算
export const addXmBudgetLabor = params => { return axios.post(`${base}/xm/core/xmBudgetLabor/add`, params); };
export const addXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/add`, params); };
//批量修改某些字段
export const editSomeFieldsXmBudgetLabor = params => { return axios.post(`${base}/xm/core/xmBudgetLabor/editSomeFields`, params); };
export const editSomeFieldsXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/editSomeFields`, params); };
export const listSumXmBudgetLabor = params => { return axios.get(`${base}/xm/core/xmBudgetLabor/listSum`, { params: params }); };
export const listSumXmBudgetRecord = params => { return axios.get(`${base}/xm/core/xmBudgetRecord/listSum`, { params: params }); };
//拆分一条项目人力成本预算
export const splitXmBudgetRecord = params => { return axios.post(`${base}/xm/core/xmBudgetRecord/split`, params); };

View File

@@ -13,23 +13,23 @@ let base = config.getXmCtx();
**/
//普通查询 条件之间and关系
export const listXmCostNlabor = params => { return axios.get(`${base}/xm/core/xmCostNlabor/list`, { params: params }); };
export const listXmCostRecord = params => { return axios.get(`${base}/xm/core/xmCostRecord/list`, { params: params }); };
//删除一条项目实际人工成本费用 params={id:'主键 主键'}
export const delXmCostNlabor = params => { return axios.post(`${base}/xm/core/xmCostNlabor/del`,params); };
export const delXmCostRecord = params => { return axios.post(`${base}/xm/core/xmCostRecord/del`,params); };
//批量删除项目实际人工成本费用 params=[{id:'主键 主键'}]
export const batchDelXmCostNlabor = params => { return axios.post(`${base}/xm/core/xmCostNlabor/batchDel`, params); };
export const batchDelXmCostRecord = params => { return axios.post(`${base}/xm/core/xmCostRecord/batchDel`, params); };
//修改一条项目实际人工成本费用记录
export const editXmCostNlabor = params => { return axios.post(`${base}/xm/core/xmCostNlabor/edit`, params); };
export const editXmCostRecord = params => { return axios.post(`${base}/xm/core/xmCostRecord/edit`, params); };
//新增一条项目实际人工成本费用
export const addXmCostNlabor = params => { return axios.post(`${base}/xm/core/xmCostNlabor/add`, params); };
export const addXmCostRecord = params => { return axios.post(`${base}/xm/core/xmCostRecord/add`, params); };
//批量修改某些字段
export const editSomeFieldsXmCostNlabor = params => { return axios.post(`${base}/xm/core/xmCostNlabor/editSomeFields`, params); };
export const editSomeFieldsXmCostRecord = params => { return axios.post(`${base}/xm/core/xmCostRecord/editSomeFields`, params); };
//普通查询 条件之间and关系
export const listSumXmCostNlabor = params => { return axios.get(`${base}/xm/core/xmCostNlabor/listSum`, { params: params }); };
export const listSumXmCostRecord = params => { return axios.get(`${base}/xm/core/xmCostRecord/listSum`, { params: params }); };

View File

@@ -15,7 +15,8 @@ import MdpFormData from './mdp-expand/FormData.vue'
import MdpFormExpand from './mdp-expand/FormExpand.vue'
import MdpColumnExpand from './mdp-expand/ColumnExpand.vue'
import MdpFuncMenu from './mdp-func-menu/Index.vue'
import MdpFocus from './mdp-focus/Index.vue'
import MdpFocus from './mdp-focus/Index.vue'
import MdpSelectBranch from './mdp-select-branch/Index.vue'
const compLists = {
install: function(Vue) {
@@ -38,6 +39,7 @@ const compLists = {
Vue.component('MdpColumnExpand', MdpColumnExpand)
Vue.component('MdpFuncMenu',MdpFuncMenu)
Vue.component('MdpFocus',MdpFocus)
Vue.component('MdpSelectBranch',MdpSelectBranch)
}
}
export default compLists

View File

@@ -1,235 +1,178 @@
<template>
<el-card>
<template #header>
<el-space wrap>
<mdp-select style="width:100%" :disabled="categoryType" v-model="filters.categoryType" item-code="categoryType" placeholder="请选择主题" clearable @change="onCategoryTypeChange"/>
<el-button icon="plus" type="primary" plain @click.prevent.stop="addTopNode()" title="添加顶级分类,在分类上右键可以添加子分类"/>
<el-button v-if="showConfirm" type="warning" @click="confirm" title="确认选择" icon="check"/>
<el-input v-model="filters.key" placeholder="名称"/>
</el-space>
</template>
<el-tree accordion v-if="show"
:props="defaultTreeProps"
:filter-node-method="filterNode"
:show-checkbox="showCheckbox"
:default-expand-all="defaultExpandAll"
:expand-on-click-node="expandOnClickNode"
:node-key="nodeKey_"
:default-expanded-keys="defaultExpandedKeys"
:default-checked-keys="defaultCheckedKeys"
auto-expand-parent
@check-change="handleCheckChange"
@current-change="handleCurrentChange"
@node-click="handleNodeClick"
:check-strictly="true"
:check-on-click-node="true"
lazy
:load="loadNode"
ref="nodeTree" @contextmenu.prevent>
<template #default="{ node, data}">
<div class="custom-tree-node" @contextmenu.prevent title="右键可以增删改">
<el-popover
:open-delay="1000"
placement="top-start"
:width="showConfirm?300:200"
trigger="contextmenu" >
<el-button icon="plus" circle type="success" v-if=" !(!data.id || data.id=='C0'||data.id=='0')" @click.prevent.stop="addNode(data,node)" title="添加子分类"/>
<el-button icon="edit" circle type="warning" v-if=" !(!data.id || data.id=='C0'||data.id=='0')" @click.prevent.stop="editNode(data,node)" title="修改名字"/>
<el-button icon="delete" circle type="danger" v-if=" !(!data.id || data.id=='C0'||data.id=='0')" @click.prevent.stop="deleteNode(data,node)" title="删除该分类"/>
<template>
<MdpTree
ref="nodeTree"
title="功能模块"
showCheckbox
:props="propsCpd"
:load="listCategory"
:del="delCategory"
:batchDel="batchDelCategory"
:multiple="multiple"
:showConfirm="showConfirm"
:hidden="hiddenCpd"
@addTopNode="(cb) => onAddTopClick(cb)"
@editNode="(d, cb, subcb) => onEditClick(d, cb, subcb)"
@addSubNode="(p, cb) => onAddSubClick(p, cb)"
@changePid="(cks,cb) => onChangePidClick(cks,cb)"
@confirm = "(d)=>{$emit('confirm',d);$emit('select',d)}"
@check-change="(d,c,i)=>$emit('check-change',d,c,i)"
@node-click="(d,n,c)=>$emit('node-click',d,n,c)"
rootId="C0"
:draggable="true"
>
<template #topToolbar>
<mdp-select width="250px" :disabled="categoryType" v-model="filters.categoryType" item-code="categoryType" placeholder="主题" clearable @change="onCategoryTypeChange"/>
</template>
<template #nodeName="{ data }">
<el-space>
<div><Icon v-if="data.imageUrls" :icon="data.imageUrls"/>{{data.name}}</div>
</el-space>
</template>
<template #nodeToolbar="{data}">
<el-button type="primary" v-if="data.qxLvl=='2'" @click="$refs['qxSetDialog'].open({category:data})">配置限制规则</el-button>
</template>
</MdpTree>
<template #reference><div style="display:flex;align-items:center;width:100%;"><Icon v-if="data.imageUrls" :icon="data.imageUrls"/>{{data.name}}</div></template>
</el-popover>
</div>
</template>
</el-tree>
</el-card>
<el-dialog
title="新增分类"
v-model="addVisible"
width="60%" append-to-body>
<el-form ref="addCategory" :model="addCategory" label-width="200" >
<!--编辑 Category xm_project_func界面-->
<mdp-dialog ref="editDialog" width="30%" append-to-body :close-on-click-modal="false">
<template #default="{ data,dialog }">
<el-form ref="editForm" :model="editForm" label-width="150" >
<el-form-item label="主题" prop="categoryType" :rules="[
{ required: true, message: '主题不能为空'}
]">
<mdp-select v-model="addCategory.categoryType" :disabled="currentCategory?.categoryType" item-code="categoryType" placeholder="请选择主题"/>
<mdp-select width="100%" v-model="editForm.categoryType" item-code="categoryType" placeholder="请选择主题" :disabled="data.formData.categoryType"/>
</el-form-item>
<el-form-item label="分类编号" prop="id" :rules="[
{ required: true, message: '不能为空'}
]">
{{editForm.id}}
</el-form-item>
<el-form-item label="分类名称" prop="name"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="editForm.name" />
</el-form-item>
<el-form-item label="图标" >
<IconSelect v-model="editForm.imageUrls"/>
</el-form-item>
<el-form-item label="配置" >
<el-checkbox v-model="editForm.isLeaf" auto-complete="off" true-label="0" false-label="1">是否可添加子分类</el-checkbox>
<el-checkbox v-model="editForm.limitType" auto-complete="off" true-label="1" false-label="2">文章数目是否限制为1篇</el-checkbox>
<el-checkbox v-model="editForm.isAuth" auto-complete="off" true-label="1" false-label="0">文章发布是否需要审核</el-checkbox>
</el-form-item>
<el-form-item label="权限" >
<el-radio v-model="editForm.qxLvl" auto-complete="off" label="0">全网公开</el-radio>
<el-radio v-model="editForm.qxLvl" auto-complete="off" label="1">内部公开</el-radio>
<el-radio v-model="editForm.qxLvl" auto-complete="off" label="2">受限</el-radio>
<el-button type="primary" v-if="editForm.qxLvl=='2'" @click="$refs['qxSetDialog'].open({category:editCategory})">配置限制规则</el-button>
<el-checkbox v-model="editForm.pqx" auto-complete="off" true-label="1" false-label="0">所有子类遵守上级权限规则</el-checkbox>
</el-form-item>
</el-form>
<div class="footer">
<el-button @click="dialog.close()">关 闭</el-button>
<el-button type="primary" v-loading="loading.edit" @click="editSubmit(data.callback)">确 定</el-button>
</div>
</template>
</mdp-dialog>
<!--新增 Category xm_project_func界面-->
<mdp-dialog ref="addDialog" width="30%" append-to-body :close-on-click-modal="false">
<template #default="{ data, dialog }">
<el-form ref="addForm" :model="addForm" label-width="150" >
<el-form-item label="主题" prop="categoryType" :rules="[
{ required: true, message: '主题不能为空'}
]">
<mdp-select width="100%" v-model="addForm.categoryType" :disabled="data.parent && data.parent.categoryType" item-code="categoryType" placeholder="请选择主题"/>
</el-form-item>
<el-form-item label="上级分类">
<el-tag>{{ currentCategory && currentCategory.id && currentCategory.id!='C0'? "上级:"+currentCategory.name:"顶级分类C0" }}</el-tag>
<el-tag>{{ data.parent && data.parent.id && data.parent.id!='C0'? "上级"+data.parent.name:"顶级分类C0" }}</el-tag>
</el-form-item>
<el-form-item label="分类编号">
<el-input v-model="addCategory.id" placeholder="如果为空,则系统自动生成"/>
<el-form-item label="分类编号" prop="id" :rules="[
{ required: true, message: '不能为空'}
]">
<el-input v-model="addForm.id" placeholder="如果为空则系统自动生成"/>
</el-form-item>
<el-form-item label="分类名称" prop="name"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="addCategory.name" />
<el-input v-model="addForm.name" />
</el-form-item>
<el-form-item label="图标" >
<IconSelect v-model="addCategory.imageUrls"/>
<IconSelect v-model="addForm.imageUrls"/>
</el-form-item>
<el-form-item label="配置" prop="name">
<el-checkbox v-model="addCategory.isLeaf" auto-complete="off" true-label="0" false-label="1">是否可添加子分类</el-checkbox>
<el-checkbox v-model="addForm.isLeaf" auto-complete="off" true-label="0" false-label="1">是否可添加子分类</el-checkbox>
<el-checkbox v-model="addCategory.limitType" auto-complete="off" true-label="1" false-label="2">文章数目是否限制为1篇</el-checkbox>
<el-checkbox v-model="addForm.limitType" auto-complete="off" true-label="1" false-label="2">文章数目是否限制为1篇</el-checkbox>
<el-checkbox v-model="addCategory.isAuth" auto-complete="off" true-label="1" false-label="0">文章发布是否需要审核</el-checkbox>
<el-checkbox v-model="addForm.isAuth" auto-complete="off" true-label="1" false-label="0">文章发布是否需要审核</el-checkbox>
</el-form-item>
<el-form-item label="权限" >
<el-radio v-model="addCategory.qxLvl" auto-complete="off" label="0">全网公开</el-radio>
<el-radio v-model="addCategory.qxLvl" auto-complete="off" label="1">内部公开</el-radio>
<el-radio v-model="addCategory.qxLvl" auto-complete="off" label="2">受限</el-radio>
<el-checkbox v-model="addCategory.pqx" auto-complete="off" true-label="1" false-label="0">所有子类遵守上级权限规则</el-checkbox>
<el-radio v-model="addForm.qxLvl" auto-complete="off" label="0">全网公开</el-radio>
<el-radio v-model="addForm.qxLvl" auto-complete="off" label="1">内部公开</el-radio>
<el-radio v-model="addForm.qxLvl" auto-complete="off" label="2">受限</el-radio>
<el-checkbox v-model="addForm.pqx" auto-complete="off" true-label="1" false-label="0">所有子类遵守上级权限规则</el-checkbox>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="addVisible = false">关闭</el-button>
<el-button type="primary" v-loading="addLoading" @click="addCategorySubmit"> </el-button>
<div class="footer">
<el-button @click="dialog.close()">关闭</el-button>
<el-button type="primary" v-loading="loading.add" @click="addSubmit(data.parent,data.callback)">确 定</el-button>
</div>
</template>
</el-dialog>
<el-dialog
title="修改分类提示"
v-model="editVisible"
width="60%" append-to-body>
<el-form ref="editCategory" :model="editCategory" label-width="200" >
<el-form-item label="主题" prop="categoryType" :rules="[
{ required: true, message: '主题不能为空'}
]">
<mdp-select v-model="editCategory.categoryType" item-code="categoryType" placeholder="请选择主题" :disabled="editCategory.categoryType"/>
</el-form-item>
<el-form-item label="分类编号" prop="id">
{{editCategory.id}}
</el-form-item>
<el-form-item label="分类名称" prop="name"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="editCategory.name" />
</el-form-item>
<el-form-item label="图标" >
<IconSelect v-model="editCategory.imageUrls"/>
</el-form-item>
<el-form-item label="配置" >
<el-checkbox v-model="editCategory.isLeaf" auto-complete="off" true-label="0" false-label="1">是否可添加子分类</el-checkbox>
<el-checkbox v-model="editCategory.limitType" auto-complete="off" true-label="1" false-label="2">文章数目是否限制为1篇</el-checkbox>
<el-checkbox v-model="editCategory.isAuth" auto-complete="off" true-label="1" false-label="0">文章发布是否需要审核</el-checkbox>
</el-form-item>
<el-form-item label="权限" >
<el-radio v-model="editCategory.qxLvl" auto-complete="off" label="0">全网公开</el-radio>
<el-radio v-model="editCategory.qxLvl" auto-complete="off" label="1">内部公开</el-radio>
<el-radio v-model="editCategory.qxLvl" auto-complete="off" label="2">受限</el-radio>
<el-button type="primary" v-if="editCategory.qxLvl=='2'" @click="$refs['qxSetDialog'].open({category:editCategory})">配置限制规则</el-button>
<el-checkbox v-model="editCategory.pqx" auto-complete="off" true-label="1" false-label="0">所有子类遵守上级权限规则</el-checkbox>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="editVisible = false"> </el-button>
<el-button type="primary" v-loading="editLoading" @click="editCategorySubmit"> </el-button>
</template>
</el-dialog>
<mdp-dialog ref="qxSetDialog">
</mdp-dialog>
<mdp-dialog ref="qxSetDialog">
<template #default="{visible,data,dialog}">
<category-qx-set :visible="visible" :category="data.category" @close="dialog.close()" @submit="dialog.close()"/>
</template>
</mdp-dialog>
</template>
<script>
<script>
import util from '@/components/mdp-ui/js/util' //全局公共库
import CategoryQxSet from './QxSet.vue';
import {
addCategory,
editCategory,
delCategory,
batchDelCategory,
listCategory,
batchChangeParent,
} from '@/api/mdp_pub/larc'
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import CategoryQxSet from './QxSet.vue';
export default {
components:{
CategoryQxSet
},
watch: {
nodeFilterText(val) {
this.$refs.nodeTree.filter(val);
},
checkedKeys(val){
this.$refs.nodeTree.setCheckedKeys(val);
},
refresh(val){
},
currentKey(val){
this.$refs.nodeTree.setCheckedKeys([val]);
},
value(val){
this.nodeid=val;
},
nodeid(val){
this.$emit('input',val);
},
categoryType(val){
//this.$refs.nodeTree.filter(this.filters.categoryType)
},
'filters.categoryType'(){
this.getTreeData();
},
'filters.key'(v){
this.$refs.nodeTree.filter(v)
}
},
computed:{
categoryTreeData() {
return []
},
defaultExpandedKeys(){
return this.defaultCheckedKeys;
},
defaultCheckedKeys(){
if(this.value){
return [this.value];
}
return this.checkedKeys;
},
nodeKey_(){
return this.nodeKey?this.nodeKey:'id'
},
...mapState(useUserStore,[
'userInfo'
]),
},
props:{
'value':String,Array,
'branchId':String,
'visible':{type:Boolean,default:false},
'showCount':{type:Boolean,default:false},
'showRoot':{type:Boolean,default:false},
'countTips':String,
'showFilter':{type:Boolean,default:false},
'multiple':{type:Boolean,default:false},
'checkedKeys':Array,
'refresh':{type:Boolean,default:false},
'defaultExpandAll':{type:Boolean,default:false},
'expandOnClickNode':{type:Boolean,default:false},
showCheckbox:{type:Boolean,default:false},
showConfirm:{type:Boolean,default:false},
'indent':Number,
categoryType:{type:String,default:null},
nodeKey:String,
export default {
props: {
'subOpType':{type:String,defalut:'mng'},
'multiple':{type:Boolean,default:false},
'showConfirm':{type:Boolean,default:false},
'hidden':{type:Object,default:()=>null},
'params':{type:Object,default:()=>null},
'clearable':{type:Boolean,default:true},
categoryType:{//主题
type:String,
default:null
},
/**
* 上级分类
*/
pid:{
pid:{
type:String,
default:''
},
@@ -250,362 +193,181 @@ import CategoryQxSet from './QxSet.vue';
default:''
}
},
data() {
return {
filters:{
categoryType:'',
computed: {
...mapState(useUserStore, ['userInfo', 'roles']),
hiddenCpd(){
var isSelect=this.subOpType=='select'
var hidden ={
batchDel: isSelect,
del:isSelect,
changePid: false,
addTop: isSelect,
addSub: isSelect,
edit: isSelect,
filter: false,
page: true,
}
hidden=Object.assign(hidden,this.hidden)
return hidden
},
nodeFilterText: '',
treeData:[],
defaultTreeProps:{
id:this.nodeKey==null?'id':this.nodeKey,
label:'name',
children: 'children',
isLeaf: function(n){
return n.childNum<=0
}
},
listLoading: false,
addLoading:false,
editLoading:false,
nodeid:'',
currentCategory:{id:'',pid:'',name:'',categoryType:null},
addCategory:{id:'',pid:'',name:'',isLeaf:'0',isAuth:'0',limitType:'2',categoryType:'',pqx:'',qxLvl:''},
editCategory:{id:'',pid:'',name:'',isLeaf:'0',isAuth:'0',limitType:'2',categoryType:'',pqx:'',qxLvl:''},
addVisible:false,
editVisible:false,
options:{categoryType:[]},
root:{},
isAddTop:false,
resolve:null,
show:true,
}
},
methods: {
onCategoryTypeChange(v){
this.getTreeData()
propsCpd(){
return { id: 'id', pid: 'pid', label: 'name' , isLeaf:(data,n)=>{
return data.childNum<=0
}}
}
},
data() {
return {
filters: {
categoryType: ''
},
unselect(){
this.$refs['nodeTree'].setCurrentKey(null)
},
handleCheckChange(data, checked, indeterminate) {
let checkedKeys=this.$refs.nodeTree.getCheckedKeys();
console.log(this.multiple);
if( this.multiple===undefined || this.multiple===false||this.multiple==='false'){
if(checked==true){
if(checkedKeys.length>1){
this.$refs.nodeTree.setCheckedKeys([data[this.nodeKey_]]);
this.$emit('check-change',data,checked,indeterminate);
this.nodeid=data[this.nodeKey_];
}else{
this.$emit('check-change',data,checked,indeterminate);
this.nodeid=data[this.nodeKey_];
}
}else{
if(checkedKeys.length==0){
this.nodeid='';
this.$emit('check-change',data,checked,indeterminate);
addForm:{id:'',pid:'',name:'',isLeaf:'0',isAuth:'0',limitType:'2',categoryType:'',pqx:'',qxLvl:''},
editForm:{id:'',pid:'',name:'',isLeaf:'0',isAuth:'0',limitType:'2',categoryType:'',pqx:'',qxLvl:''},
loading:{add:false,edit:false,list:false}
}
}, //end data
methods: {
listCategory(params, node) {
Object.assign(params,this.filters)
if(this.params){
Object.assign(params,this.params)
}
return listCategory(params)
},
delCategory,
batchDelCategory,
//显示编辑界面 Category xm_project_func
onEditClick: function (formData, callback, addSubCallback) {
this.editForm={...formData}
this.$refs['editDialog'].open({
formData: formData,
callback: callback,
addSubCallback: addSubCallback
})
},
//显示新增界面 Category xm_project_func
onAddTopClick: function (callback) {
var formData = {}
if (!this.initExtParams(formData)) {
return
}
this.$refs['addDialog'].open({
formData: formData,
parent: null,
callback: callback
})
},
initExtParams(formData, parent) {
if(this.categoryType){
formData.categoryType=this.categoryType
}
return true
},
onAddSubClick: function (parent, callback) {
var formData = {}
if (!this.initExtParams(formData, parent)) {
return
}
Object.assign(formData,parent)
formData.pid=parent.id
formData.id=null
this.addForm={...formData}
this.$refs['addDialog'].open({
formData: formData,
parent: parent,
callback: callback
})
},
onChangePidClick: function(idLinks,callback){
batchChangeParent(idLinks).then(res=>{
let {tips}=res
if(tips.isOk){
if(callback){
callback(true)
}
this.$message.success(tips.msg)
}else{
this.$message.error(tips.msg)
}
}else{
this.$emit('check-change',data,checked,indeterminate);
}
},
handleCurrentChange(data, node) {
this.$emit('current-change',data, node);
},
handleNodeClick(data, node, comp) {
this.$emit('node-click',data, node, comp);
},
handleAddCategoryClose(){
this.addVisible=false;
},
addCategorySubmit(){
var branchId=this.userInfo.branchId
var pid=""
if(this.isAddTop){
pid="C0"
}else{
pid=this.currentCategory.id
branchId=this.currentCategory.branchId
}
this.addCategory.pid=pid
this.addCategory.isShow='1'
this.addCategory.branchId=branchId
})
},
onCategoryTypeChange(ctype){
this.$refs.nodeTree.refresh()
},
addSubmit(parent,callback){
var branchId=this.userInfo.branchId
this.addForm.branchId=branchId
if(this.crelyType){
this.addCategory.crelyType=this.crelyType
this.addForm.crelyType=this.crelyType
}
if(this.crelyId){
this.addCategory.crelyId=this.crelyId
this.addForm.crelyId=this.crelyId
}
if(this.crelyStype){
this.addCategory.crelyStype=this.crelyStype
this.addForm.crelyStype=this.crelyStype
}
if(this.crelySid){
this.addCategory.crelySid=this.crelySid
this.addForm.crelySid=this.crelySid
}
this.$refs.addCategory.validate((valid) => {
if(this.filters.categoryType){
this.addForm.categoryType=this.filters.categoryType
}
if(this.categoryType){
this.addForm.categoryType=this.categoryType
}
this.$refs.addForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.addLoading = true;
this.$mdp.addCategory(this.addCategory).then(res=>{
this.addLoading=false;
if(res.tips.isOk){
this.$message.success(res.tips.msg);
if(!this.isAddTop){
if(this.currentCategory.children){
this.currentCategory.children.push(res.data)
}else{
this.currentCategory.children=[res.data]
}
}else{
this.$refs['nodeTree'].append(res.data,this.root)
}
this.addVisible=false;
this.loading.add = true;
addCategory(this.addForm).then(res=>{
this.loading.add=false;
if(res.tips.isOk){
this.$message.success(res.tips.msg);
this.$refs.addDialog.close()
callback(res.data)
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.addLoading = false );
}).catch(e=>this.loading.add = false );
});
}
});
},
editCategorySubmit(){
this.$refs.editCategory.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.editLoading = true;
this.$mdp.editCategory(this.editCategory).then(res=>{
//console.log("res--"+JSON.stringify(res));
this.editLoading = false;
if(res.tips.isOk){
this.editVisible=false;
this.$message.success(res.tips.msg);
this.$refs['nodeTree'].updateKeyChildren(res.data.id,res.data)
this.editVisible=false
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.editLoading = false );
});
}
});
},
addTopNode(){
this.isAddTop=true
this.addVisible=true;
this.addCategory.categoryType=this.categoryType||null
return false;
},
addNode(data, node, comp) {
this.isAddTop=false
this.currentCategory=data
this.addVisible=true;
this.addCategory.categoryType=this.currentCategory?.categoryType||null
return false;
},
editNode(data, node, comp) {
this.editCategory=data
this.editVisible=true;
console.log("editNode__"+JSON.stringify(data));
return false;
},
deleteNode(data, node, comp) {
console.log("deleteNode__"+JSON.stringify(data));
if(data.children){
this.$message.error("请先删除子元素");
return;
}
let params={
id:data.id,
branchId:data.branchId
}
if(!params.branchId){
params.branchId=this.userInfo.branchId
}
this.$confirm('确认删除吗?', '提示', {}).then(() => {
this.$mdp.delCategory(params).then(res=>{
//console.log("res--"+JSON.stringify(res));
if(res.tips.isOk){
this.editVisible=false;
this.$refs['nodeTree'].remove(data)
this.$message.success(res.tips.msg);
}else{
this.$message.error(res.tips.msg);
}
});
})
return false;
},
//获取分类树列表
getTreeData(refresh) {
this.show=false
this.$nextTick(()=>{
this.show=true
})
},
refreshNode(guid) {
let node = this.$refs.nodeTree.getNode(guid)
if (node && node.loaded) {
node.loaded = false
node.expand() // 主动调用展开节点方法,重新查询该节点下的所有子节点
}
},
filterNode(value, data) {
if (!value) return true;
return data.name.includes(value);
},
renderContent(h, { node, data, store }) {
var countMsg='';
if(this.countTips){
countMsg=this.countTips;
}
if(this.showCount==true || this.showCount=='true'){
return h('div'[h('span',node.label+"("+data.count+countMsg+")")]) ;
}else{
return h('div',[h('span',node.label+"("+data.count+countMsg+")")]) ;
//return h('span',"@contextmenu.prevent='contextmenu('"+node.id+"')',"+node.label+"("+(data.children==null?0:data.children.length)+countMsg+")") ;
}
},
confirm(){
var nodes= this.$refs.nodeTree.getCheckedNodes(false,false)
if(this.multiple){
this.$emit('confirm',nodes)
}else{
this.$emit('confirm',nodes&&nodes.length>0?nodes[0]:null)
}
},
setNodeData(data){
if(!data){
return;
}
if(data.imageUrls){
return;
}
data.imageUrls=data.childNum>0?'fa-solid:folder':'fa:file-o'
},
loadNode(node, resolve) {
if (node.level === 0) {
this.root=node
this.resolve=resolve
let params = {
'pid':'C0'
};
if(this.categoryType){
params.categoryType=this.categoryType
}
if(this.filters.categoryType){
params.categoryType=this.filters.categoryType
}
this.listLoading = true;
this.$mdp.listCategory(params).then((res) => {
var tips=res.tips;
var data=res.data;
this.listLoading = false;
this.expandRowKeys=data.map(i=>i.deptid)
data.forEach(k=>this.setNodeData(k))
resolve(data )
}).catch(() => {
this.listLoading = false;
});
}else {
setTimeout(() => {
let params = {
pid:node.data.id
};
this.listLoading = true;
this.$mdp.listCategory(params).then((res) => {
var tips=res.tips;
var data=res.data;
this.listLoading = false;
data.forEach(k=>this.setNodeData(k))
resolve(data)
}).catch(() => {
this.listLoading = false;
});
}, 500);
}
}
},
mounted() {
this.nodeid=this.value;
}
}
editSubmit(callback){
this.$refs.editForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.loading.edit = true;
editCategory(this.editForm).then(res=>{
if(res.tips.isOk){
this.loading.edit = false
this.$refs.editDialog.close();
this.$message.success(res.tips.msg);
callback(this.editForm)
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.loading.edit = false );
});
}
});
}
}, //end methods
components: { CategoryQxSet
},
mounted() {
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: #4386c6;
}
.el-ic {
display: none;
i, span {
padding: 0 1px;
font-size: 18px;
font-weight: 600;
}
}
.el-tree-node__content:hover .el-ic {
color: #428bca !important;
display: inline-block;
margin-left: 2px;
z-index: 10000;
}
.el-tree-node__content:hover {
font-weight: bold;
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content :hover {
.el-tree-node__expand-icon.is-leaf {
color: transparent;
cursor: default;
}
/*background-color: #3998d9;*/
.custom-tree-node {
font-weight: bold;
}
.el-tree-node__expand-icon {
font-weight: bold;
}
}
</style>
<style lang="scss" />

View File

@@ -0,0 +1,96 @@
<template>
<MdpSelectTable :relative="relative" :initName="initName" :initLoad="initLoad" :label="label" :width="width" :placeholder="placeholder" :show-style="showStyle" ref="select" v-model="myVal" :loadFun="$mdp.listBranch" :props="{id:'id',name:'branchName'}" @change2="(e)=>$emit('change2',e)" @change="(e)=>$emit('change',e)" :multiple="multiple" :split="split" :disabled="disabled" />
</template>
<script>
export default {
computed:{
myVal:{
set(val){
this.$emit('update:modelValue',val)
},
get(){
return this.modelValue
}
}
},
name: 'MdpSelectBranch',
props:{
modelValue:{
type: String,Array,
default: null
},
multiple:{
type: Boolean,
default: false
},
showStyle:{
type:String,
default:'origin'
},
label:{
type:String,
default: '机构'
},
placeholder:{
type:String,
default: '机构'
},
disabled:{
type: Boolean,
default:false
},
width:{
type: String,
default: null
},
split:{
type: String,
default:null,
},
/**
* 当tag 模式下,定位出问题后,设置此参数可解决问题
*/
relative:{
type: Boolean,
default: false
},
/**
* 初始化时,如果已知名称,用此属性可以反显
*/
initName:{
type: [String,Array],
default: null
},
/**
* 初始化时initLoad=true将进行远程调用否则不进行远程调用
*/
initLoad:{
type: Boolean,
default: false
}
},
data(){
return {
}
},
methods:{
onTableDataSelect(datas){
this.$refs['select'].onTableDataSelect(datas)
this.$refs['tableDialog'].close();
},
onTableLoadDatas(res){
this.$refs['select'].onTableLoadDatas(res)
}
},
mounted(){
},
}
</script>
<style lang="scss" scoped>
@import '../../mdp-ui/index.scss';
</style>

View File

@@ -1,387 +1,291 @@
<template>
<el-card>
<template #header>
<el-space wrap>
<el-input style="width:100%;" v-model="deptFilterText" placeholder="编号、名称过滤" auto-complete="off" />
<el-button type="primary" @click="addTopNode" icon="plus" title="添加一级部门" />
<el-button v-if="showConfirm" type="warning" @click="confirm" icon="check" title="确认选择" />
<MdpTree
ref="nodeTree"
title="部门"
showCheckbox
:props="propsCpd"
:load="listDept"
:del="delDept"
:multiple="multiple"
:showConfirm="showConfirm"
:hidden="hiddenCpd"
@addTopNode="(cb) => onAddTopClick(cb)"
@editNode="(d, cb, subcb) => onEditClick(d, cb, subcb)"
@addSubNode="(p, cb) => onAddSubClick(p, cb)"
@changePid="(cks,cb) => onChangePidClick(cks,cb)"
@confirm = "(d)=>{$emit('confirm',d);$emit('select',d)}"
@check-change="(d,c,i)=>$emit('check-change',d,c,i)"
@node-click="(d,n,c)=>$emit('node-click',d,n,c)"
rootId="A0"
:draggable="true"
>
<template #nodeName="{ data }">
<el-space>
<div><Icon v-if="data.icon" :icon="data.icon"/>{{data.deptName}}</div>
</el-space>
</template>
<el-tree v-if="treeVisible" v-loading="listLoading" :props="defaultDeptTreeProps" :filter-node-method="filterDeptNode"
:show-checkbox="showCheckbox" :expand-on-click-node="expandOnClickNode" :indent="indent" :node-key="'deptid'"
:default-expanded-keys="defaultExpandedKeys" :default-checked-keys="defaultCheckedKeys" auto-expand-parent
highlight-current style="min-height:100px;" @check-change="handleCheckChange" @current-change="handleCurrentChange"
@node-click="handleNodeClick" :check-on-click-node="true" check-strictly lazy :load="loadNode" ref="deptTree" @contextmenu.prevent >
</template>
</MdpTree>
<template #default="{ node, data }">
<div class="custom-tree-node" @contextmenu.prevent title="右键可以增删改">
<el-popover :open-delay="1000" placement="top-start" :width="showConfirm ? 300 : 200" trigger="contextmenu">
<el-button icon="plus" circle type="success" v-if="!(!data.deptid || data.deptid == 'A0' || data.deptid == '0')"
@click.prevent.stop="addNode(data, node)" title="添加子部门" />
<el-button icon="edit" circle type="warning" v-if="!(!data.deptid || data.deptid == 'A0' || data.deptid == '0')"
@click.prevent.stop="editNode(data, node)" title="修改部门" />
<el-button icon="delete" circle type="danger" v-if="!(!data.deptid || data.deptid == 'A0' || data.deptid == '0')"
@click.prevent.stop="deleteNode(data, node)" title="删除该部门" />
<template #reference>
<div style="display:flex;align-items:center;width:100%;"> {{ data.deptName }} </div>
</template>
</el-popover>
</div>
</template>
</el-tree>
</el-card>
<mdp-dialog title="新增部门" ref="addDialog" width="60%" append-to-body>
<el-form ref="addDept" :model="addDept" label-width="200">
<el-form-item label="上级部门">
<el-tag>{{ currentDept && currentDept.deptid && currentDept.deptid != 'A0' ? currentDept.deptName : "顶级部门A0" }}</el-tag>
</el-form-item>
<el-form-item label="部门编号">
<el-input v-model="addDept.deptid" placeholder="如果为空,则系统自动生成" />
</el-form-item>
<el-form-item label="部门名称" prop="deptName" :rules="[
{ required: true, message: '名称不能为空' }
]">
<el-input v-model="addDept.deptName" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="$refs['addDialog'].close()">关闭</el-button>
<el-button type="primary" v-loading="addLoading" @click="addDeptSubmit"> </el-button>
</template>
</mdp-dialog>
<mdp-dialog title="修改部门提示" width="60%" append-to-body ref="editDialog">
<el-form ref="editDept" :model="editDept" label-width="200">
<el-form-item label="部门编号" prop="id">
{{ editDept.deptid }}
</el-form-item>
<el-form-item label="部门名称" prop="deptName" :rules="[
{ required: true, message: '名称不能为空' }
<!--编辑 Dept xm_project_func界面-->
<mdp-dialog ref="editDialog" width="30%" append-to-body :close-on-click-modal="false">
<template #default="{ data,dialog }">
<el-form ref="editForm" :model="editForm" label-width="150" >
<el-form-item label="部门编号" prop="deptid" :rules="[
{ required: true, message: '不能为空'}
]">
<el-input v-model="editDept.deptName" />
</el-form-item>
{{editForm.deptid}}
</el-form-item>
<el-form-item label="部门名称" prop="deptName"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="editForm.deptName" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="$refs['editDialog'].close()"> </el-button>
<el-button type="primary" v-loading="editLoading" @click="editDeptSubmit"> </el-button>
<el-form-item label="图标" >
<IconSelect v-model="editForm.icon"/>
</el-form-item>
</el-form>
<div class="footer">
<el-button @click="dialog.close()">关 闭</el-button>
<el-button type="primary" v-loading="loading.edit" @click="editSubmit(data.callback)">确 定</el-button>
</div>
</template>
</mdp-dialog>
<!--新增 Dept xm_project_func界面-->
<mdp-dialog ref="addDialog" width="30%" append-to-body :close-on-click-modal="false">
<template #default="{ data, dialog }">
<el-form ref="addForm" :model="addForm" label-width="150" >
<el-form-item label="上级部门">
<el-tag>{{ data.parent && data.parent.deptid && data.parent.deptid!='A0'? "上级"+data.parent.deptName:"顶级部门A0" }}</el-tag>
</el-form-item>
<el-form-item label="部门编号" prop="deptid" :rules="[
{ required: true, message: '不能为空'}
]">
<el-input v-model="addForm.deptid" placeholder="如果为空则系统自动生成"/>
</el-form-item>
<el-form-item label="部门名称" prop="deptName"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="addForm.deptName" />
</el-form-item>
<el-form-item label="图标" >
<IconSelect v-model="addForm.icon"/>
</el-form-item>
</el-form>
<div class="footer">
<el-button @click="dialog.close()">关闭</el-button>
<el-button type="primary" v-loading="loading.add" @click="addSubmit(data.parent,data.callback)">确 定</el-button>
</div>
</template>
</mdp-dialog>
</template>
<script>
import util from '@/components/mdp-ui/js/util' //全局公共库
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
watch: {
deptFilterText(val) {
this.$refs.deptTree.filter(val);
},
checkedKeys(val) {
this.$refs.deptTree.setCheckedKeys(val);
},
refresh(val) {
this.getDeptTreeData(val);
},
currentKey(val) {
this.$refs.deptTree.setCheckedKeys([val]);
},
value(val) {
this.deptid = val;
},
deptid(val) {
this.$emit('input', val);
},
},
components: {
},
computed: {
defaultExpandedKeys() {
return this.expandRowKeys
},
defaultCheckedKeys() {
if (this.value) {
return [this.value];
}
return this.checkedKeys;
},
...mapState(useUserStore, [
'userInfo'
]),
},
props: {
'value': String, Array,
'branchId': String,
'visible': { type: Boolean, default: false },
'showCount': { type: Boolean, default: false },
'showRoot': { type: Boolean, default: false },
'countTips': String,
'showFilter': { type: Boolean, default: false },
'multiple': { type: Boolean, default: false },
'checkedKeys': Array,
'refresh': { type: Boolean, default: false },
'defaultExpandAll': { type: Boolean, default: false },
'expandOnClickNode': { type: Boolean, default: false },
showCheckbox: { type: Boolean, default: false },
showConfirm: { type: Boolean, default: false },
'indent': Number
},
'subOpType':{type:String,defalut:'mng'},
'multiple':{type:Boolean,default:false},
'showConfirm':{type:Boolean,default:false},
'hidden':{type:Object,default:()=>null},
'params':{type:Object,default:()=>null},
'clearable':{type:Boolean,default:true},
relyType:{
type:String,
default:''
},
relyId:{
type:String,
default:''
},
relyStype:{
type:String,
default:'',
},
relySid:{
type:String,
default:''
}
},
computed: {
...mapState(useUserStore, ['userInfo', 'roles']),
hiddenCpd(){
var isSelect=this.subOpType=='select'
var hidden ={
batchDel: isSelect,
del:isSelect,
changePid: false,
addTop: isSelect,
addSub: isSelect,
edit: isSelect,
filter: false,
page: true,
}
hidden=Object.assign(hidden,this.hidden)
return hidden
},
propsCpd(){
return { id: 'deptid', pid: 'pdeptid', label: 'deptName' , isLeaf:(data,n)=>{
return data.childNum<=0
}}
}
},
data() {
return {
deptFilterText: '',
defaultDeptTreeProps: {
id: 'deptid',
label: 'deptName',
children: 'children',
isLeaf: function (n) {
return n.childNum <= 0
}
},
listLoading: false,
deptid: '',
expandRowKeys: [],
root: null,
resolve: null,
filters: {
addDept:{deptid:'',deptName:'',pdeptid:''},
editDept:{deptid:'',deptName:'',pdeptid:''},
treeVisible:true,
isAddTop: false,
currentDept:{},
},
addForm:{deptid:'',pdeptid:'',deptName:'',isLeaf:'0',isAuth:'0',limitType:'2',deptType:'',pqx:'',qxLvl:''},
editForm:{deptid:'',pdeptid:'',deptName:'',isLeaf:'0',isAuth:'0',limitType:'2',deptType:'',pqx:'',qxLvl:''},
loading:{add:false,edit:false,list:false}
}
},
}, //end data
methods: {
addDeptSubmit(){
var branchId=this.userInfo.branchId
var pdeptid=""
if(this.isAddTop){
pdeptid="A0"
}else{
pdeptid=this.currentDept.deptid
branchId=this.currentDept.branchId||this.userInfo.branchId
}
this.addDept.pdeptid=pdeptid
this.addDept.branchId=branchId
this.$refs.addDept.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.addLoading = true;
this.$mdp.addDept(this.addDept).then(res=>{
this.addLoading=false;
if(res.tips.isOk){
this.$message.success(res.tips.msg);
if(!this.isAddTop){
if(this.currentDept.children){
this.currentDept.children.push(res.data)
}else{
this.currentDept.children=[res.data]
}
}else{
this.$refs['deptTree'].append(res.data,this.root)
}
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.addLoading = false );
});
}
});
},
editDeptSubmit(){
this.$refs.editDept.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.editLoading = true;
this.$mdp.editDept(this.editDept).then(res=>{
//console.log("res--"+JSON.stringify(res));
this.editLoading = false;
if(res.tips.isOk){
this.$message.success(res.tips.msg);
this.$refs['deptTree'].updateKeyChildren(res.data.deptid,res.data)
this.editVisible=false
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.editLoading = false );
});
}
});
},
addTopNode(){
this.isAddTop=true
this.addDept.pdeptid='A0'
this.addDept.deptid=''
this.addDept.deptName=''
this.$refs['addDialog'].open()
},
addNode(data, node, comp) {
this.isAddTop=false
this.currentDept=data
this.addDept.pdeptid=data.deptid
this.addDept.deptid=''
this.addDept.deptName=''
this.$refs['addDialog'].open()
},
editNode(data, node, comp) {
this.editDept=data
this.$refs['editDialog'].open()
},
deleteNode(data, node, comp) {
if(data.childNum>0||data.children?.length>0){
this.$message.error("请先删除子元素");
return;
}
let params={
deptid:data.deptid
}
this.$confirm('确认删除吗?', '提示', {}).then(() => {
this.$mdp.delDept(params).then(res=>{
//console.log("res--"+JSON.stringify(res));
if(res.tips.isOk){
this.$refs['deptTree'].remove(data)
this.$message.success(res.tips.msg);
}else{
this.$message.error(res.tips.msg);
}
});
})
return false;
},
handleCheckChange(data, checked, indeterminate) {
let checkedKeys = this.$refs.deptTree.getCheckedKeys();
if (this.multiple === undefined || this.multiple === false || this.multiple === 'false') {
if (checked == true) {
if (checkedKeys.length > 1) {
this.$refs.deptTree.setCheckedKeys([data['deptid']]);
this.$emit('check-change', data, checked, indeterminate);
this.deptid = data['deptid'];
} else {
this.$emit('check-change', data, checked, indeterminate);
this.deptid = data['deptid'];
}
} else {
if (checkedKeys.length == 0) {
this.deptid = '';
this.$emit('check-change', data, checked, indeterminate);
}
}
} else {
this.$emit('check-change', data, checked, indeterminate);
}
listDept(params, node) {
Object.assign(params,this.filters)
if(this.params){
Object.assign(params,this.params)
}
return this.$mdp.listDept(params)
},
handleCurrentChange(data, node) {
this.$emit('current-change', data, node);
},
handleNodeClick(data, node, comp) {
this.$emit('node-click', data, node, comp);
},
translateDataToTree(data) {
if (!data) {
return [];
}
return data
},
//获取部门树列表
getDeptTreeData(refresh) {
this.treeVisible=false
this.$nextTick(()=>{
this.treeVisible=true
delDept(p){return this.$mdp.delDept(p)},
addDept(p){return this.$mdp.addDept(p)},
editDept(p){return this.$mdp.editDept(p)},
batchChangeParent(p){return this.$mdp.batchChangeDeptParent(p)},
//显示编辑界面 Dept xm_project_func
onEditClick: function (formData, callback, addSubCallback) {
this.editForm={...formData}
this.$refs['editDialog'].open({
formData: formData,
callback: callback,
addSubCallback: addSubCallback
})
},
filterDeptNode(value, data) {
if (!value) return true;
if (data.deptid.indexOf(value) >= 0 || data.deptName.indexOf(value) >= 0) {
return true;
} else {
if (data.pdeptid && data.pdeptid.indexOf(value) >= 0) {
return true;
}
//显示新增界面 Dept xm_project_func
onAddTopClick: function (callback) {
var formData = {}
if (!this.initExtParams(formData)) {
return
}
return false;
},
confirm() {
var nodes = this.$refs.deptTree.getCheckedNodes(false, false)
if (this.multiple) {
this.$emit('confirm', nodes)
} else {
this.$emit('confirm', nodes && nodes.length > 0 ? nodes[0] : null)
}
this.$refs['addDialog'].open({
formData: formData,
parent: null,
callback: callback
})
},
loadNode(node, resolve) {
if (node.level === 0) {
this.root = node
this.resolve = resolve
let params = {
'res.levelType': 'L1'
};
params.branchId = this.branchId
if (params.branchId == null || params.branchId == '') {
params.branchId = this.userInfo.branchId
}
this.listLoading = true;
this.$mdp.listDept(params).then((res) => {
var tips = res.tips;
var data = res.data;
this.listLoading = false;
var tempData = this.translateDataToTree(data);
this.expandRowKeys = tempData?.length > 0 ? [tempData[0]] : []
resolve(tempData)
}).catch(() => {
this.listLoading = false;
});
} else {
setTimeout(() => {
let params = {
pdeptid: node.data.deptid
};
if (params.branchId == null || params.branchId == '') {
params.branchId = this.userInfo.branchId
initExtParams(formData, parent) {
return true
},
onAddSubClick: function (parent, callback) {
var formData = {}
if (!this.initExtParams(formData, parent)) {
return
}
Object.assign(formData,parent)
formData.pdeptid=parent.deptid
formData.deptid=null
this.addForm={...formData}
this.$refs['addDialog'].open({
formData: formData,
parent: parent,
callback: callback
})
},
onChangePidClick: function(idLinks,callback){
this.batchChangeParent(idLinks).then(res=>{
let {tips}=res
if(tips.isOk){
if(callback){
callback(true)
}
this.$message.success(tips.msg)
}else{
this.$message.error(tips.msg)
}
this.listLoading = true;
this.$mdp.listDept(params).then((res) => {
var tips = res.tips;
var data = res.data;
this.listLoading = false;
resolve(this.translateDataToTree(data))
})
},
addSubmit(parent,callback){
var branchId=this.userInfo.branchId
this.addForm.branchId=branchId
if(this.relyType){
this.addForm.relyType=this.relyType
}
if(this.relyId){
this.addForm.relyId=this.relyId
}
if(this.relyStype){
this.addForm.relyStype=this.relyStype
}
if(this.relySid){
this.addForm.relySid=this.relySid
}
this.$refs.addForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.loading.add = true;
this.addDept(this.addForm).then(res=>{
this.loading.add=false;
if(res.tips.isOk){
this.$message.success(res.tips.msg);
this.$refs.addDialog.close()
callback(res.data)
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.loading.add = false );
}).catch(() => {
this.listLoading = false;
});
}, 500);
});
}
});
},
editSubmit(callback){
this.$refs.editForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.loading.edit = true;
this.editDept(this.editForm).then(res=>{
if(res.tips.isOk){
this.loading.edit = false
this.$refs.editDialog.close();
this.$message.success(res.tips.msg);
callback(this.editForm)
}else{
this.$message.error(res.tips.msg);
}
}).catch(e=>this.loading.edit = false );
}
});
}
});
}
}, //end methods
components: {
},
mounted() {
this.deptid = this.value;
//this.getDeptTreeData();
mounted() {
}
}
</script>
<style scoped>
</style>
<style lang="scss" />

View File

@@ -72,6 +72,18 @@ export default {
getDate() {
return moment().format(DEFAULT_PATTERN)
},
//获取两个日期之间的月份列表
getMonths(startDate, endDate) {
let months = [];
let current = moment(startDate);
while (current.isBefore(endDate)) {
months.push(current.clone());
current.add(1, 'months');
}
return months;
},
getQueryStringByName: function(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
@@ -136,6 +148,16 @@ export default {
toMLine(name) {
return name.replace(/([A-Z])/g, "-$1").toLowerCase();
},
toFixed(val,scale){
if(!val){
return 0
}else{
return val.toFixed(scale)
}
},
moment:function(){
return moment()
},
formatDate: function(date, pattern) {
if(!date){

View File

@@ -10,19 +10,28 @@
<el-input v-if="!hiddenCpd.filter" style="width:10em;" v-model="filterText" placeholder="名称" auto-complete="off" clearable/>
<el-button v-if="!hiddenCpd.addTop" type="primary" @click="addTopNode_()" icon="plus" :title="'添加一级' + title" plain/>
<el-button v-if="!hiddenCpd.batchDel" type="danger" @click="batchDel_()" icon="delete" :title="'批量删除'" plain/>
<el-button v-if="!hiddenCpd.changePid" type="warning" @click="changePid_()" icon="top" :title="'调整上级'" plain/>
</slot>
<el-button v-if="showConfirm" type="warning" @click="confirm" icon="check" title="确认选择" />
<el-button v-if="!hiddenCpd.changePid && idLinks.size>0" type="warning" @click="changePid_()" icon="top" :title="'拖拽后必须保存才能正式生效'">拖拽后保存</el-button>
<el-button v-if="!hiddenCpd.changePid && idLinks.size>0" @click="cancelChangePid()" icon="close" :title="'取消保存'">取消</el-button>
</slot>
<el-button v-if="showConfirm" type="warning" @click="confirm" icon="check" title="确认选择" />
</el-space>
</template>
<el-tree v-adaptive style="width:100%;" v-if="treeVisible" v-loading="listLoading" :props="propsCpd" :filter-node-method="filterNode"
:show-checkbox="showCheckbox" :expand-on-click-node="expandOnClickNode" :indent="indent" :node-key="propsCpd['id']"
<el-tree v-adaptive style="width:100%;" v-if="treeVisible" v-loading="loading.addlist" :props="propsCpd" :filter-node-method="filterNode"
:show-checkbox="showCheckbox" :expand-on-click-node="expandOnClickNode" :indent="indent" :node-key="propsCpd.id"
:default-expanded-keys="defaultExpandedKeys" :default-checked-keys="defaultCheckedKeys" auto-expand-parent
highlight-current @check-change="handleCheckChange" @current-change="handleCurrentChange" accordion
@node-click="handleNodeClick" :check-on-click-node="true" check-strictly lazy :load="loadNode" ref="nodeTree"
@contextmenu.prevent>
@contextmenu.prevent
:draggable="draggable"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
:allowDrop="myAllowDrop"
>
<template #default="{ node, data }">
<div class="custom-tree-node" @contextmenu.prevent title="右键可以增删改">
@@ -34,7 +43,7 @@
@click.prevent.stop="editNode_(data, node)" :title="'修改' + title" />
<el-button icon="delete" circle type="danger" v-if="!(!data[propsCpd['id']] || data[propsCpd['id']] == rootId) && !hiddenCpd.del"
@click.prevent.stop="deleteNode_(data, node)" :title="'删除该' + title" />
<slot name="nodeToolbar">
<slot name="nodeToolbar" :data="data" :node="node">
</slot>
</slot>
@@ -105,6 +114,8 @@ export default {
}
},
props: {
'allowDrop':{type: Function,default:null},
'draggable':{type: Boolean,default: false},
'showCount': { type: Boolean, default: false },
'showFilter': { type: Boolean, default: false },
'multiple': { type: Boolean, default: false },
@@ -128,7 +139,7 @@ export default {
label: 'name',
pid: 'pid',
children: 'children',
isLeaf: function (n) {
isLeaf: function (n,node) {
return n.childNum <= 0
}
}
@@ -163,8 +174,10 @@ export default {
},
data() {
return {
filterText: '',
listLoading: false,
idLinks:new Map(),//存储新的上下级关系key=id,value=pid
oldIdLinks: new Map(), //存储原来的上下级关系key=id,value=pid,只存一次,拖拽开始的时候就存入
draging: false,//拖拽成功后变成true,保存后变成false
filterText: '',
expandRowKeys: [],
root: null,
resolve: null,
@@ -176,10 +189,69 @@ export default {
pageSize: 500,
pageNum: 1,
count: true
}
},
loading:{add:false,edit:false,list:false,del:false}
}
},
methods: {
handleDragStart(node,event){
this.$emit("node-drag-start",node,event)
},
handleDragEnter(draggingNode,dropNode,event){
this.$emit("node-drag-enter",draggingNode,dropNode,event)
},
handleDragLeave(draggingNode,dropNode,event){
this.$emit("node-drag-leave",draggingNode,dropNode,event)
},
handleDragOver(draggingNode,dropNode,event){
this.$emit("node-drag-over",draggingNode,dropNode,event)
},
handleDragEnd(draggingNode,dropNode,dropType,event){
this.$emit("node-drag-end",draggingNode,dropNode,dropType,event)
},
myAllowDrop(draggingNode,dropNode,dropType){
return this.allowDrop?this.allowDrop(draggingNode,dropNode,dropType):true
},
handleDrop(draggingNode,dropNode,dropType,event){
this.draging=true
let idKey=this.propsCpd['id']
let pidKey=this.propsCpd['pid']
let sdata=draggingNode.data
var pnode=dropNode
if(dropType!='inner'){
pnode=dropNode.parent
}
let edata=pnode.data
let oldPid=sdata[pidKey]
let newPid=edata[idKey]
if(newPid==oldPid){
this.idLinks.delete(sdata[idKey])
}else{
this.idLinks.set(sdata[idKey],edata[idKey])
}
if(!pnode.expanded ){
var callback=null;
if(pnode.shouldLoadData()){
callback=()=>{
//加载数据后需要手动添加一个节点bug
pnode.insertChild({data:sdata})
}
}
pnode.expand(callback)
}
this.$emit("node-drop",draggingNode,dropNode,dropType,event)
},
getCheckedKeys(){
return this.$refs.nodeTree.getCheckedKeys();
},
@@ -188,6 +260,7 @@ export default {
return this.$refs.nodeTree.getCheckedNodes()
},
updateKeyChildren(key,data){
debugger
this.$refs['nodeTree'].updateKeyChildren(key,data)
},
addTopNode(data){
@@ -203,11 +276,14 @@ export default {
if(!data){
return
}
if(parent.children){
parent.children.push(data)
debugger
var pnode=this.$refs.nodeTree.getNode(parent[this.propsCpd['id']])
if(!pnode.expanded ){
pnode.expand()
}else{
parent.children=[data]
pnode.insertChild({data:data})
}
},
addSubNode_(parent, node, comp) {
@@ -217,11 +293,13 @@ export default {
this.$emit('addSubNode',parent,callback)
},
editNode_(cdata, node, comp) {
var callback = (data) => {
debugger
if(!data){
return
}
this.$refs['nodeTree'].updateKeyChildren(cdata[this.propsCpd['id']],data)
Object.assign(node.data,data)
}
var addSubCallback = (subData) => {
this.addSubNode(cdata,subData)
@@ -248,16 +326,26 @@ export default {
})
return false;
},
changePid_(){
let checkedKeys = this.$refs.nodeTree.getCheckedKeys();
if(checkedKeys.length==0){
this.$message.error("请选择需要更换上级的记录");
cancelChangePid(){
this.refresh()
},
changePid_(){
if(this.idLinks.length==0){
this.$message.error("没有数据改变,无须保存");
return;
}
var callback = () => {
this.refresh()
var callback = (refresh) => {
this.idLinks=new Map()
if(refresh)this.refresh()
}
this.$emit('changePid',checkedKeys,callback)
var list=[]
this.idLinks.forEach((value, key) => {
let d={}
d[this.propsCpd['id']]=key
d[this.propsCpd['pid']]=value
list.push(d)
});
this.$emit('changePid',list,callback)
},
batchDel_() {
let checkedKeys = this.$refs.nodeTree.getCheckedKeys();
@@ -317,6 +405,7 @@ export default {
},
//重新获取部门树列表
refresh() {
this.idLinks=new Map()
this.treeVisible = false
this.$nextTick(() => {
this.treeVisible = true
@@ -351,31 +440,30 @@ export default {
this.resolve = resolve
let params = {};
params[this.propsCpd['pid']] = this.rootId
this.listLoading = true;
this.loading.addlist = true;
this.load(params, node, resolve).then((res) => {
var tips = res.tips;
var data = res.data;
this.listLoading = false;
var tempData = this.translateDataToTree(data);
//this.expandRowKeys = tempData?.length > 0 ? [tempData[0]] : []
this.loading.addlist = false;
var tempData = this.translateDataToTree(data);
resolve(tempData)
}).catch(() => {
this.listLoading = false;
this.loading.addlist = false;
});
} else {
setTimeout(() => {
let params = {};
params[this.propsCpd['pid']] = node.data[this.propsCpd['id']]
this.listLoading = true;
this.loading.addlist = true;
this.load(params, node, resolve).then((res) => {
var tips = res.tips;
var data = res.data;
this.listLoading = false;
this.loading.addlist = false;
resolve(this.translateDataToTree(data))
}).catch(() => {
this.listLoading = false;
this.loading.addlist = false;
});
}, 500);

View File

@@ -97,7 +97,7 @@ export const MdpSelectMixin = {
return util.getCodeKey(this.itemCode,this.params)
}else{
if(this.loadFun){
if(this.loadFun){
return util.getCodeKey(this.loadFun.name,this.params)
}else{
return "xxxx"
@@ -211,10 +211,12 @@ export const MdpSelectMixin = {
}
this.myValCpd=this.myVal
},
codeKey(){
this.initMyValByValue();
codeKey(){
this.initItemOptions();
},
initName(){
this.initMyValByValue()
}
},
props: {
title:{
@@ -735,6 +737,7 @@ export const MdpSelectMixin = {
* @returns
*/
initMyValByValue(){
debugger
if(this.initOptions && this.initOptions.length>0){
return;
}

View File

@@ -689,6 +689,12 @@ export const MdpTableMixin = {
form=this.$refs['formDialog']
}
}
if(!form){
form=this.$refs['formDlg']
if(!form){
form=this.$refs['formDlg']
}
}
if(form){
if(!parentOpType){
parentOpType=this.currOpType
@@ -761,11 +767,14 @@ export const MdpTableMixin = {
},
//即将作废
showAdd(){
this.addFormVisible=true
},
//即将作废
showEdit(){
showEdit(row){
if(row){
this.editForm=row
}
this.editFormVisible=true
},
//即将作废
showDetail(){

View File

@@ -262,18 +262,7 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
roles: ['user'],
hidden: true
}
},
{
path: 'contract',
component: () => import('@/views/xm/pro/xmContract/XmContractForProject.vue'),
name: 'projectContract',
meta: {
title: '项目-合同',
icon: 'project',
roles: ['user'],
hidden: true
}
},
},
{
path: 'record',
component: () => import('@/views/xm/core/xmRecord/XmRecordForProject.vue'),
@@ -284,51 +273,18 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
roles: ['user'],
hidden: true
}
},
{
path: 'budget',
component: () => import('@/views/xm/pro/fin/XmProjectBudgetCost.vue'),
name: 'projectBudget',
meta: {
title: '项目-预算',
icon: 'project',
roles: ['user'],
hidden: true
}
},
{
path: 'cost',
component: () => import('@/views/xm/pro/fin/XmProjectCost.vue'),
name: 'projectCost',
meta: {
title: '项目-费用',
icon: 'project',
roles: ['user'],
hidden: true
}
},
},
{
path: 'workloadDay',
component: () => import('@/views/xm/core/xmWorkload/WorkloadSetDayList.vue'),
name: 'projectBudget',
name: 'projectWorkloadDay',
meta: {
title: '项目-工时日报',
icon: 'project',
roles: ['user'],
hidden: true
}
},
{
path: 'workloadMonth',
component: () => import('@/views/xm/pro/rpt/workload/WorkloadSetMonthList.vue'),
name: 'projectWorkloadMonth',
meta: {
title: '项目-工时月报',
icon: 'project',
roles: ['user'],
hidden: true
}
},
},
{
path: 'file',
component: () => import('@/views/xm/core/xmFile/XmFileForProject.vue'),
@@ -339,18 +295,7 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
roles: ['user'],
hidden: true
}
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForProject.vue'),
name: 'projectRpt',
meta: {
title: '项目-效能',
icon: 'project',
roles: ['user'],
hidden: true
}
}
},
]
},
{
@@ -473,17 +418,7 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
icon: 'product',
hidden: true
}
},
{
path: 'contract',
component: () => import('@/views/xm/pro/xmContract/XmContractForProduct.vue'),
name: 'productContract',
meta: {
title: '产品-合同',
icon: 'product',
hidden: true
}
},
},
{
path: 'record',
component: () => import('@/views/xm/core/xmRecord/XmRecordForProduct.vue'),
@@ -493,27 +428,7 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
icon: 'product',
hidden: true
}
},
{
path: 'workloadDay',
component: () => import('@/views/xm/core/xmWorkload/WorkloadSetDayList.vue'),
name: 'productBudget',
meta: {
title: '产品-工时日报',
icon: 'product',
hidden: true
}
},
{
path: 'workloadMonth',
component: () => import('@/views/xm/pro/rpt/workload/WorkloadSetMonthList.vue'),
name: 'productWorkloadMonth',
meta: {
title: '产品-工时月报',
icon: 'product',
hidden: true
}
},
},
{
path: 'file',
component: () => import('@/views/xm/core/xmFile/XmFileForProduct.vue'),
@@ -525,15 +440,15 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
}
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForProduct.vue'),
name: 'productRpt',
path: 'workloadDay',
component: () => import('@/views/xm/core/xmWorkload/WorkloadSetDayList.vue'),
name: 'productWorkloadDay',
meta: {
title: '产品-效能',
title: '产品-工时日报',
icon: 'product',
hidden: true
}
}
},
]
},
@@ -638,33 +553,13 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
{
path: 'workloadDay',
component: () => import('@/views/xm/core/xmWorkload/WorkloadSetDayList.vue'),
name: 'iterationBudget',
name: 'iterationWorkloadDay',
meta: {
title: '迭代-工时日报',
icon: 'iteration',
hidden: true
}
},
{
path: 'workloadMonth',
component: () => import('@/views/xm/pro/rpt/workload/WorkloadSetMonthList.vue'),
name: 'iterationWorkloadMonth',
meta: {
title: '迭代-工时月报',
icon: 'iteration',
hidden: true
}
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForIteration.vue'),
name: 'iterationRpt',
meta: {
title: '迭代-效能',
icon: 'iteration',
hidden: true
}
}
},
]
},
{
@@ -757,13 +652,7 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
component: () => import('@/views/xm/core/xmGroup/XmGroupForTest.vue'),
name: 'testGroup',
meta: { title: '团队', roles: ['user'], hidden: true }
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForTest.vue'),
name: 'testRpt',
meta: { title: '统计分析', roles: ['user'], hidden: true }
}
},
]
},

View File

@@ -1,5 +1,9 @@
import { Layout } from '@/utils/routerHelper'
import XmProjectLayout from '@/views/xm/core/xmProject/index.vue'
import XmProductLayout from '@/views/xm/core/xmProduct/index.vue'
import XmIterationLayout from '@/views/xm/core/xmIteration/index.vue'
import XmTestLayout from '@/views/xm/core/xmTestCasedb/index.vue'
const { t } = useI18n()
const RoutesXmCore: AppRouteRecordRaw[] = [
@@ -45,17 +49,29 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
children: [
{
path: 'branch/cost',
component: () => import('@/views/xm/pro/fin/XmProjectCost.vue'),
component: () => import('@/views/xm/pro/fin/XmCost.vue'),
name: 'XmBranchCost',
meta: { title: '应付统计', roles: ['user'] }
meta: { title: '成本分析', roles: ['user'] }
},
{
path: 'branch/cost/nlabor',
component: () => import('@/views/xm/pro/xmCostNlabor/XmCostNlaborMng.vue'),
name: 'XmBranchCostNlabor',
meta: { title: '支出明细', roles: ['user'] }
path: 'branch/cost/record',
component: () => import('@/views/xm/pro/xmCostRecord/Index.vue'),
name: 'XmBranchCostRecord',
meta: { title: '成本明细', roles: ['user'] }
},
{
path: 'branch/budget',
component: () => import('@/views/xm/pro/fin/XmBudgetCost.vue'),
name: 'XmBranchBudget',
meta: { title: '预算分析', roles: ['user'] }
},
{
path: 'branch/budget/record',
component: () => import('@/views/xm/pro/xmBudgetRecord/Index.vue'),
name: 'XmBranchBudgetRecord',
meta: { title: '预算明细', roles: ['user'] }
},
{
path: 'task/sbill',
component: () => import('@/views/xm/pro/xmTaskSbill/XmTaskSbillMng.vue'),
@@ -116,9 +132,189 @@ const RoutesXmCore: AppRouteRecordRaw[] = [
component: () => import('@/views/xm/pro/rpt/index/index.vue'),
name: 'rptIndex',
meta: { title: '指标分析', roles: ['user'] }
},
{
path: 'branch',
component: () => import('@/views/xm/pro/XmOverview.vue'),
name: 'branchRpt',
meta: { title: '企业级效能概览', roles: ['user'] }
},
]
},
{
path: '/xm/pro/project/view',
component: XmProjectLayout,
name: 'XmProProjectView',
meta: {
title: '项目管理',
icon: 'project',
hidden: true,
},
// leaf: true,//只有一个节点
children: [
{
path: 'budget',
component: () => import('@/views/xm/pro/fin/XmBudgetForProject.vue'),
name: 'projectBudget',
meta: {
title: '项目-预算',
icon: 'project',
roles: ['user'],
hidden: true
}
},
{
path: 'cost',
component: () => import('@/views/xm/pro/fin/XmCostForProject.vue'),
name: 'projectCost',
meta: {
title: '项目-费用',
icon: 'project',
roles: ['user'],
hidden: true
}
},
{
path: 'workloadMonth',
component: () => import('@/views/xm/pro/rpt/workload/WorkloadSetMonthList.vue'),
name: 'projectWorkloadMonth',
meta: {
title: '项目-工时月报',
icon: 'project',
roles: ['user'],
hidden: true
}
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForProject.vue'),
name: 'projectRpt',
meta: {
title: '项目-效能',
icon: 'project',
roles: ['user'],
hidden: true
}
}
]
}
},
{
path: '/xm/pro/product/view',
component: XmProductLayout,
name: 'XmProProductView',
meta: {
title: '产品管理',
icon: 'product',
hidden: true,
},
// leaf: true,//只有一个节点
children: [
{
path: 'contract',
component: () => import('@/views/xm/pro/xmContract/XmContractForProduct.vue'),
name: 'productContract',
meta: {
title: '产品-合同',
icon: 'product',
hidden: true
}
},
{
path: 'budget',
component: () => import('@/views/xm/pro/fin/XmBudgetForProduct.vue'),
name: 'productBudget',
meta: {
title: '产品-预算',
icon: 'product',
hidden: true
}
},
{
path: 'cost',
component: () => import('@/views/xm/pro/fin/XmCostForProduct.vue'),
name: 'productCost',
meta: {
title: '产品-成本',
icon: 'product',
hidden: true
}
},
{
path: 'workloadMonth',
component: () => import('@/views/xm/pro/rpt/workload/WorkloadSetMonthList.vue'),
name: 'productWorkloadMonth',
meta: {
title: '产品-工时月报',
icon: 'product',
hidden: true
}
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForProduct.vue'),
name: 'productRpt',
meta: {
title: '产品-效能',
icon: 'product',
hidden: true
}
}
]
},
{
path: '/xm/pro/iteration/view',
component: XmIterationLayout,
name: 'XmProIterationView',
meta: {
title: '迭代管理',
icon: 'iteration',
hidden: true,
},
// leaf: true,//只有一个节点
children: [
{
path: 'workloadMonth',
component: () => import('@/views/xm/pro/rpt/workload/WorkloadSetMonthList.vue'),
name: 'iterationWorkloadMonth',
meta: {
title: '迭代-工时月报',
icon: 'iteration',
hidden: true
}
},
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForIteration.vue'),
name: 'iterationRpt',
meta: {
title: '迭代-效能',
icon: 'iteration',
hidden: true
}
}
]
},
{
path: '/xm/pro/test/view',
component: XmTestLayout,
name: 'XmProTestView',
meta: {
title: '测试管理',
icon: 'bug',
hidden: true,
},
// leaf: true,//只有一个节点
children: [
{
path: 'rpt',
component: () => import('@/views/xm/pro/rpt/index/indexForTest.vue'),
name: 'testRpt',
meta: { title: '统计分析', roles: ['user'], hidden: true }
}
]
},
]
export default RoutesXmCore

View File

@@ -1,5 +1,4 @@
<template>
<!--编辑界面 XmEnvList xm_env_list-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm" label-position="left">
<el-form-item label="名称" prop="name">
@@ -60,15 +59,14 @@
</el-row>
<el-form-item label="备注说明" prop="remark">
<el-input type="textarea" rows="4" v-model="editForm.remark" placeholder="备注说明" />
</el-form-item>
<el-form-item>
<el-col :span="24" :offset="8">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="editSubmit" :disabled="load.edit==true">提交</el-button>
</el-col>
</el-form-item>
</el-form-item>
</el-form>
<div class="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="editSubmit" :disabled="load.edit==true">提交</el-button>
</div>
</template>
<script>

View File

@@ -13,10 +13,12 @@
@addTopNode="(cb) => onAddTopClick(cb)"
@editNode="(d, cb, subcb) => onEditClick(d, cb, subcb)"
@addSubNode="(p, cb) => onAddSubClick(p, cb)"
@changePid="(cks,cb) => onChangePidClick(cks,cb)"
@confirm = "(d)=>{$emit('confirm',d);$emit('select',d)}"
@check-change="(d,c,i)=>$emit('check-change',d,c,i)"
@node-click="(d,n,c)=>$emit('node-click',d,n,c)"
rootId="0"
:draggable="true"
>
<template #topToolbar>
<xm-product-select width="300px"
@@ -69,7 +71,8 @@
import {
delXmFunc,
batchDelXmFunc,
listXmFunc
listXmFunc,
batchChangeParent,
} from '@/api/xm/core/xmFunc'
import XmProductSelect from '@/views/xm/core/components/XmProductSelect.vue' //新增界面
@@ -99,7 +102,7 @@
var hidden ={
batchDel: isSelect,
del:isSelect,
changePid: true,
changePid: false,
addTop: isSelect,
addSub: isSelect,
edit: isSelect,
@@ -205,7 +208,19 @@
callback: callback
})
},
onChangePidClick: function(idLinks,callback){
batchChangeParent(idLinks).then(res=>{
let {tips}=res
if(tips.isOk){
if(callback){
callback(true)
}
this.$message.success(tips.msg)
}else{
this.$message.error(tips.msg)
}
})
},
onProductSelected: function (product) {
this.product = product
this.$refs['nodeTree'].refresh()

View File

@@ -6,39 +6,35 @@
<el-input v-model="editForm.groupName" placeholder="团队名称">
<template v-if="currOpType=='edit'" #append>{{editForm.lvl}}</template>
</el-input>
</el-form-item>
<el-form-item label="组长" prop="leaderUsername">
<MdpSelectUser width="100%" v-model="editForm.leaderUserid" :init-name="editForm.leaderUsername"/>
</el-form-item>
<el-form-item label="负责人" prop="leaderUsername">
<el-form-item label="组长" prop="leaderUsername">
<el-input v-model="editForm.leaderUsername" placeholder="组长人姓名" @click="showUserSelect('leader')"/>
</el-form-item>
<el-form-item label="副组长" prop="assUsername">
<el-input v-model="editForm.assUsername" placeholder="副组长姓名" @click="showUserSelect('ass')"/>
<font color="blue">如果没有副组长可以设置为项目助理小组助理等具有组长同等权限</font>
</el-form-item>
</el-form-item>
<el-form-item label="企业协作" prop="isCrow">
<el-form-item label="" prop="isCrow">
<el-form-item label="副组长" prop="assUsername">
<MdpSelectUser width="100%" v-model="editForm.assUserid" :init-name="editForm.assUsername"/>
<el-text type="primary">如果没有副组长可以设置为项目助理小组助理等具有组长同等权限</el-text>
</el-form-item>
<el-form-item label="归属产品" prop="productId">
<XmProductSelect width="100%" v-model="editForm.productId" :link-project-id="editForm.projectId"/>
<el-text type="primary">关联上产品可以将小组归属到产品上</el-text>
</el-form-item>
<el-form-item label="企业协作" prop="isCrow">
<el-checkbox v-model="editForm.isCrow" true-label="1" false-label="0">是否属于协作公司</el-checkbox>
</el-form-item>
<el-form-item label="协作公司" prop="crowBranchId" v-if="editForm.isCrow=='1'">
<mdp-select-branch width="100%" v-model="editForm.crowBranchId" :init-name="editForm.crowBranchName" @change2="branchRowClick" />
<el-text type="primary">如果该团队属于某协作公司请选择协作公司</el-text>
</el-form-item>
<el-form-item label="协作公司" prop="crowBranchName" v-if="editForm.isCrow">
<el-input v-model="editForm.crowBranchName" placeholder="协作公司名称" @click="branchVisible=true"/>
<font color="blue">如果该团队属于某协作公司请选择协作公司</font>
</el-form-item>
</el-form-item>
</el-form>
<el-row class="page-bottom bottom-fixed">
<div class="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="saveSubmit" :disabled="load.edit==true">提交</el-button>
</el-row>
<mdp-dialog append-to-body title="选择员工" v-model="userSelectVisible" width="60%">
<users-select isSingleUser=true @confirm="onUserSelected" ref="usersSelect" />
</mdp-dialog>
<mdp-dialog title="机构选择" v-model="branchVisible" size="50%" top="20" :close-on-click-modal="false" append-to-body>
<branch-select :visible="branchVisible" @cancel="branchVisible=false" @row-click="branchRowClick" />
</mdp-dialog>
</div>
</template>
@@ -48,12 +44,12 @@
import { addXmGroup,editXmGroup } from '@/api/xm/core/xmGroup';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import { useUserStore } from '@/store/modules/user'
import XmProductSelect from '@/views/xm/core/components/XmProductSelect.vue' //新增界面
export default {
name:'xmGroupEdit',
components: {
XmProductSelect
},
computed: {
...mapState(useUserStore,[ 'userInfo' ]),
@@ -168,8 +164,7 @@ import { useUserStore } from '@/store/modules/user'
}
},
branchRowClick: function(row, event, column){
this.branchVisible=false
branchRowClick: function(row){
this.editForm.crowBranchId=row.id
this.editForm.crowBranchName=row.branchName
},

View File

@@ -2,29 +2,27 @@
<ContentWrap>
<el-space>
<xm-project-select v-if="!selProject&&!xmProduct" :link-iteration-id="xmIteration?xmIteration.id:null" :link-product-id="xmProduct?xmProduct.id:null" @select="onProjectRowClick" @clear="onProjectClearSelect" />
<xm-project-select v-if="!selProject" :link-iteration-id="xmIteration?xmIteration.id:null" :link-product-id="xmProduct?xmProduct.id:null" @select="onProjectRowClick" @clear="onProjectClearSelect" />
<el-input v-model="filters.groupName" style="width:15%;" clearable placeholder="名称过滤"/>
<el-input v-model="filters.groupName" clearable placeholder="名称过滤"/>
<el-button type="primary" @click="searchXmGroups" icon="search">刷新</el-button>
<el-button type="plain" @click="showGroupState" icon="s-data">小组进度</el-button>
<el-button class="hidden-lg-and-down" type="plain" @click="xmRecordVisible=true" icon="document">变化日志</el-button>
<el-button class="hidden-lg-and-down" type="plain" @click="doSearchImGroupsByProjectId" icon="document">绑定即聊情况</el-button>
<el-button type="plain" @click="showAllGroupDlg" icon="histogram">小组数据对比</el-button>
<el-button class="hidden-lg-and-down" type="plain" @click="showRecord()" icon="document">变化日志</el-button>
<!-- <el-button class="hidden-lg-and-down" type="plain" @click="doSearchImGroupsByProjectId" icon="document">绑定即聊情况</el-button> -->
<el-button class="hidden-md-and-down" @click="groupRoleDescVisible=true" icon="document">角色说明</el-button>
<font style="font-size:12px;" class="hidden-md-and-down" color="blue">点击架构图操作</font>
<el-text type="info">架构图-右键-操作</el-text>
<el-popover
placement="bottom"
width="500"
trigger="click">
<el-button type="plain" @click="xmRecordVisible=true" icon="document">变化日志</el-button>
<el-button type="plain" @click="doSearchImGroupsByProjectId" icon="document">绑定即聊情况</el-button>
<el-button @click="groupRoleDescVisible=true" icon="document">角色说明</el-button>
<font style="font-size:12px;" color="blue">注意点击架构图进行操作</font>
<el-button @click="groupRoleDescVisible=true" icon="document">角色说明</el-button>
<el-text type="info">注意点击架构图-右键进行新增等操作</el-text>
<template #reference><el-link type="warning" v-if="!selProject" icon="search">更多</el-link></template>
</el-popover>
</el-space>
</ContentWrap>
<Vue3TreeOrg v-adaptive :data="okrTreeData" v-loading="load.list" ref="tree" :props="{'id':'id','pid':'pgroupId',label:'label'}"
<Vue3TreeOrg @contextmenu.prevent v-adaptive :data="okrTreeData" v-loading="load.list" ref="tree" :props="{'id':'id','pid':'pgroupId',label:'label'}"
:node-draggable="true"
:horizontal="false"
:collapsable="true"
@@ -120,7 +118,7 @@
</el-collapse>
</el-row>
<el-row class="padding">
<el-row class="footer">
<el-button type="primary" @click="groupRoleDescVisible=false">关闭</el-button>
</el-row>
</mdp-dialog>
@@ -128,22 +126,15 @@
<mdp-select-user @change2="onUserSelected" multiple/>
</mdp-dialog>
<mdp-dialog v-if="selProject" :title="selProject==null?'操作日志':selProject.name+'团队操作日志'" center v-model="xmRecordVisible" width="80%" :close-on-click-modal="false" append-to-body>
<xm-record :visible="xmRecordVisible" :project-id="selProject.id" objType="7" :simple="1" />
</mdp-dialog>
<mdp-dialog v-else-if="xmProduct&&!selProject" :title="xmProduct==null?'操作日志':xmProduct.productName+'团队操作日志'" center v-model="xmRecordVisible" width="80%" :close-on-click-modal="false" append-to-body>
<xm-record :visible="xmRecordVisible" :product-id="xmProduct.id" objType="7" :simple="1" />
</mdp-dialog>
<mdp-dialog v-if="currNodeType=='group'&&editForm.groupName" :title="editForm.groupName+'小组进度数据查看'" center v-model="xmGroupStateVisible" fullscreen :close-on-click-modal="false" append-to-body>
<xm-group-state-mng :xm-group="editForm" :selProject="project" :visible="xmGroupStateVisible" />
</mdp-dialog>
<mdp-dialog v-else-if="selProject" :title="selProject.name+'小组进度数据查看'" center v-model="xmGroupStateVisible" fullscreen :close-on-click-modal="false" append-to-body>
<xm-group-state-mng :sel-project="project" :visible="xmGroupStateVisible" />
</mdp-dialog>
<mdp-dialog v-else-if="!selProject && xmProduct" :title="xmProduct.productName+'小组进度数据查看'" center v-model="xmGroupStateVisible" fullscreen :close-on-click-modal="false" append-to-body>
<xm-group-state-mng :xm-product="xmProduct" :visible="xmGroupStateVisible" />
<mdp-dialog v-if="project" :title="project==null?'操作日志':project.name+'团队操作日志'" center v-model="xmRecordVisible" width="80%" :close-on-click-modal="false" append-to-body>
<xm-record :visible="xmRecordVisible" :project-id="project.id" objType="7" :simple="1" />
</mdp-dialog>
<mdp-dialog ref="allGroupDlg" center fullscreen :close-on-click-modal="false" append-to-body>
<xm-group-state-mng :selProject="project" />
</mdp-dialog>
<mdp-dialog ref="oneGroupDlg" center fullscreen :close-on-click-modal="false" append-to-body>
<xm-group-state-mng :xm-group="editForm" :sel-project="project" />
</mdp-dialog>
<mdp-dialog v-if="currNodeType=='group'&&editForm.groupName" center :title="(editForm==null?editForm.groupName:'')+'小组成员管理'" v-model="groupUserVisible" width="80%" :close-on-click-modal="false" append-to-body>
<xm-group-user-mng :xm-group="editForm" :visible="groupUserVisible" />
</mdp-dialog>
@@ -344,7 +335,7 @@ XmTaskExecuserSelect,
{ name:'删除小组', command: 'del' },
{ name:'拉部门人员进组', command: 'addDeptUsers' },
{ name:'拉竞标人员进组', command: 'addHxUsers' },
{ name:'查看小组进度', command: 'showGroupState' },
{ name:'查看小组进度', command: 'showOneGroupDlg' },
]
}else if (currNodeType=='groupUser') {
return [
@@ -376,9 +367,9 @@ XmTaskExecuserSelect,
this.handleDel(formData)
}else if(command=='delGroupUser'){
this.handleDelGroupUser(formData)
}else if(command=='showGroupState'){
}else if(command=='showOneGroupDlg'){
this.editForm=formData
this.showGroupState()
this.showOneGroupDlg()
}
},
restore(){
@@ -386,6 +377,13 @@ XmTaskExecuserSelect,
},
onNodeClick(){
},
showRecord(){
if(!this.project||!this.project.id){
this.$message.warning("请先选中项目")
return;
}
this.xmRecordVisible=true
},
handleSizeChange(pageSize) {
this.pageInfo.pageSize=pageSize;
@@ -413,48 +411,33 @@ XmTaskExecuserSelect,
}
this.searchTableDatass();
},
searchXmGroups(){
debugger
this.pageInfo.count=true;
this.searchTableDatass();
},
loadNexGroup(){
var params={}
if(this.currNodeType=='branch'||this.currNodeType=='iteration'){
params.branchId=this.editForm.branchId
params.lvl=1
}else if(this.currNodeType=='project'){
params.projectId=this.editForm.id
params.lvl=1
}else if(this.currNodeType=='product'){
params.productId=this.editForm.id
params.lvl=1
}else if(this.currNodeType=='group'){
params.pgroupId=this.editForm.id
}else if(this.currNodeType=='groupUser'){
searchXmGroups(){
if(!this.project||!this.project.id){
this.$message.success("请先选中项目")
return;
}
listXmGroup(params).then((res) => {
var tips=res.tips;
if(tips.isOk){
this.pageInfo.total = res.total;
this.pageInfo.count=false;
var childrens = res.data;
childrens=childrens.filter(i=>!this.xmGroups.some(k=>k.id==i.id))
this.xmGroups.push(...childrens)
this.$notify({position:'bottom-left',showClose:true, message: tips.msg+",返回"+res.data.length+"条数据。", type: tips.isOk?'success':'error' });
}else{
this.$notify({position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
this.pageInfo.count=true;
this.searchTableDatass();
},
showAllGroupDlg(){
if(!this.project ||!this.project.id){
this.$message.success("请先选中项目")
return;
}else{
this.$refs.allGroupDlg.open({title:this.project.projectName+"项目全体小组数据对比分析"})
}
},
showOneGroupDlg(){
if(!this.editForm ||!this.editForm.id){
this.$message.success("请先选中小组")
return;
}else{
this.$refs.oneGroupDlg.open({title:this.editForm.groupName+"小组数据分析"})
}
},
//获取列表 XmGroup xm_group
searchTableDatass() {
debugger
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
@@ -468,16 +451,12 @@ XmTaskExecuserSelect,
}
params.orderBy= orderBys.join(",")
}
if( (!this.project || !this.project.id) && (!this.xmProduct || !this.xmProduct.id)){
if( (!this.project || !this.project.id)){
return;
}
if(this.project && this.project.id){
params.projectId=this.project.id
}
if(this.xmProduct && this.xmProduct.id){
params.productId=this.xmProduct.id
}
if(this.filters.groupName){
params.groupName=this.filters.groupName
}
@@ -525,31 +504,15 @@ XmTaskExecuserSelect,
this.addForm.projectId=this.project.id
this.addForm.groupName=this.project.name+"-项目管理组"
this.addFormVisible = true;
}else{
return;
}
}
if(this.xmProduct && this.xmProduct.id){
this.addForm.productId=this.xmProduct.id
}
//this.addForm=Object.assign({}, this.editForm);
},
//显示新增界面 XmGroup xm_group
showProductGroupAdd: function () {
if(!this.xmProduct || !this.xmProduct.id){
this.$notify({position:'bottom-left',showClose:true, message: "请先选择产品", type: 'warning' });
return;
}
this.addForm={...this.addFormInit}
if(this.currNodeType=='product'){
this.addForm.pgroupId=null
this.addForm.pgroupName=null
this.addForm.productId=this.xmProduct.id
this.addForm.pgClass="1"
this.addForm.groupName=this.xmProduct.productName+"-产品管理组"
this.addFormVisible = true;
}else{
return;
}
//this.addForm=Object.assign({}, this.editForm);
showProductGroupAdd: function () {
this.showProjectGroupAdd()
},
//显示新增界面 XmGroup xm_group
showAddSub: function (row) {
@@ -618,11 +581,7 @@ XmTaskExecuserSelect,
this.$notify({position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error'});
}).catch( err => this.load.del=false );
});
},
showGroupState(){
this.xmGroupStateVisible=true;
},
},
doSearchImGroupsByProjectId(){
var params={bizPid:this.selProject.id}
@@ -792,7 +751,7 @@ XmTaskExecuserSelect,
this.selectProjectVisible=false;
},
onProjectRowClick(project){
debugger
this.project=project;
this.searchXmGroups();
},

View File

@@ -50,9 +50,9 @@
<mdp-dialog
append-to-body
title="小组概览"
v-model="overviewVisible" width="80%"
v-model="overviewVisible" width="80%" fullscreen
>
<XmGroupStateOverview :xm-group-state="editForm" />
<XmGroupStateOverview v-if="overviewVisible" :xm-group-state="editForm"/>
</mdp-dialog>
@@ -76,7 +76,7 @@ export default {
'userInfo','roles'
])
},
props:['selProject','visible','xmProduct','xmGroup'],
props:['selProject','visible','xmGroup'],
watch:{
visible(visible){
if(visible==true){
@@ -106,10 +106,6 @@ export default {
params.projectId=this.selProject.id
}
if(this.xmProduct){
params.productId=this.xmProduct.id
}
if(this.xmGroup){
params.groupId=this.xmGroup.id
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@
<el-form-item :label="editForm.pgClass=='1'?'产品编号':'项目编号'" prop="pgClass">
{{editForm.projectId?editForm.projectId:''}}{{editForm.productId?editForm.productId:''}}
</el-form-item>
<el-form-item label="小组名称" prop="groupName">
<el-input v-model="editForm.groupName" placeholder="小组名称"/>
<el-form-item label="小组名称" prop="groupName">
<el-text type="primary">{{editForm.groupName}}</el-text>
</el-form-item>
<el-form-item label="组员姓名" prop="username">
<el-input v-model="editForm.username" placeholder="组员姓名"/>
@@ -19,8 +19,8 @@
<el-form-item label="排序号" prop="seqNo">
<el-input-number v-model="editForm.seqNo" :min="0" :max="200" />
</el-form-item>
<el-form-item label="原归属机构名称" prop="obranchName">
<el-input v-model="editForm.obranchName" placeholder="原归属机构名称"/>
<el-form-item label="原归属机构名称" prop="obranchName">
<MdpSelectBranch width="100%" v-model="editForm.obranchId" :init-name="editForm.obranchName"/>
</el-form-item>
<el-form-item label="加入时间" prop="joinTime">
<el-date-picker type="date" placeholder="选择日期" v-model="editForm.joinTime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD" />

View File

@@ -40,6 +40,7 @@
</el-space>
</template>
<el-space>
<XmProjectSelect v-model="filters['res.projectId']" placeholder="项目"/>
<el-input v-model="filters.groupName" style="width:15%;" clearable placeholder="小组名称查询"/>
<el-input v-model="filters.leaderUsername" style="width:15%;" clearable placeholder="组长名称查询"/>
<el-input v-model="filters.assUsername" style="width:15%;" clearable placeholder="副组长名称查询"/>
@@ -100,6 +101,7 @@
import XmGroupUserEdit from './XmGroupUserEdit.vue';//新增修改界面
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import XmProjectSelect from '@/views/xm/core/components/XmProjectSelect.vue';
import { MdpTableMixin } from '@/components/mdp-ui/mixin/MdpTableMixin.js'
@@ -107,7 +109,7 @@ import { MdpTableMixin } from '@/components/mdp-ui/mixin/MdpTableMixin.js'
mixins:[MdpTableMixin],
name:'xmGroupUserMng',
components: {
XmGroupUserEdit,
XmGroupUserEdit,XmProjectSelect
},
props:['visible','xmGroup'],
computed: {

View File

@@ -44,7 +44,7 @@
<el-menu-item :index="'/xm/iteration/view/group?iterationId='+xmIteration.id">
<template #title><i class="user-solid"></i>团队</template>
</el-menu-item>
<el-menu-item :index="'/xm/iteration/view/rpt?iterationId='+xmIteration.id">
<el-menu-item :index="'/xm/pro/iteration/view/rpt?iterationId='+xmIteration.id">
<template #title><i class="s-data"></i>效能</template>
</el-menu-item>
<el-sub-menu index="更多">
@@ -52,7 +52,7 @@
<el-menu-item :index="'/xm/iteration/view/workloadDay?iterationId='+xmIteration.id">
<template #title><i class="video-camera"></i>每日工时</template>
</el-menu-item>
<el-menu-item :index="'/xm/iteration/view/workloadMonth?iterationId='+xmIteration.id">
<el-menu-item :index="'/xm/pro/iteration/view/workloadMonth?iterationId='+xmIteration.id">
<template #title
><i class="video-camera"></i>每月工时</template
>

View File

@@ -18,6 +18,7 @@
@check-change="(d,c,i)=>$emit('check-change',d,c,i)"
@node-click="(d,n,c)=>$emit('node-click',d,n,c)"
rootId="0"
:draggable="true"
>
<template #topToolbar>
<xm-product-select width="300px"
@@ -78,14 +79,6 @@
/>
</template>
</mdp-dialog>
<mdp-dialog append-to-body width="60%" top="20px" ref="parentDialog">
<template #default="{data,dialog}">
<XmEpicFeaturesSelect showConfirm subOpType="select"
:xm-product="xmProduct ? xmProduct : product"
@confirm="(menu)=>{onParentMenuSelected(menu,data.checkKeys,data.callback);dialog.close()}"
/>
</template>
</mdp-dialog>
</template>
<script>
@@ -108,10 +101,7 @@ import { useUserStore } from '@/store/modules/user'
// 在 Vue 3 中,可以使用 defineAsyncComponent 方法来创建异步组件
import { defineAsyncComponent } from 'vue';
// 创建一个异步组件它会从一个外部API动态导入组件
const XmEpicFeaturesSelect = defineAsyncComponent(() =>
import('./XmEpicFeatures.vue') // 假设LazyComponent.vue是你想要懒加载的组件
);
// 创建一个异步组件它会从一个外部API动态导入组件
const XmMenuAdd = defineAsyncComponent(() =>
import('./XmMenuAdd.vue') // 假设LazyComponent.vue是你想要懒加载的组件
@@ -260,8 +250,22 @@ export default {
callback: callback
})
},
onChangePidClick: function(checkKeys,callback){
this.$refs['parentDialog'].open({callback:callback,checkKeys:checkKeys})
onChangePidClick: function(idLinks,callback){
batchChangeParentMenu(idLinks).then(res=>{
let {tips}=res
if(tips.isOk){
if(callback){
callback(true)
}
this.$message.success(tips.msg)
}else{
this.$message.error(tips.msg)
}
})
},
onProductSelected: function (product) {
@@ -386,48 +390,12 @@ export default {
})
})
.catch((err) => (this.load.edit = false))
},
onParentMenuSelected(menu,checkKeys,callback) {
if (!menu || !menu.menuId) {
this.$notify({
position: 'bottom-left',
showClose: true,
message: '请先选择一个上级需求',
type: 'warning'
})
return
}
if (menu.dclass != '1') {
this.$notify({
position: 'bottom-left',
showClose: true,
message: menu.menuName + '是特性,不能作为上级,请选择史诗作为上级',
type: 'warning'
})
return
}
var params = {
menuIds: checkKeys,
pmenuId: menu.menuId
}
batchChangeParentMenu(params).then((res) => {
var tips = res.tips
if (tips.isOk) {
this.$refs['nodeTree'].refresh()
}
this.$notify({
position: 'bottom-left',
showClose: true,
message: tips.msg,
type: tips.isOk ? 'success' : 'error'
})
})
},
},
}, //end methods
components: {
'xm-menu-add': XmMenuAdd,
'xm-menu-edit': XmMenuEdit,
XmProductSelect,XmEpicFeaturesSelect
XmProductSelect
//在下面添加其它组件
},
mounted() {

View File

@@ -117,11 +117,11 @@
</mdp-field>
</el-col>
<el-col :span="8">
<mdp-select-user show-style="x" label="负责人" v-model="editForm.mmUserid"
<mdp-select-user show-style="x" label="负责人" v-model="editForm.mmUserid" :init-name="editForm.mmUsername"
@change2="editSomeFields(editForm, 'mmUserid', $event)" />
</el-col>
<el-col :span="8">
<mdp-select-user show-style="x" label="提出人" v-model="editForm.proposerId"
<mdp-select-user show-style="x" label="提出人" v-model="editForm.proposerId" :init-name="editForm.proposerName"
@change2="editSomeFields(editForm, 'proposerId', $event)" />
</el-col>
</el-row>
@@ -216,24 +216,23 @@
placeholder="什么人?做什么事?,为什么?如: 作为招聘专员,我需要统计员工半年在职/离职人数,以便我能够制定招聘计划" />
</el-form-item>
</el-tab-pane>
<el-tab-pane :label="'任务( ' + (subWorkitemCpd ? subWorkitemCpd : 0) + ' )'" name="64" v-if="editForm.dclass=='3'">
<el-tab-pane :label="'任务( ' + (editForm.taskCnt||0) + ' )'" name="64" v-if="editForm.dclass=='3'">
<XmTaskMng v-if="activateTabPaneName == '64'" :xm-product="{id:editForm.productId,productName:editForm.productName}"
:selProject="selProject" @loadDatas="setSubWorkItemNum"
:selProject="selProject"
@add-submit="onAddSubMenu" :menuId="editForm.menuId"/>
</el-tab-pane>
<el-tab-pane :label="'子项( ' + (subWorkitemCpd ? subWorkitemCpd : 0) + ' )'" name="64" v-if="editForm.dclass<'3'">
<el-tab-pane :label="'子项( ' + (editForm.childrenCnt||0) + ' )'" name="64" v-if="editForm.dclass<'3'">
<XmMenuMng v-if="activateTabPaneName == '64'" :parent-menu="editForm"
:xm-product="{id:editForm.productId,productName:editForm.productName}"
@loadDatas="setSubWorkItemNum"
:xm-product="{id:editForm.productId,productName:editForm.productName}"
@add-submit="onAddSubMenu" />
</el-tab-pane>
<el-tab-pane :label="'缺陷(' + (editForm.bugCnt ? editForm.bugCnt : 0) + ')'" name="63">
<el-tab-pane :label="'缺陷(' + (editForm.bugCnt||0) + ')'" name="63">
<xm-question-mng v-if="activateTabPaneName == '63'"
:xm-product="editForm.productId ? { id: editForm.productId, productName: editForm.productName } : null"
:xm-menu="editForm" />
</el-tab-pane>
<el-tab-pane :label="'测试用例(' + (editForm.testCases ? editForm.testCases : 0) + ')'" name="62">
<el-tab-pane :label="'测试用例(' + (editForm.testCases|| 0) + ')'" name="62">
<xm-test-case-mng v-if="activateTabPaneName == '62'"
:xm-product="{ id: editForm.productId, productName: editForm.productName }" :xm-menu="editForm" />
</el-tab-pane>
@@ -352,22 +351,7 @@ import { MdpFormMixin } from '@/components/mdp-ui/mixin/MdpFormMixin';
}
return params;
},
subWorkitemCpd() {
if (this.subWorkItemNum > 0) {
return this.subWorkItemNum
} else {
if (this.editForm.dclass == '3') {
var taskCnt = 0;
if (this.editForm.taskCnt) {
taskCnt = parseInt(this.editForm.taskCnt)
}
return taskCnt;
} else {
return this.editForm.childrenCnt
}
}
}
},
props: ['xmMenu', 'visible', 'parentMenu', 'product', 'dclass', 'selProject', 'reload'],
watch: {
@@ -375,8 +359,7 @@ import { MdpFormMixin } from '@/components/mdp-ui/mixin/MdpFormMixin';
//this.editForm = {...xmMenu};
},
'visible': function (visible) {
if (visible == true) {
this.subWorkItemNum = 0;
if (visible == true) {
if (this.reload == true) {
this.searchXmMenus();
} else {
@@ -442,8 +425,7 @@ import { MdpFormMixin } from '@/components/mdp-ui/mixin/MdpFormMixin';
menuStatus: [
]
},
tagSelectVisible: false,
subWorkItemNum: -1,
tagSelectVisible: false,
activateTabPaneName: '4',
pmenuFormVisible: false,
parentMenuVisible: false,
@@ -457,10 +439,7 @@ import { MdpFormMixin } from '@/components/mdp-ui/mixin/MdpFormMixin';
/**end 在上面加自定义属性**/
}//end return
},//end data
methods: {
setSubWorkItemNum(val) {
this.subWorkItemNum = val.total;
},
methods: {
// 取消按钮点击 父组件监听@cancel="editFormVisible=false" 监听
handleCancel: function () {
this.$emit('cancel');

View File

@@ -901,10 +901,7 @@ export default {
})
return
}
var params = {
menuIds: this.sels.map((i) => i.menuId),
pmenuId: menu.menuId
}
var params = this.sels.map((i) => { return {menuId:i.menuId,pmenuId:menu.menuId}})
batchChangeParentMenu(params).then((res) => {
var tips = res.tips
if (tips.isOk) {

View File

@@ -56,17 +56,17 @@
</el-menu-item>
<el-sub-menu index="caiwu" class="hidden-sm-and-down">
<template #title><i class="coin"></i>财务</template>
<el-menu-item :index="'/xm/product/view/contract?productId='+xmProduct.id">
<el-menu-item :index="'/xm/pro/product/view/contract?productId='+xmProduct.id">
<template #title><i class="s-data"></i>合同管理</template>
</el-menu-item>
<el-menu-item :index="'/xm/product/view/budget?productId='+xmProduct.id">
<el-menu-item :index="'/xm/pro/product/view/budget?productId='+xmProduct.id">
<template #title><i class="coin"></i>预算</template>
</el-menu-item>
<el-menu-item :index="'/xm/product/view/cost?productId='+xmProduct.id">
<el-menu-item :index="'/xm/pro/product/view/cost?productId='+xmProduct.id">
<template #title><i class="coin"></i>费用</template>
</el-menu-item>
</el-sub-menu>
<el-menu-item :index="'/xm/product/view/rpt?productId='+xmProduct.id">
<el-menu-item :index="'/xm/pro/product/view/rpt?productId='+xmProduct.id">
<template #title><i class="s-data"></i>效能</template>
</el-menu-item>
<el-sub-menu index="zhishi" class="hidden-md-and-down">
@@ -88,7 +88,7 @@
><i class="video-camera"></i>每日工时</template
>
</el-menu-item>
<el-menu-item :index="'/xm/product/view/workloadMonth?productId='+xmProduct.id">
<el-menu-item :index="'/xm/pro/product/view/workloadMonth?productId='+xmProduct.id">
<template #title
><i class="video-camera"></i>每月工时</template
>

View File

@@ -58,17 +58,17 @@
</el-menu-item>
<el-sub-menu index="caiwu" class="hidden-sm-and-down">
<template #title><i class="coin"></i>财务</template>
<el-menu-item :index="'/xm/project/view/contract?projectId='+projectInfo.id">
<el-menu-item :index="'/xm/pro/project/view/contract?projectId='+projectInfo.id">
<template #title><i class="s-data"></i>合同管理</template>
</el-menu-item>
<el-menu-item :index="'/xm/project/view/budget?projectId='+projectInfo.id">
<el-menu-item :index="'/xm/pro/project/view/budget?projectId='+projectInfo.id">
<template #title><i class="coin"></i>预算</template>
</el-menu-item>
<el-menu-item :index="'/xm/project/view/cost?projectId='+projectInfo.id">
<el-menu-item :index="'/xm/pro/project/view/cost?projectId='+projectInfo.id">
<template #title><i class="coin"></i>费用</template>
</el-menu-item>
</el-sub-menu>
<el-menu-item :index="'/xm/project/view/rpt?projectId='+projectInfo.id">
<el-menu-item :index="'/xm/pro/project/view/rpt?projectId='+projectInfo.id">
<template #title><i class="s-data"></i>效能</template>
</el-menu-item>
<el-sub-menu index="zhishi" class="hidden-md-and-down">
@@ -90,7 +90,7 @@
><i class="video-camera"></i>每日工时</template
>
</el-menu-item>
<el-menu-item :index="'/xm/project/view/workloadMonth?projectId='+projectInfo.id">
<el-menu-item :index="'/xm/pro/project/view/workloadMonth?projectId='+projectInfo.id">
<template #title
><i class="video-camera"></i>每月工时</template
>

View File

@@ -58,7 +58,7 @@
<el-row>
<el-col :span="6">
<el-form-item>
<mdp-select-user show-style="x" size="medium" label="责任人" v-model="editForm.handlerUserid"
<mdp-select-user show-style="x" size="medium" label="责任人" v-model="editForm.handlerUserid" :init-name="editForm.handlerUsername"
@change="editSomeFields(editForm, 'handlerUserid', $event)">
<template #extOpe>
指派给 <el-button type="text" @click="sendToAsk"> 提出人</el-button> <el-button type="text"

View File

@@ -102,7 +102,7 @@
</el-table-column>
<el-table-column prop="tagNames" label="标签" width="120" show-overflow-tooltip>
<template #default="scope">
<MdpSelectTag showStyle="tag" multiple v-model="scope.row.tagIds" @change2="editSomeFields(scope.row,'tagIds',$event)"/>
<MdpSelectTag showStyle="tag" multiple v-model="scope.row.tagIds" :init-name="scope.row.tagNames" @change2="editSomeFields(scope.row,'tagIds',$event)"/>
</template>
</el-table-column>
<el-table-column prop="menuName" label="需求" width="120" show-overflow-tooltip />
@@ -432,7 +432,7 @@ import { MdpTableMixin } from '@/components/mdp-ui/mixin/MdpTableMixin.js';
return msg;
},
editSomeFieldsCheck(row,fieldName,$event,params){
debugger
if(fieldName==='handlerUserid'){
if($event){
params[fieldName]=$event.userid;

View File

@@ -18,6 +18,7 @@
@check-change="(d,c,i)=>$emit('check-change',d,c,i)"
@node-click="(d,n,c)=>$emit('node-click',d,n,c)"
rootId="0"
:draggable="true"
>
<template #topToolbar>
<xm-project-select width="300px"
@@ -63,7 +64,7 @@
@cancel="dialog.close()"
@submit="data.callback"
@add-sub-task="data.addSubCallback"
@edit-fields="data.callback"
@fields-change="(res,isOk,params,row)=>data.callback(row)"
/>
</template>
</mdp-dialog>
@@ -172,7 +173,7 @@ export default {
project:null,
props:{
id: 'id', pid: 'parentTaskid', label: 'name' ,
isLeaf:(n)=>{
isLeaf:(n,node)=>{
return n.subPlanCnt<=0||n.childrenCnt<=0
}
}
@@ -219,7 +220,7 @@ export default {
},
//显示新增界面 XmTask xm_project_menu
onAddTopClick: function (callback) {
debugger
let ntype = '1'
var parentTask = null
var formData = {}
@@ -277,8 +278,18 @@ export default {
callback: callback
})
},
onChangePidClick: function(checkKeys,callback){
this.$refs['parentDialog'].open({callback:callback,checkKeys:checkKeys})
onChangePidClick: function(idLinks,callback){
batchChangeParentTask(idLinks).then(res=>{
let {tips}=res
if(tips.isOk){
if(callback){
callback(true)
}
this.$message.success(tips.msg)
}else{
this.$message.error(tips.msg)
}
})
},
onProjectSelected: function (project) {

View File

@@ -170,15 +170,15 @@
</el-col>
<el-col :span="8">
<el-form-item>
<mdp-select-user show-style="x" label="负责人" v-model="editForm.createUserid" @change2="editSomeFields(editForm,'createUserid',$event)"/>
<mdp-select-user show-style="x" label="负责人" v-model="editForm.createUserid" @change2="editSomeFields(editForm,'createUserid',$event)" :init-name="editForm.createUsername"/>
</el-form-item>
</el-col>
<el-col :span="8" v-if="editForm.ntype=='0'">
<el-form-item>
<mdp-select-user show-style="x" v-if="editForm.crowd=='1'" label="执行人" v-model="editForm.executorUserid">
<mdp-select-user show-style="x" v-if="editForm.crowd=='1'" label="执行人" v-model="editForm.executorUserid" :init-name="editForm.executorUsername">
<template #oper><el-button @click="activateTabPaneName='42'">去管理竞标人</el-button></template>
</mdp-select-user>
<mdp-select-user show-style="x" v-if="editForm.crowd!='1'" label="执行人" v-model="editForm.executorUserid" @change2="editSomeFields(editForm,'executorUserid',$event)"/>
<mdp-select-user show-style="x" v-if="editForm.crowd!='1'" label="执行人" v-model="editForm.executorUserid" :init-name="editForm.executorUsername" @change2="editSomeFields(editForm,'executorUserid',$event)"/>
</el-form-item>
</el-col>
<el-col :span="8">
@@ -323,11 +323,11 @@
</el-form-item>
</el-tab-pane>
<el-tab-pane :label="'子计划('+(subPlanNumCpd||0)+')'" name="45" v-if="editForm.ntype==='1'">
<XmTaskMng v-if="activateTabPaneName=='45'" :parent-task="editForm" @loadDatas="setSubPlanNum" @add-submit="onAddSubTask" queryScope="plan"/>
<el-tab-pane :label="'子计划('+(editForm.subPlanCnt||0)+')'" name="45" v-if="editForm.ntype==='1'">
<XmTaskMng v-if="activateTabPaneName=='45'" :parent-task="editForm" @add-submit="onAddSubTask" queryScope="plan"/>
</el-tab-pane>
<el-tab-pane :label="'子任务('+ (subWorkItemNumCpd||0) +')'" name="46" v-if="editForm.ntype==='1'">
<XmTaskMng v-if="activateTabPaneName=='46'" :parent-task="editForm" @loadDatas="setSubWorkItemNum" @add-submit="onAddSubTask" queryScope="task"/>
<el-tab-pane :label="'子任务('+ (editForm.subTaskCnt||0) +')'" name="46" v-if="editForm.ntype==='1'">
<XmTaskMng v-if="activateTabPaneName=='46'" :parent-task="editForm" @add-submit="onAddSubTask" queryScope="task"/>
</el-tab-pane>
<el-tab-pane label="缺陷" name="41" v-if="editForm.ntype!='1'">
<xm-question-mng v-if="activateTabPaneName=='41' && editForm.menuId" :xm-product="editForm.productId?{id:editForm.productId,productName:editForm.productName}:null" :xm-menu="editForm.menuId?{menuId:editForm.menuId,menuName:editForm.menuName}:null" :sel-project="xmProject" />
@@ -658,32 +658,7 @@ import { MdpFormMixin } from '@/components/mdp-ui/mixin/MdpFormMixin';
}
toPayAtObj.total=toPayAt;
return toPayAtObj;
},
subWorkItemNumCpd(){
if(this.subWorkItemNum>0){
return this.subWorkItemNum
}else{
if(this.editForm.ntype=='1'){
return this.editForm.childrenCnt
}else{
return this.subWorkItemNum
}
}
},
subPlanNumCpd(){
if(this.subPlanNum>0){
return this.subPlanNum
}else{
if(this.editForm.ntype=='1'){
return this.editForm.childrenCnt
}else{
return this.subPlanNum
}
}
},
},
xmProjectCpd(){
if(this.xmProject && this.xmProject.id){
return this.xmProject
@@ -783,14 +758,7 @@ import { MdpFormMixin } from '@/components/mdp-ui/mixin/MdpFormMixin';
}//end return
},//end data
methods: {
...util,
setSubWorkItemNum(val){
this.subWorkItemNum=val.total;
},
setSubPlanNum(val){
this.subPlanNum=val.total;
},
...util,
// 取消按钮点击 父组件监听@cancel="editFormVisible=false" 监听
handleCancel:function(){
this.$emit('cancel');

View File

@@ -90,7 +90,7 @@
</el-space>
</ContentWrap>
<el-table element-loading-text="努力加载中" element-loading-spinner="loading" :data="tableDatas"
<el-table ref="table" element-loading-text="努力加载中" element-loading-spinner="loading" :data="tableDatas"
@sort-change="sortChange" v-loading="load.list" @row-click="rowClick" @selection-change="selsChange"
highlight-current-row current-row-key="id" stripe fit border tooltip-effect="light" v-adaptive="{ bottom: 50 }"
row-key="id">
@@ -118,15 +118,25 @@
</el-table-column>
<el-table-column sortable prop="rate" label="进度" width="120">
<template #default="scope">
<el-link v-if="scope.row.ntype == '0'" style="border-radius: 30px"
:type="scope.row.rate >= 100 ? 'success' : 'warning'" @click="showWorkload(scope.row)">
{{ (scope.row.rate != null ? scope.row.rate : 0) + "%" }}
</el-link>
<el-link v-else style="border-radius: 30px" :type="scope.row.rate >= 100 ? 'success' : 'warning'"
@click="calcProgress(scope.row)">
{{ (scope.row.rate != null ? scope.row.rate : 0) + "%" }}
</el-link>
<MdpField>
<template #info>
<el-link
:type="scope.row.rate >= 100 ? 'success' : 'warning'">
{{ (scope.row.rate != null ? scope.row.rate : 0) + "%" }}
</el-link>
</template>
<template #oper>
<el-button type="primary" @click="showWorkload(scope.row)" v-if="scope.row.ntype=='0'" plain>
报工
</el-button>
<el-button type="primary" @click="calcProgress(scope.row)" v-if="scope.row.ntype>'0'" plain title="注意仅统计当前计划及上级所有计划的进度情况,不对子计划进行统计">
统计进度
</el-button>
</template>
</MdpField>
</template>
</el-table-column>
<el-table-column sortable prop="createUsername" label="负责人" min-width="120" >
@@ -192,6 +202,11 @@
{{ scope.row.menuName||scope.row.menuId }}
</template>
</el-table-column>
<el-table-column prop="id" label="编号" width="80" show-overflow-tooltip/>
<el-table-column prop="preTaskid" label="前置任务编号" width="80" show-overflow-tooltip/>
<el-table-column prop="pidPaths" label="路径" width="80" show-overflow-tooltip/>
<el-table-column prop="parentTaskid" label="上级编号" width="80" show-overflow-tooltip/>
<el-table-column prop="parentTaskname" label="上级名称" width="80" show-overflow-tooltip/>
<template v-if="currOpType=='select' && multiple!=true">
<el-table-column label="操作" width="120" fixed="right">
<template #default="scope">
@@ -220,22 +235,30 @@
</template>
</mdp-dialog>
<mdp-dialog ref="workloadInitDlg" width="600px" append-to-body>
<mdp-dialog ref="workloadInitDlg" width="600px" append-to-body title="更新预估工作量">
<el-form class="padding" ref="workloadInit" :model="editForm" label-position="top" label-width="80px" >
<el-form-item label="更新范围">
<div v-if="sels.length == 0">
<el-text type="primary" v-if="sels.length == 0">
{{ editForm.name }}
</div>
<div v-if="sels.length > 0">
{{ editForm.name }} <font color="red">{{ sels.length }}个任务</font>
</div>
</el-text>
<el-text v-if="sels.length > 0">
{{ editForm.name }} {{ sels.length }}个计划/任务
</el-text>
</el-form-item>
<el-form-item label="预估工时(小时)">
<el-input style="width:50%;" v-model="editForm.budgetWorkload"
@change="editSomeFields(editForm, 'budgetWorkload', $event)" />
<el-input v-model="editForm.budgetWorkload" type="number">
<template #suffix>
小时
</template>
</el-input>
<el-text type="danger">注意更新范围内的计划/任务的预估工时都会被更新为 {{editForm.budgetWorkload}}小时</el-text>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="Object.assign(editForm,dataBak);$refs['workloadInitDlg'].close()">取消</el-button>
<el-button @click="editSomeFields(editForm, 'budgetWorkload', $event)">确定</el-button>
</template>
</mdp-dialog>
<!-- 新增 XmTask xm_task界面-->
<mdp-dialog class="XmTaskAdd" title="新增任务" v-model="addFormVisible" width="90%" top="20px" append-to-body
@@ -685,7 +708,7 @@ export default {
this.menuVisible = false;
},
onTaskTemplatesSelected(taskTemplates) {
debugger
if (taskTemplates == null || taskTemplates.length == 0) {
this.taskTemplateVisible = false;
return;
@@ -1119,7 +1142,7 @@ export default {
return;
}
var params = { taskIds: this.sels.map(i => i.id), parentTaskid: task.id }
var params = this.sels.map(i =>{ return {id:i.id,parentTaskid: task.id}})
this.$confirm("确认批量更新以下" + this.sels.length + "个任务的上级为【" + task.name + "】吗?", "提示", {
type: "warning",
}).then(() => {
@@ -1175,50 +1198,4 @@ export default {
},
};
</script>
<style lang="scss" scoped> .extra {
border-bottom: 1px solid #dedede;
padding: 8px;
}
.field-label {
display: inline-block;
width: 60px;
font-size: 12px;
font-weight: bold;
}
.task-header {
border-top: 1px solid #dedede;
}
.title {
font-size: 18px;
font-weight: bold;
line-height: 36px;
}
.compact {
font-size: 12px;
color: #8c92a4;
}
.compact>span {
color: #00b2f3;
}
.remarks {
margin-top: 10px;
font-size: 16px;
overflow-x: auto;
overflow-y: hidden;
}
>>>.el-date-editor--daterange.el-input,
.el-date-editor--daterange.el-input__inner,
.el-date-editor--timerange.el-input,
.el-date-editor--timerange.el-input__inner {
width: 250px;
}
</style>

View File

@@ -34,7 +34,7 @@
<el-menu-item :index="'/xm/test/view/env?casedbId='+testCasedb.id">
<template #title><i class="setting"></i>环境变量</template>
</el-menu-item>
<el-menu-item :index="'/xm/test/view/rpt?casedbId='+testCasedb.id">
<el-menu-item :index="'/xm/pro/test/view/rpt?casedbId='+testCasedb.id">
<template #title><i class="time"></i>统计分析</template>
</el-menu-item>

View File

@@ -129,7 +129,7 @@ export default {
methods: {
initCurrData: function () {
debugger
this.editForm=this.xmTestPlan
},

View File

@@ -1,6 +1,5 @@
<template>
<el-row class="padding" ref="table">
<el-row class="row_1" style="margin-bottom:20px;">
<div class="r r1">
<span style="color: #4779F6">{{formatNum(xmBranch.projectCnt,0) || 0}}</span>
@@ -64,8 +63,8 @@
<el-row style="margin-bottom:20px">
<el-col :span="8">
<div class="item">
<div class="icon1" style="background-color: rgb(79, 140, 255);">
<i class="right"></i>
<div class="icon1" style="background-color: rgb(79, 140, 255);">
<icon icon="ep:right"/>
</div>
<div class="info">
<div v-text="totalTask" ></div>
@@ -77,6 +76,7 @@
<div class="item">
<div class="icon1" style="background-color: rgb(255, 153, 51);">
<i class="loading"></i>
<icon icon="ep:right"/>
</div>
<div class="info">
<div v-text="notStart" ></div>
@@ -88,6 +88,7 @@
<div class="item">
<div class="icon1" style="background-color: rgb(0, 153, 51);">
<i class="check"></i>
<icon icon="ep:right"/>
</div>
<div class="info">
<div v-text="competeTasks" ></div>
@@ -100,17 +101,17 @@
<div class="item">
<div class="icon2" style="background-color: rgb(204, 204, 204);">
<i class="date"></i>
<icon icon="ep:calendar"/>
</div>
<div class="info">
<div v-text="xmBranch.calcTime" ></div>
<div class="title">企业数据更新日期</div>
<div class="info">
<div class="title">更新日期 {{ xmBranch.calcTime }} </div>
</div>
</div>
</el-row>
<el-row style="margin-bottom:20px">
<div class="item">
<div class="icon2" style="background-color: rgb(204, 204, 204);">
<i class="star-off"></i>
<div class="icon2" style="background-color: rgb(204, 204, 204);">
<icon icon="ep:star"/>
</div>
<div class="info">
<div class="title"> 需求数 {{this.xmBranch.menuCnt||0}}</div>
@@ -119,8 +120,8 @@
</el-row>
<el-row style="margin-bottom:20px">
<div class="item">
<div class="icon2" style="background-color: rgb(204, 204, 204);">
<i class="alarm-clock"></i>
<div class="icon2" style="background-color: rgb(204, 204, 204);">
<icon icon="ep:clock"/>
</div>
<div>
<div class="progress-item">
@@ -156,76 +157,70 @@
<div id="iterationAndProduct" :style="{width: '100%', height: '350px'}" ></div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" style="margin-bottom:10px">
</el-col>
<el-col :span="16" >
<el-card class="box-card" style="padding:0px ;height:425px">
<template #header>
<span>企业工时</span>
</template >
<div>
<el-row >
<div class="item">
<el-row class="item">
<el-col :span="8">
<div>
<div style="text-align:center;">
<span style="font-size:24px;" v-text="this.xmBranch.budgetWorkload" ></span>
<span style="font-size:5px;">h</span>
<span style="font-size:14px;">h</span>
</div>
<div style="text-align:center;font-size:5px;">总估工时</div>
<div style="text-align:center;font-size:14px;">总估工时</div>
</div>
</el-col>
<el-col :span="8">
<div>
<div style="text-align:center;">
<span style="font-size:24px;" v-text="this.xmBranch.estimateWorkload" ></span>
<span style="font-size:5px;">h</span>
<span style="font-size:14px;">h</span>
</div>
<div style="text-align:center;font-size:5px;">应完成工时</div>
<div style="text-align:center;font-size:14px;">应完成工时</div>
</div>
</el-col>
<el-col :span="8">
<div>
<div style="text-align:center;">
<span style="font-size:24px;" v-text="this.xmBranch.actWorkload" ></span>
<span style="font-size:5px;">h</span>
<span style="font-size:14px;">h</span>
</div>
<div style="text-align:center;font-size:5px;" title="已登记的工时">已完成工时</div>
<div style="text-align:center;font-size:14px;" title="已登记的工时">已完成工时</div>
</div>
</el-col>
</div>
</el-col>
</el-row>
<el-row >
<div class="item">
<el-row class="item">
<el-col :span="8">
<div title="总估工时-已完成工时">
<div style="text-align:center;">
<span style="font-size:24px;" v-text="remainWorkload" ></span>
<span style="font-size:5px;">h</span>
<span style="font-size:14px;">h</span>
</div>
<div style="text-align:center;font-size:5px;">剩余工时</div>
<div style="text-align:center;font-size:14px;">剩余工时</div>
</div>
</el-col>
<el-col :span="8">
<div title="已完成工时-当前应完成工时">
<div style="text-align:center;">
<span style="font-size:24px;" v-text="deviation" ></span>
<span style="font-size:5px;">h</span>
<span style="font-size:14px;">h</span>
</div>
<div style="text-align:center;font-size:5px;">预估偏差</div>
<div style="text-align:center;font-size:14px;">预估偏差</div>
</div>
</el-col>
<el-col :span="8">
<div title="(已完成工时-当前应完成工时)/ 当前应完成工时">
<div style="text-align:center;">
<span style="font-size:24px;" v-text="deviationRate" ></span>
<span style="font-size:5px;">%</span>
<span style="font-size:14px;">%</span>
</div>
<div style="text-align:center;font-size:5px;">预估偏差率</div>
<div style="text-align:center;font-size:14px;">预估偏差率</div>
</div>
</el-col>
</div>
</el-col>
</el-row>
<el-row>
<span style="margin-left:20px;" title="应完成工时/总预估工时">预计进度</span>
@@ -248,9 +243,7 @@
<div id="workloadDistribution" :style="{width: '100%', height: '320px'}" ></div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" style="margin-bottom:10px">
</el-col>
<el-col :span="8" >
<el-card class="box-card" style="height:425px">
<template #header>
@@ -281,10 +274,7 @@
<div id="taskChart" :style="{width: '100%', height: '350px'}" ></div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" style="margin-bottom:10px">
</el-col>
<el-col :span="8" >
<el-card class="box-card" style="height:425px">
<template #header>
@@ -307,7 +297,6 @@
</el-card>
</el-col>
</el-row>
</el-row>
</template>

View File

@@ -0,0 +1,458 @@
<template>
<ContentWrap>
<el-space wrap>
<MdpSelectDept v-model="filters.costCenterId" placeholder="成本中心" title="成本中心"/>
<XmProjectSelect v-model="filters.projectId" v-if="!projectInfo?.id" :link-product-id="xmProduct?.id" @change2="project=$event" @clear="project=null"/>
<MdpSelect title="分组统计" split="," v-model="filters.groupBy" :options="[{id:'cost_center_id',name:'成本中心'},{id:'project_id',name:'项目'},{id:'userid',name:'用户'},{id:'subject_id',name:'资金用途(科目)'},{id:'biz_month',name:'支出月份'},{id:'task_id',name:'任务'},{id:'biz_flow_state',name:'审核状态'}]" multiple placeholder="分组"/>
<mdp-date-range start-key="startBizMonth" end-key="endBizMonth" type="monthrange" v-model="filters" value-format="YYYY-MM" format="YYYY-MM" placeholder="统计时间" :clearable="false" />
<el-checkbox v-model="chartShow">图表</el-checkbox>
<el-checkbox v-model="filters.budgetCost" true-label="1" false-label="">预算/实际比对</el-checkbox>
<el-button @click="doSearch" icon="search" plain/>
</el-space>
</ContentWrap>
<el-scrollbar v-adaptive>
<div v-if="chartShow" class="row-box">
<XmBudgetCostMonthTrend :showParams="false" :showTitle="false" :rptDatas="rptDatas" :cfg="echartRptCfg" class="echart-box" :baseView="baseView" :budgetCost="filters.budgetCost" :id="id" :key="id"/>
</div>
<el-table
:data="sumXmBudgeCostConvert"
highlight-current-row
v-loading="load.list"
border >
<el-table-column prop="costCenterId" label="成本中心" min-width="150" v-if="filters.groupBy.indexOf('cost_center_id')>=0">
<template #default="scope">
<MdpField>
<template #info>
{{scope.row.costCenterId}}
</template>
<template #oper>
<el-space wrap>
<el-button v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'costCenterId')">预算</el-button>
<el-button v-if="costShow" @click="showXmCostRecordDetails(scope.row,'costCenterId')">成本</el-button>
</el-space>
</template>
</MdpField>
</template>
</el-table-column>
<el-table-column prop="projectId" label="项目编号" min-width="150" v-if="filters.groupBy.indexOf('project_id')>=0">
<template #default="scope">
<MdpField>
<template #info>
{{scope.row.projectId}}
</template>
<template #oper>
<el-space wrap>
<el-button v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'projectId')">预算</el-button>
<el-button v-if="costShow" @click="showXmCostRecordDetails(scope.row,'projectId')">成本</el-button>
</el-space>
</template>
</MdpField>
</template>
</el-table-column>
<el-table-column prop="subjectId" label="科目" min-width="100" v-if="filters.groupBy.indexOf('subject_id')>=0">
<template #default="scope">
<MdpField>
<template #info>
<MdpSelect showStyle="tag" v-model="scope.row.subjectId" itemCode="projectSubject" disabled/>
</template>
<template #oper>
<el-space wrap>
<el-button v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'subjectId')">预算</el-button>
<el-button v-if="costShow" @click="showXmCostRecordDetails(scope.row,'subjectId')">成本</el-button>
</el-space>
</template>
</MdpField>
</template>
</el-table-column>
<el-table-column prop="bizFlowState" label="状态" min-width="100" v-if="filters.groupBy.indexOf('biz_flow_state')>=0">
<template #default="scope">
<MdpField>
<template #info>
<MdpSelect showStyle="tag" v-model="scope.row.bizFlowState" itemCode="bizFlowState" disabled/>
</template>
<template #oper>
<el-space wrap>
<el-button v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'bizFlowState')">预算</el-button>
<el-button v-if="costShow" @click="showXmCostRecordDetails(scope.row,'bizFlowState')">成本</el-button>
</el-space>
</template>
</MdpField>
</template>
</el-table-column>
<el-table-column prop="userid" label="姓名" min-width="100" v-if="filters.groupBy.indexOf('userid')>=0">
<template #default="scope">
<MdpField>
<template #info>
{{scope.row.username||scope.row.userid}}
</template>
<template #oper>
<el-space wrap>
<el-button v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'userid')">预算</el-button>
<el-button v-if="costShow" @click="showXmCostRecordDetails(scope.row,'userid')">成本</el-button>
</el-space>
</template>
</MdpField>
</template>
</el-table-column>
<el-table-column prop="taskId" label="任务编号" min-width="100" v-if="filters.groupBy.indexOf('task_id')>=0">
<template #default="scope">
<MdpField>
<template #info>
{{scope.row.taskId}}
</template>
<template #oper>
<el-space wrap>
<el-button v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'taskId')">预算</el-button>
<el-button v-if="costShow" @click="showXmCostRecordDetails(scope.row,'taskId')">成本</el-button>
</el-space>
</template>
</MdpField>
</template>
</el-table-column>
<!-- <el-table-column min-width="100" /> -->
<el-table-column :prop="month" v-for="month in selYearMonths" :key="month" :label="month" width="120">
<template #default="scope">
<el-space wrap fill>
<el-link v-if="budgetShow" @click="showXmBudgetRecordDetails(scope.row,'bizMonth',month)">{{$mdp.toFixed(scope.row["budget"+month],2)}}</el-link>
<el-link v-if="costShow" type="warning" @click="showXmCostRecordDetails(scope.row,'bizMonth',month)">{{$mdp.toFixed(scope.row["cost"+month],2)}}</el-link>
</el-space>
</template>
</el-table-column>
<el-table-column label="合计" min-width="80" fixed="right">
<template #default="scope">
<el-space wrap fill>
<el-text v-if="budgetShow">{{ $mdp.toFixed(scope.row.budgetMonthsSum,2) }}</el-text>
<el-text v-if="costShow" type="warning">{{ $mdp.toFixed(scope.row.costMonthsSum,2) }}</el-text>
</el-space>
</template>
</el-table-column>
</el-table>
</el-scrollbar>
<mdp-dialog ref="xmBudgetRecordDlg" title="查看预算明细" fullscreen append-to-body :close-on-click-modal="false">
<template #default="{visible,data}">
<XmBudgetRecord :visible="visible" :params="data.params"/>
</template>
</mdp-dialog>
<mdp-dialog ref="xmCostRecordDlg" title="查看成本明细" fullscreen append-to-body :close-on-click-modal="false">
<template #default="{visible,data}">
<XmCostRecord :visible="visible" :params="data.params" :selProject="project"/>
</template>
</mdp-dialog>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user';
import { listSumXmCostRecord } from '@/api/xm/pro/xmCostRecord';
import { listSumXmBudgetRecord } from '@/api/xm/pro/xmBudgetRecord';
import XmBudgetRecord from '@/views/xm/pro/xmBudgetRecord/Index.vue';
import XmCostRecord from '@/views/xm/pro/xmCostRecord/Index.vue';
import XmProjectSelect from '@/views/xm/core/components/XmProjectSelect.vue'
import XmBudgetCostMonthTrend from '../rpt/project/budgetCostMonthTrend.vue'
export default {
props:{
selProject:null,
xmProduct:null,
baseView:{
type:String,
default: 'budget'
}
},
computed: {
...mapState(useUserStore,[
'userInfo','roles'
]),
selYearMonths:function(){
if(this.filters.groupBy.indexOf('biz_month')<0){
return []
}
var months=this.$mdp.getMonths(this.filters.startBizMonth,this.filters.endBizMonth)
return months.map(k=>this.$mdp.formatDate(k,'YYYY-MM'))
},
sumXmBudgeCostConvert:function(){
var map={};
var secMap={};
this.sumXmBudgetRecords?.forEach(i=>{
let key=this.getRowKey(i);
let monthKey=key+"_"+(i.bizMonth||'bm');
secMap[monthKey]={...i};
map[key]={...i};
});
//实际的成本计算
this.sumXmCostRecords?.forEach(i=>{
let key=this.getRowKey(i);
let monthKey=key+"_"+(i.bizMonth||'bm');
if(!map[key]){
map[key]={...i}
secMap[monthKey]={...i};
}
if(!secMap[monthKey]){
secMap[monthKey]={...i}
}
map[key].actAt=i.actAt
secMap[monthKey].actAt=i.actAt
});
var list=[];
for(var key in map){
var row=map[key];
var budgetMonthsSum=0;
var costMonthsSum=0;
if(this.filters.groupBy.indexOf('biz_month')>=0){
this.selYearMonths.forEach(i=>{
var val=secMap[key+"_"+i];
if( val !=null && val !=undefined ){
row["budget"+i]=val.budgetAt||0;
row["cost"+i]=val.actAt||0
}else{
row["budget"+i]=0;
row["cost"+i]=0
}
budgetMonthsSum=budgetMonthsSum+(row["budget"+i]||0)
costMonthsSum=costMonthsSum+(row["cost"+i]||0)
});
}else{
row['budgetMonthsSum']=row.budgetAt||0;
row['costMonthsSum']=row.actAt||0;
}
list.push(row);
}
return list;
},
budgetShow(){
if(this.baseView=='budget'){
return true
}else if(this.filters.budgetCost=='1'){
return true
}else{
return false
}
},
costShow(){
if(this.baseView=='cost'){
return true
}else if(this.filters.budgetCost=='1'){
return true
}else{
return false
}
},
id(){
return this.$mdp.getCodeKey("rpt",this.filters)
},
echartRptCfg(){
let cfg={
id:'xxxxx',
title:this.titleCpd(),
params:{
...this.filters
}
}
return cfg
}
},
watch: {
id(){
this.listSumSamt()
}
},
data() {
return {
filters: {
projectId:'',
groupBy:'project_id,biz_month',
startBizMonth: '',
endBizMonth: '',
budgetCost: '1',
},
load:{ list: false, edit: false, del: false, add: false },//查询中...
sumXmBudgetRecords:[],
sumXmCostRecords:[],
chartShow:true,
rptDatas:[],
project:null,
}
},//end data
methods: {
titleCpd(){
var preName=""
if(this.project && this.project.id){
if(this.project.name){
preName=`项目【${this.project.name}`
}else{
preName=`项目【${this.project.id}`
}
}else{
preName="企业"
}
var midName=''
if(this.budgetCost=='1'){
midName="预算与实际成本"
}else if(this.baseView=='cost'){
midName="成本"
}else{
midName="预算"
}
return preName+midName+"每月趋势图"
},
getRowKey(i){
return (i.costCenterId||"")+(i.projectId||"")+"_"+(i.subjectId||"")+"_"+(i.userid||"")+"_"+(i.taskId||"")+"_"+(i.bizFlowState||"");
},
rowClick: function(row, event, column){
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
doSearch(){
this.listSumSamt()
},
calcEchartData(res){
let budgetData=res.data
let costData=res.costData
if(this.baseView=='cost'){
budgetData=res.budgetData
costData=res.data
}
//he bing shuju
let map={}
budgetData?.forEach(i=>{
let key=i.bizMonth ||'bm'
if(!map[key]){
map[key]={bizMonth:i.bizMonth||'bm',actAt:0,budgetAt:i.budgetAt||0}
}else{
map[key].budgetAt=(map[key].budgetAt||0)+(i.budgetAt||0)
}
})
costData?.forEach(i=>{
let key=i.bizMonth||'bm'
if(!map[key]){
map[key]={bizMonth:i.bizMonth||'bm',actAt:(i.actAt||0),budgetAt:0}
}else{
map[key].actAt=(map[key].actAt||0)+(i.actAt||0)
}
})
let list=[]
for(var key in map){
list.push(map[key])
}
list.sort(this.sort)
debugger
return list
},
listSumSamt:function(){
var params={
projectId:this.projectInfo?.id||this.filters.projectId||"",
groupBy: this.filters.groupBy,
startBizMonth: this.filters.startBizMonth,
endBizMonth: this.filters.endBizMonth,
budgetCost: this.filters.budgetCost
}
if(!params.groupBy){
this.$message.error("分组必须选上")
return;
}
let func=listSumXmBudgetRecord
if(this.baseView=='cost'){
func=listSumXmCostRecord
}
func(params).then(res=>{
if(res.tips.isOk){
if(this.baseView=='cost'){
this.sumXmBudgetRecords=res.budgetData;
this.sumXmCostRecords=res.data;
}else{
this.sumXmBudgetRecords=res.data;
this.sumXmCostRecords=res.costData;
}
this.rptDatas=this.calcEchartData(res)
this.$message.success("查询成功")
}else{
this.$message.error(res.tips.msg)
}
})
},
showXmBudgetRecordDetails:function(row,fieldName,fieldValue){
var params={}
var groupByArr=this.filters.groupBy.split(",")
groupByArr.forEach(k=>
{
var field=this.$mdp.toCamel(k)
if(field!='bizMonth'){
params[field]=row[field]
}
})
let filters={startBizMonth:this.filters.startBizMonth,endBizMonth:this.filters.endBizMonth}
Object.assign(params,filters)
if(fieldValue){
params[fieldName]=fieldValue
}else{
params[fieldName]=row[fieldName]
}
this.$refs['xmBudgetRecordDlg'].open({params:params})
},
showXmCostRecordDetails:function(row,fieldName,fieldValue){
var params={}
var groupByArr=this.filters.groupBy.split(",")
groupByArr.forEach(k=>
{
var field=this.$mdp.toCamel(k)
if(field!='bizMonth'){
params[field]=row[field]
}
})
let filters={startBizMonth:this.filters.startBizMonth,endBizMonth:this.filters.endBizMonth}
Object.assign(params,filters)
if(fieldValue){
params[fieldName]=fieldValue
}else{
params[fieldName]=row[fieldName]
}
this.$refs['xmCostRecordDlg'].open({params:params})
},
/**end 自定义函数请在上面加**/
},//end methods
components: {
XmBudgetRecord, XmCostRecord,
XmProjectSelect,XmBudgetCostMonthTrend
//在下面添加其它组件
},
mounted() {
this.project=this.selProject
this.product=this.xmProduct
this.filters.startBizMonth=this.$mdp.moment().startOf('year').format("YYYY-MM")
this.filters.endBizMonth=this.$mdp.moment().endOf('year').format("YYYY-MM")
this.listSumSamt()
}
}
</script>

View File

@@ -0,0 +1,20 @@
<template>
<XmBudget :xmProduct="xmProduct" v-if="xmProduct?.id" baseView="budget"/>
</template>
<script>
import { mapState } from 'pinia'
import XmBudget from './XmBudgetCost.vue'
import { useXmStore } from '@/store/modules/xm';
export default {
computed: {
...mapState(useXmStore,['xmProduct']),
},
components: {
XmBudget,
//在下面添加其它组件
},
}
</script>

View File

@@ -0,0 +1,20 @@
<template>
<XmBudget :selProject="projectInfo" v-if="projectInfo?.id" baseView="budget"/>
</template>
<script>
import { mapState } from 'pinia'
import XmBudget from './XmBudgetCost.vue'
import { useXmStore } from '@/store/modules/xm';
export default {
computed: {
...mapState(useXmStore,['projectInfo']),
},
components: {
XmBudget,
//在下面添加其它组件
},
}
</script>

View File

@@ -0,0 +1,20 @@
<template>
<XmCost baseView="cost"/>
</template>
<script>
import { mapState } from 'pinia'
import XmCost from './XmBudgetCost.vue'
import { useXmStore } from '@/store/modules/xm';
export default {
computed: {
...mapState(useXmStore,['xmProduct']),
},
components: {
XmCost,
//在下面添加其它组件
},
}
</script>

View File

@@ -0,0 +1,20 @@
<template>
<XmCost :xmProduct="xmProduct" v-if="xmProduct?.id" baseView="cost"/>
</template>
<script>
import { mapState } from 'pinia'
import XmCost from './XmBudgetCost.vue'
import { useXmStore } from '@/store/modules/xm';
export default {
computed: {
...mapState(useXmStore,['xmProduct']),
},
components: {
XmCost,
//在下面添加其它组件
},
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<XmCost :selProject="projectInfo" v-if="projectInfo?.id" baseView="cost"/>
</template>
<script>
import { mapState } from 'pinia'
import XmCost from './XmBudgetCost.vue'
import { useXmStore } from '@/store/modules/xm';
export default {
computed: {
...mapState(useXmStore,['projectInfo']),
},
components: {
XmCost,
},
}
</script>

View File

@@ -1,359 +0,0 @@
<template>
<el-row class="xm-budget">
<div class="title-bar">
<el-radio-group v-model="costShow" size="medium">
<el-radio-button label="预算清单" />
<el-radio-button label="预算统计" />
</el-radio-group>
<span style="margin-left:10px;font-size:14px;">项目总预算</span> <el-tag type="success">{{projectInfoBudget.planTotalCost}}</el-tag>
<span style="margin-left:10px;font-size:14px;">非人力总预算</span><el-tag>{{projectInfoBudget.planNouserAt}}</el-tag>
<span style="margin-left:10px;font-size:14px;">内部人力总预算</span><el-tag>{{projectInfoBudget.planIuserAt}}</el-tag>
<span style="margin-left:10px;font-size:14px;">外购人力总预算</span><el-tag>{{projectInfoBudget.planOuserAt}}</el-tag>
</div>
<div class="title-bar">
<el-radio-group v-model="showType" size="medium">
<el-radio-button label="人力" />
<el-radio-button label="非人力" />
</el-radio-group>
</div>
<div v-if="costShow == '预算统计'">
<el-date-picker style="padding:10px;width:120px;" v-model="selYear" value-format="yyyy" type="year" placeholder="年份" :clearable="false" />
<!-- <el-select style="height:50px;padding:10px;width:120px;" v-model="selYear" placeholder="年份">
<el-option
v-for="item in subjectYearList"
:key="item"
:label="item"
:value="item" />
</el-select> -->
<el-table
ref="table"
v-adaptive="{bottom:30}"
v-if="showType == '人力'"
:data="sumXmBudgetLaborsConvert"
highlight-current-row
v-loading="load.list"
border>
<el-table-column prop="subjectId" label="科目" min-width="100" >
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showCostUserDetails(scope.row,'subjectId','queryBySubjectId')">{{scope.row.subjectId}}</a>
</template>
</el-table-column>
<el-table-column prop="username" label="姓名" min-width="100" >
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showCostUserDetails(scope.row,'username','queryByUsername')">{{scope.row.username}}</a>
</template>
</el-table-column>
<!-- <el-table-column min-width="100" /> -->
<el-table-column :prop="month" v-for="month in selYearMonths" :key="month" :label="month" width="120">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showCostUserDetails(scope.row,month,'queryByBizzMonth')">{{scope.row[month]}}</a>
</template>
</el-table-column>
<el-table-column prop="monthsSum" label="合计" min-width="80"/>
</el-table>
<el-table
ref="table"
v-adaptive="{bottom:30}"
v-if="showType == '非人力'"
:data="sumXmBudgetNlaborsConvert"
highlight-current-row
v-loading="load.list"
border
style="width: 100%;height:720px;overflow-y:auto;">
<el-table-column prop="subjectId" label="科目" min-width="100" >
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showCostNouserDetails(scope.row,'subjectId','queryBySubjectId')">{{scope.row.subjectId}}</a>
</template>
</el-table-column>
<el-table-column prop="username" label="姓名" min-width="100" >
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showCostNouserDetails(scope.row,'username','queryByUsername')">{{scope.row.username}}</a>
</template>
</el-table-column>
<!-- <el-table-column min-width="100" /> -->
<el-table-column :prop="month" v-for="month in selYearMonths" :key="month" :label="month" width="120">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showCostNouserDetails(scope.row,month,'queryByBizzMonth')">{{scope.row[month]}}</a>
</template>
</el-table-column>
<el-table-column prop="monthsSum" label="合计" min-width="80"/>
</el-table>
</div>
<div v-else>
<xm-budget-labor v-if="showType == '人力'" :sel-project="projectInfo" />
<xm-budget-nlabor v-else :sel-project="projectInfo" />
</div>
<mdp-dialog title="查看人力预算明细" v-model="xmBudgetLaborVisible" fullscreen append-to-body :close-on-click-modal="false">
<xm-budget-labor :xm-budget-labor="xmBudgetLabor" :visible="xmBudgetLaborVisible" :field-name="fieldName" :query-type="queryType" :sel-project="projectInfo" />
</mdp-dialog>
<mdp-dialog title="查看非人力预算明细" v-model="xmBudgetNlaborVisible" fullscreen append-to-body :close-on-click-modal="false">
<xm-budget-nlabor :xm-budget-nlabor="xmBudgetNlabor" :visible="xmBudgetNlaborVisible" :field-name="fieldName" :query-type="queryType" :sel-project="projectInfo" />
</mdp-dialog>
</el-row>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
//import Sticky from '@/components/Sticky' // 粘性header组件
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user';
import { editBudget } from '@/api/xm/core/xmProject';
import { listSumXmBudgetLabor } from '@/api/xm/pro/xmBudgetLabor';
import { listSumXmBudgetNlabor } from '@/api/xm/pro/xmBudgetNlabor';
import xmBudgetLabor from '../xmBudgetLabor/XmBudgetLaborMng.vue';
import xmBudgetNlabor from '../xmBudgetNlabor/XmBudgetNlaborMng.vue';
export default {
computed: {
...mapState(useUserStore,[
'userInfo','roles','projectInfo'
]),
selYearMonths:function(){
var selYear=this.selYear;
var yearMonths=[selYear+'-01',selYear+'-02',selYear+'-03',selYear+'-04',selYear+'-05',selYear+'-06',selYear+'-07',selYear+'-08',selYear+'-09',selYear+'-10',selYear+'-11',selYear+'-12']
return yearMonths;
},
sumXmBudgetLaborsConvert:function(){
var map={};
var secMap={};
this.sumXmBudgetLabors.forEach(i=>{
i.key=i.projectId+"_"+i.subjectId+"_"+i.userid+"_"+i.username;
i.monthKey=i.key+"_"+i.bizzMonth;
secMap[i.monthKey]=i;
map[i.key]=i;
});
var list=[];
for(var key in map){
var row=map[key];
var monthsSum=0;
this.selYearMonths.forEach(i=>{
var val=secMap[key+"_"+i];
if( val !=null && val !=undefined ){
row[i]=val.budgetCost;
}else{
row[i]=0;
}
monthsSum=monthsSum+row[i]
});
row['monthsSum']=monthsSum;
list.push(row);
}
return list;
},
sumXmBudgetNlaborsConvert:function(){
var map={};
var secMap={};
this.sumXmBudgetNlabors.forEach(i=>{
i.key=i.projectId+"_"+i.subjectId;
i.monthKey=i.key+"_"+i.bizzMonth;
secMap[i.monthKey]=i;
map[i.key]=i;
});
var list=[];
for(var key in map){
var row=map[key];
var monthsSum=0;
this.selYearMonths.forEach(i=>{
var val=secMap[key+"_"+i];
if( val !=null && val !=undefined ){
row[i]=val.budgetCost;
}else{
row[i]=0;
}
monthsSum=monthsSum+row[i]
});
row['monthsSum']=monthsSum;
list.push(row);
}
return list;
}
},
watch: {
'showType': function(val) {
if(val == "人力"){
this.listSumXmBudgetLabor();
}
else{
this.listSumXmBudgetNlabor();
}
},
'projectInfo': function(projectInfo){
this.projectInfoBudget=Object.assign({},this.projectInfo);
}
},
data() {
return {
filters: {
key: ''
},
screenData: [],//查询结果
load:{ list: false, edit: false, del: false, add: false },//查询中...
/**begin 自定义属性请在下面加 请加备注**/
subjects: [],
costShow: "预算统计",
selYear: ""+new Date().getFullYear(),
showType: "",
xmBudgetLabors: [],
xmBudgetNlabors: [],
projectInfoBudget:{},
sumXmBudgetLabors:[],
xmBudgetLabor:null,
fieldName:'',
queryType:'',
xmBudgetLaborVisible:false,
sumXmBudgetNlabors:[],
xmBudgetNlabor:null,
xmBudgetNlaborVisible:false,
tableHeight:300,
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
rowClick: function(row, event, column){
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
listSumXmBudgetLabor:function(){
var parmas={
projectId:this.projectInfo.id,
}
listSumXmBudgetLabor(parmas).then(res=>{
this.sumXmBudgetLabors=res.data;
})
},
listSumXmBudgetNlabor:function(){
var parmas={
projectId:this.projectInfo.id,
}
listSumXmBudgetNlabor(parmas).then(res=>{
this.sumXmBudgetNlabors=res.data;
})
},
showCostUserDetails:function(row,fieldName,queryType){
this.xmBudgetLabor=row
this.fileName=fieldName
this.queryType=queryType
this.xmBudgetLaborVisible=true;
},
showCostNouserDetails:function(row,fieldName,queryType){
this.xmBudgetNlabor=row
this.fileName=fieldName
this.queryType=queryType
this.xmBudgetNlaborVisible=true;
},
/**begin 自定义函数请在下面加**/
// inputChange() {
// this.projectInfo.planTotalCost = this.projectInfo.planTotalCost.replace(/[^\d.]/g,"").replace(/^\./g,"").replace(/\.{1,}/g,".");
// },
updateBudget() {
if(this.projectInfo.planTotalCost==undefined){
this.$notify({position:'bottom-left',showClose:true,message:"不允许修改", type: 'success'});
return;
}
var planTotalCost=this.getFloatValue(this.projectInfoBudget.planTotalCost)
var planIuserAt=this.getFloatValue(this.projectInfoBudget.planIuserAt)
var planOuserAt=this.getFloatValue(this.projectInfoBudget.planOuserAt)
var planNouserAt=this.getFloatValue(this.projectInfoBudget.planNouserAt)
this.projectInfoBudget.planTotalCost=planIuserAt+planOuserAt+planNouserAt
this.$confirm('确定修改项目总预算吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.edit = true;
let params = this.projectInfoBudget
editBudget(params).then((res) => {
var tips=res.tips;
if(tips.isOk){
this.projectInfo.planTotalCost=this.projectInfoBudget.planTotalCost
this.projectInfo.planIuserAt=this.projectInfoBudget.planIuserAt
this.projectInfo.planOuserAt=this.projectInfoBudget.planOuserAt
this.projectInfo.planNouserAt=this.projectInfoBudget.planNouserAt
}else{
this.projectInfoBudget=Object.assign({},this.projectInfo)
}
this.$notify({position:'bottom-left',showClose:true,message: tips.msg, type: tips.isOk?'success':'error' });
this.load.edit = false;
}).catch( err => this.load.edut = false );
}).catch(() => {
this.projectInfoBudget=Object.assign({},this.projectInfo)
});
},
getFloatValue(value,digit){
if(value==null || value=='' || value==undefined){
value=0;
}
return parseFloat(value);
},
/**end 自定义函数请在上面加**/
},//end methods
components: {
xmBudgetLabor,
xmBudgetNlabor,
//在下面添加其它组件
},
mounted() {
this.showType = "人力";
this.projectInfoBudget=Object.assign({},this.projectInfo);
}
}
</script>
<style scoped>
.xm-budget{
width: 100%;
}
.title-bar{
padding:7px 10px;
height: 50px;
background: #fafbfc;
border-bottom: 1px solid #efefef;
}
/* .title-bar>button{
float:right;
} */
.fs-ft{
font-size: 14px !important;
}
.xm-budget .el-form-item{
padding: 0 10px;
}
.xm-budget >>> input[type="number"]{
padding-left: 5px;
padding-right: 0;
}
/* .xm-budget >>> .headBorder:first-child, */
.xm-budget >>> .headBorder:nth-last-child(3){
border-right: 0 !important;
}
.xm-budget .title-bar >>> .el-radio-button__inner{
padding: 10px 15px;
background: transparent;
border: 0;
border-radius: 0;
box-shadow: 0 0 0 0 !important;
}
.xm-budget .title-bar .is-active >>> .el-radio-button__inner{
color: #409EFF !important;
border: 1px solid #409EFF;
}
.xm-budget>.el-table::before{
height: 0;
}
/* 超过宽度则用...代替 */
.truncate{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -1,370 +0,0 @@
<template>
<ContentWrap>
<el-space wrap>
<el-radio-group v-model="showType">
<el-radio-button label="人力" />
<el-radio-button label="非人力" />
</el-radio-group>
<XmProjectSelect v-model="filters.projectId" v-if="!projectInfo?.id" />
<MdpSelect split="," v-model="filters.groupBy" :options="[{id:'project_id',name:'项目'},{id:'userid',name:'用户'},{id:'subject_id',name:'资金用途(科目)'},{id:'biz_month',name:'支出月份'}]" multiple placeholder="分组"/>
<mdp-date v-model="selYear" value-format="YYYY" format="YYYY" type="year" placeholder="统计年份" :clearable="false" />
<el-button @click="doSearch" icon="search" plain/>
</el-space>
</ContentWrap>
<el-table ref="table"
v-adaptive="{bottom:30}"
v-if=" showType == '人力'"
:data="sumXmCostLaborsConvert"
highlight-current-row
v-loading="load.list"
border>
<el-table-column prop="subjectId" label="科目" min-width="100" v-if="filters.groupBy.indexOf('subject_id')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostNlaborDetails(scope.row,'subjectId')">{{scope.row.subjectName||scope.row.subjectId}}</a>
</template>
</el-table-column>
<el-table-column prop="userid" label="成员姓名" min-width="100" v-if="filters.groupBy.indexOf('userid')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostLaborDetails(scope.row,'userid')">{{scope.row.username}}</a>
</template>
</el-table-column>
<el-table-column prop="projectId" label="项目编号" min-width="100" v-if="filters.groupBy.indexOf('project_id')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostLaborDetails(scope.row,'projectId')">{{scope.row.projectId}}</a>
</template>
</el-table-column>
<el-table-column prop="branchId" label="企业编号" min-width="100" v-if="filters.groupBy.indexOf('branchId')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostLaborDetails(scope.row,'branchId')">{{scope.row.branchId}}</a>
</template>
</el-table-column>
<!-- <el-table-column min-width="100" /> -->
<el-table-column :prop="month" v-for="month in selYearMonths" :key="month" :label="month" width="120">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostLaborDetails(scope.row,'bizMonth',month)">{{scope.row[month]}}</a>
</template>
</el-table-column>
<el-table-column prop="monthsSum" label="合计" min-width="80" fixed="right"/>
</el-table>
<el-table
v-adaptive="{bottom:30}"
v-if=" showType == '非人力'"
:data="sumXmCostNlaborsConvert"
highlight-current-row
v-loading="load.list"
border
style="width: 100%;height:720px;overflow-y:auto;">
<el-table-column prop="subjectId" label="科目" min-width="100" v-if="filters.groupBy.indexOf('subject_id')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostNlaborDetails(scope.row,'subjectId')">{{scope.row.subjectName||scope.row.subjectId}}</a>
</template>
</el-table-column>
<el-table-column prop="userid" label="姓名" min-width="100" v-if="filters.groupBy.indexOf('userid')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostNlaborDetails(scope.row,'userid')">{{scope.row.username}}</a>
</template>
</el-table-column>
<el-table-column prop="projectId" label="项目编号" min-width="100" v-if="filters.groupBy.indexOf('project_id')>=0">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostNlaborDetails(scope.row,'projectId')">{{scope.row.projectId}}</a>
</template>
</el-table-column>
<!-- <el-table-column min-width="100" /> -->
<el-table-column :prop="month" v-for="month in selYearMonths" :key="month" :label="month" width="120">
<template #default="scope">
<a style="text-decoration:underline;margin-right:5px;" @click="showXmCostNlaborDetails(scope.row,'bizMonth',month)">{{scope.row[month]}}</a>
</template>
</el-table-column>
<el-table-column prop="monthsSum" label="合计" min-width="80" fixed="right"/>
</el-table>
<mdp-dialog ref="xmCostLaborDlg" title="查看人力支出明细" width="80%" append-to-body :close-on-click-modal="false">
<template #default="{visible,data}">
<xm-cost-labor :visible="visible" :params="data.params"/>
</template>
</mdp-dialog>
<mdp-dialog ref="xmCostNlaborDlg" title="查看非人力支出明细" width="90%" append-to-body :close-on-click-modal="false">
<template #default="{visible,data}">
<xm-cost-nlabor :params="data.params" :visible="visible" :sel-project="projectInfo" />
</template>
</mdp-dialog>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user';
import { useXmStore } from '@/store/modules/xm';
import { listSumXmCostLabor } from '@/api/xm/pro/xmTaskSbillDetail';
import { listSumXmCostNlabor } from '@/api/xm/pro/xmCostNlabor';
import xmCostLabor from '@/views/xm/pro/xmTaskSbillDetail/XmTaskSbillDetailMng.vue';
import xmCostNlabor from '@/views/xm/pro/xmCostNlabor/XmCostNlaborMng.vue';
import XmProjectSelect from '@/views/xm/core/components/XmProjectSelect.vue'
export default {
computed: {
...mapState(useUserStore,[
'userInfo','roles'
]),
...mapState(useXmStore,[ 'projectInfo']),
selYearMonths:function(){
var selYear=this.selYear||'未知';
var yearMonths=[selYear+'-01',selYear+'-02',selYear+'-03',selYear+'-04',selYear+'-05',selYear+'-06',selYear+'-07',selYear+'-08',selYear+'-09',selYear+'-10',selYear+'-11',selYear+'-12']
return yearMonths;
},
sumXmCostLaborsConvert:function(){
var map={};
var secMap={};
this.sumXmCostLabors.forEach(i=>{
i.key=i.branchId+"_"+i.projectId+"_"+i.subjectId+"_"+i.userid;
i.monthKey=i.key+"_"+i.bizMonth;
secMap[i.monthKey]=i;
map[i.key]=i;
});
var list=[];
for(var key in map){
var row=map[key];
var monthsSum=0;
this.selYearMonths.forEach(i=>{
var val=secMap[key+"_"+i];
if( val !=null && val !=undefined ){
row[i]=val.samt;
}else{
row[i]=0;
}
monthsSum=monthsSum+row[i]
});
row['monthsSum']=monthsSum;
list.push(row);
}
return list;
},
sumXmCostNlaborsConvert:function(){
var map={};
var secMap={};
this.sumXmCostNlabors.forEach(i=>{
i.key=i.projectId+"_"+i.subjectId;
i.monthKey=i.key+"_"+i.bizMonth;
secMap[i.monthKey]=i;
map[i.key]=i;
});
var list=[];
for(var key in map){
var row=map[key];
var monthsSum=0;
this.selYearMonths.forEach(i=>{
var val=secMap[key+"_"+i];
if( val !=null && val !=undefined ){
row[i]=val.actAt;
}else{
row[i]=0;
}
monthsSum=monthsSum+row[i]
});
row['monthsSum']=monthsSum;
list.push(row);
}
return list;
},
keyCpd(){
return this.showType+"|"+this.selYear+"|"+this.rptType+"|"+(this.projectInfo?.id||'')
}
},
watch: {
keyCpd: function(){
},
},
data() {
return {
filters: {
projectId:'',
groupBy:'project_id,biz_month',
startBizMonth: '',
endBizMonth: ''
},
screenData: [],//查询结果
load:{ list: false, edit: false, del: false, add: false },//查询中...
/**begin 自定义属性请在下面加 请加备注**/
subjects: [],
costShow: "支出统计",
selYear: ""+new Date().getFullYear(),
showType: "人力",
xmCostLabor: [],
xmCostNlabor: [],
sumXmCostLabors:[],
fieldName:'',
queryType:'',
sumXmCostNlabors:[],
rptType:'1',//统计类型
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
rowClick: function(row, event, column){
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
doSearch(){
if(this.showType=='人力'){
this.listSumSamt()
}else{
this.listSumXmCostNlabor()
}
},
listSumSamt:function(){
var params={
projectId:this.projectInfo?.id||this.filters.projectId||"",
groupBy: this.filters.groupBy,
bizYear:this.selYear,
}
if(!params.groupBy){
this.$message.error("分组必须选上")
return;
}
if(params.groupBy.indexOf('biz_month')<0){
this.$message.error("分组必须选上支出月份")
return;
}
listSumXmCostLabor(params).then(res=>{
if(res.tips.isOk){
this.sumXmCostLabors=res.data;
this.$message.success("查询成功")
}else{
this.$message.error(res.tips.msg)
}
})
},
listSumXmCostNlabor:function(){
var params={
projectId:this.projectInfo?.id||this.filters.projectId||"",
groupBy: this.filters.groupBy,
startBizMonth: this.selYear+"-01",
endBizMonth: this.selYear+"-12"
}
if(!params.groupBy){
this.$message.error("分组必须选上")
return;
}
if(params.groupBy.indexOf('biz_month')<0){
this.$message.error("分组必须选上支出月份")
return;
}
listSumXmCostNlabor(params).then(res=>{
if(res.tips.isOk){
this.sumXmCostNlabors=res.data;
this.$message.success("查询成功")
}else{
this.$message.error(res.tips.msg)
}
})
},
showXmCostLaborDetails:function(row,fieldName,fieldValue){
var params={}
var groupByArr=this.filters.groupBy.split(",")
groupByArr.forEach(k=>
{
var field=this.$mdp.toCamel(k)
params[field]=row[field]
})
if(fieldValue){
params[fieldName]=fieldValue
}else{
params[fieldName]=row[fieldName]
}
this.$refs['xmCostLaborDlg'].open({params:params})
},
showXmCostNlaborDetails:function(row,fieldName,fieldValue){
var params={}
var groupByArr=this.filters.groupBy.split(",")
groupByArr.forEach(k=>
{
var field=this.$mdp.toCamel(k)
params[field]=row[field]
})
if(fieldValue){
params[fieldName]=fieldValue
}else{
params[fieldName]=row[fieldName]
}
this.$refs['xmCostNlaborDlg'].open({params:params})
},
/**end 自定义函数请在上面加**/
},//end methods
components: {
xmCostLabor,
xmCostNlabor,
XmProjectSelect
//在下面添加其它组件
},
mounted() {
}
}
</script>
<style scoped>
.xm-cost{
width: 100%;
}
.title-bar{
padding:7px 10px;
height: 50px;
background: #fafbfc;
border-bottom: 1px solid #efefef;
}
/* .title-bar>button{
float:right;
} */
.fs-ft{
font-size: 14px !important;
}
.xm-cost .el-form-item{
padding: 0 10px;
}
.xm-cost >>> input[type="number"]{
padding-left: 5px;
padding-right: 0;
}
/* .xm-cost >>> .headBorder:first-child, */
.xm-cost >>> .headBorder:nth-last-child(3){
border-right: 0 !important;
}
.xm-cost .title-bar >>> .el-radio-button__inner{
padding: 10px 15px;
background: transparent;
border: 0;
border-radius: 0;
box-shadow: 0 0 0 0 !important;
}
.xm-cost .title-bar .is-active >>> .el-radio-button__inner{
color: #409EFF !important;
border: 1px solid #409EFF;
}
.xm-cost>.el-table::before{
height: 0;
}
/* 超过宽度则用...代替 */
.truncate{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -309,7 +309,7 @@ export default {
}
},
onCompSelect(comp){
debugger
if(this.compCfgList.some(k=>k.compId==comp.compId)){
var compCfg=this.compCfgList.find(k=>k.compId==comp.compId)
this.$nextTick(()=>{

View File

@@ -143,6 +143,7 @@ export default {
{ isChecked: false, isCurr: false, rptName: '任务排行榜', category: '项目级,企业级', compId: 'xmTaskSort', desc: '任务提出人、负责人的用户故事数量排行(实时数据)', img: bar },
{ isChecked: false, isCurr: false, rptName: '项目结算工时每日趋势', category: '项目级', compId: 'xmProjectWorkloadSetDayList', desc: '统计项目每日登记工时、结算工时数量分布情况', img: datasetLink },
{ isChecked: false, isCurr: false, rptName: '项目结算工时每月趋势', category: '项目级', compId: 'xmProjectWorkloadSetMonthList', desc: '统计项目每月登记工时、结算工时数量分布情况', img: datasetLink },
{ isChecked: false, isCurr: false, rptName: '预算与成本每月趋势', category: '产品级,企业级,项目级', compId: 'xmBudgetCostMonthTrend', desc: '统计每月的预算与实际成本的趋势', img: datasetLink },
//测试库级报表

View File

@@ -24,6 +24,7 @@ export default {
xmProjectWorkItemDayList:defineAsyncComponent(()=>import("../project/projectWorkItemDayList.vue")),
xmProjectWorkloadSetDayList:defineAsyncComponent(()=>import("../project/projectWorkloadSetDayList.vue")),
xmProjectWorkloadSetMonthList:defineAsyncComponent(()=>import("../project/projectWorkloadSetMonthList.vue")),
xmBudgetCostMonthTrend:defineAsyncComponent(()=>import("../project/budgetCostMonthTrend.vue")),
xmQuestionDayTrend:defineAsyncComponent(()=>import("../product/questionDayTrend.vue")),
xmQuestionDayAccumulate:defineAsyncComponent(()=>import("../product/questionDayAccumulate.vue")),

View File

@@ -0,0 +1,315 @@
<template>
<MdpRptHeader v-model:title="title" v-model:remark="remark" :isRptCfg="isRptCfg" :showParams="showParams" @delete="$emit('delete',cfg)">
<template #title v-if="showTitle===false">
<span></span>
</template>
<el-form :model="params" class="padding" ref="filtersRef">
<el-form-item label="归属项目">
<XmProjectSelect width="100%" v-model="params.projectId" v-if="!projectInfo?.id" :linkProductId="xmProduct?.id" @change2="project=$event"/>
</el-form-item>
<el-form-item label="分组">
<MdpSelect width="100%" title="分组统计" split="," v-model="params.groupBy" :options="[{id:'cost_center_id',name:'成本中心'},{id:'project_id',name:'项目'},{id:'userid',name:'用户'},{id:'subject_id',name:'资金用途(科目)'},{id:'biz_month',name:'支出月份'},{id:'task_id',name:'任务'},{id:'biz_flow_state',name:'审核状态'}]" multiple placeholder="分组"/>
</el-form-item>
<el-form-item label="月份区间">
<mdp-date-range start-key="startBizMonth" end-key="endBizMonth" type="monthrange" v-model="params" value-format="YYYY-MM" format="YYYY-MM" placeholder="统计时间" :clearable="false" />
</el-form-item>
</el-form>
<template #toolbar>
<el-button type="primary" icon="search" @click="listSumXmBudgetRecord">查询</el-button>
</template>
</MdpRptHeader>
<div class="row-box">
<div class="echart-box" :id="this.id"></div>
</div>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import { listSumXmCostRecord } from '@/api/xm/pro/xmCostRecord';
import { listSumXmBudgetRecord } from '@/api/xm/pro/xmBudgetRecord';
import XmProjectSelect from '@/views/xm/core/components/XmProjectSelect.vue';//新增界面
import * as echarts from 'echarts';
export default {
components: {
XmProjectSelect,
},
props:['id','cfg','category','showToolBar','showParams','isRptCfg','rptDatas','xmProduct','xmProject','baseView'/**cost/budget */,'budgetCost'/**1-预算与成本比对*/,'showTitle'/**true/false */],
computed: {
...mapState(useUserStore,[
'userInfo','roles'
]),
monthsCpd(){
if(this.rawDatas.length==0){
return []
}else{
return this.rawDatas.map(i=>(i.bizMonth=="bm"?"合计":i.bizMonth))
}
},
budgetAtCpd(){
if(this.rawDatas.length==0){
return []
}else{
return this.rawDatas.map(i=>i.budgetAt)
}
},
costAtCpd(){
if(this.rawDatas.length==0){
return []
}else{
return this.rawDatas.map(i=> i.actAt)
}
},
legendCpd(){
if(this.budgetCost=='1'){
return ['预算','成本']
}else{
if(this.baseView=='cost'){
return ['成本']
}else{
return ["预算"]
}
}
},
titleCpd(){
if(this.cfg?.title){
return this.cfg.title
}
var preName=""
if(this.project && this.project.id){
if(this.project.name){
preName=`项目【${this.project.name}`
}else{
preName=`项目【${this.project.id}`
}
}else{
preName="企业"
}
var midName=''
if(this.budgetCost=='1'){
midName="预算与实际成本"
}else if(this.baseView=='cost'){
midName="成本"
}else{
midName="预算"
}
return preName+midName+"每月趋势图"
},
},
watch: {
rptDatas(val){
this.rawDatas=val
},
monthsCpd(){
this.$nextTick(()=>{
this.drawCharts();
})
}
},
data() {
return {
product:null,
project:null,
params:{
budgetCost:'1',
groupBy:'project_id,biz_month'
},
title:'',//报表配置项
remark:'', //报表配置项
rawDatas:[],
}//end return
},//end data
methods: {
getRowKey(i){
return i.bizMonth;
},
listSumXmBudgetRecord(){
if(this.rptDatas){
this.rawDatas=this.rptDatas
return;
}
var params={...this.params}
if(!params.groupBy){
this.$message.error("分组必须选上")
return;
}
let func=listSumXmBudgetRecord
if(this.baseView=='cost'){
func=listSumXmCostRecord
}
func(params).then(res=>{
if(res.tips.isOk){
let budgetData=res.data
let costData=res.costData
if(this.baseView=='cost'){
budgetData=res.budgetData
costData=res.data
}
//he bing shuju
let map={}
budgetData?.forEach(i=>{
let key=this.getRowKey(i)||'hj'
if(!map[key]){
map[key]={bizMonth:i.bizMonth,actAt:0,budgetAt:i.budgetAt||0}
}else{
map[key].budgetAt=(map[key].budgetAt||0)+(i.budgetAt||0)
}
})
costData?.forEach(i=>{
let key=this.getRowKey(i)||'hj'
if(!map[key]){
map[key]={bizMonth:i.bizMonth,actAt:(i.actAt||0),budgetAt:0}
}else{
map[key].actAt=(map[key].actAt||0)+(i.actAt||0)
}
})
let list=[]
for(var key in map){
list.push(map[key])
}
list.sort(this.sort)
this.rawDatas=list
}else{
this.$message.error(res.tips.msg)
}
})
},
sort(x,y){
let x1=parseInt(x.bizMonth.replace("-",""))
let y1=parseInt(y.bizMonth.replace("-",""))
return x1-y1
},
open(){
this.product=this.xmProduct
this.project=this.xmProject
if( this.product && this.product.id){
this.params.productId= this.product.id
}
if( this.project && this.project.id){
this.params.projectId= this.project.id
}
if(this.cfg && this.cfg.id){
this.params=this.cfg.params
this.title=this.cfg.title
this.remark=this.cfg.remark
}
if(this.showToolBar && !this.title){
this.title=""
}
this.$nextTick(()=>{
this.listSumXmBudgetRecord();
})
},
drawCharts() {
this.myChart = echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.titleCpd,
left: 'center'
},
tooltip: {
trigger: 'axis',
},
barMaxWidth: 100,
toolbox: {
show: true,
top:"5%",
right:"10px",
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
legend: {
bottom: 'bottom',
data: this.legendCpd
},
xAxis: {
type: 'category',
data: this.monthsCpd
},
yAxis: {
type: 'value'
},
series: [
{
name:'预算',
data: this.budgetAtCpd,
type: 'line',
smooth: true,
itemStyle: {
normal: {
// 折点颜色样式
color: 'blue',
lineStyle: {
// 折线颜色样式
color: 'blue'
}
}
},
},
{
name:'成本',
data: this.costAtCpd,
type: 'line',
smooth: true,
itemStyle: {
normal: {
// 折点颜色样式
color: 'orange',
lineStyle: {
// 折线颜色样式
color: 'orange'
}
}
},
},
]
}
)
},
},//end method
mounted() {
this.params.startBizMonth=this.$mdp.moment().startOf('year').format("YYYY-MM")
this.params.endBizMonth=this.$mdp.moment().endOf('year').format("YYYY-MM")
this.open();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

View File

@@ -1,159 +0,0 @@
<template>
<el-row class="page-header" />
<el-row class="page-main" :style="{overflowX:'auto',height:maxTableHeight+'px'}" ref="table">
<!--编辑界面 XmBudgetLabor 项目人力成本预算-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editFormRef">
<el-form-item label="项目编号" prop="projectId">
<el-input v-model="editForm.projectId" placeholder="项目编号" :maxlength="50" disabled/>
</el-form-item>
<el-form-item label="用户名称" prop="username">
<el-input v-model="editForm.username" placeholder="用户,如果不确定具体人员,可用岗位代替" />
</el-form-item>
<el-form-item label="预算金额/每月" prop="budgetAt">
<el-input v-model="editForm.budgetAt" placeholder="预算金额/每月" :maxlength="10"/>
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input v-model="editForm.remark" placeholder="备注" />
</el-form-item>
<el-form-item label="预算科目" prop="subjectId">
<mdp-select item-code="projectSubject" placeholder="预算科目编号" v-model="editForm.subjectId"/>
</el-form-item>
<el-form-item label="预算月份" prop="bizMonth">
<el-date-picker
v-model="editForm.bizMonth"
type="month"
value-format="yyyy-MM"
placeholder="选择年月">
</el-date-picker>
</el-form-item>
</el-form>
</el-row>
<el-row class="page-bottom bottom-fixed">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="saveSubmit" :disabled="load.edit==true">提交</el-button>
</el-row>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from "@/api/mdp_pub/mdp_config"; //全局公共库import
import { addXmBudgetLabor,editXmBudgetLabor } from '@/api/xm/pro/xmBudgetLabor';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
name:'xmBudgetLaborEdit',
components: {
},
computed: {
...mapState(useUserStore,[ 'userInfo' ]),
},
props:['xmBudgetLabor','visible','opType'],
watch: {
'xmBudgetLabor':function( xmBudgetLabor ) {
if(xmBudgetLabor){
this.editForm = {...xmBudgetLabor};
}
},
'visible':function(visible) {
if(visible==true){
this.initData()
}
}
},
data() {
return {
currOpType:'add',//add/edit
load:{ list: false, edit: false, del: false, add: false },//查询中...
editFormRules: {
subjectId: [
{ required: true, message: '科目不能为空', trigger: 'change' }
],
username: [
{ required: true, message: '姓名不能为空,如果不确定具体人,请填写岗位代替', trigger: 'change' }
],
budgetAt: [
{ required: true, message: '金额不能为空', trigger: 'change' }
],
remark: [
{ required: true, message: '用途说明不能为空', trigger: 'change' }
]
},
editForm: {
projectId:'',userid:'',budgetAt:'',id:'',remark:'',username:'',subjectId:'',bizSdate:'',bizEdate:'',bizMonth:'',instId:'',bizFlowState:'',costType:'',subjectName:'',branchId:'',ubranchId:''
},
maxTableHeight:300,
}//end return
},//end data
methods: {
...util,
// 取消按钮点击 父组件监听@cancel="editFormVisible=false" 监听
handleCancel:function(){
this.$refs['editFormRef'].resetFields();
this.$emit('cancel');
},
//新增、编辑提交XmBudgetLabor 项目人力成本预算父组件监听@submit="afterEditSubmit"
saveSubmit: function () {
this.$refs.editFormRef.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
let params = Object.assign({}, this.editForm);
var func=addXmBudgetLabor
if(this.currOpType=='edit'){
func=editXmBudgetLabor
}
func(params).then((res) => {
this.load.edit=false
var tips=res.tips;
if(tips.isOk){
this.editForm=res.data
this.initData()
this.currOpType="edit";
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err =>this.load.edit=false);
});
}else{
this.$notify({ showClose:true, message: "表单验证不通过,请修改表单数据再提交", type: 'error' });
}
});
},
initData: function(){
this.currOpType=this.opType
if(this.xmBudgetLabor){
this.editForm = Object.assign({},this.xmBudgetLabor);
}
if(this.opType=='edit'){
}else{
}
},
},//end method
mounted() {
this.$nextTick(() => {
this.initData()
//this.maxTableHeight =util.calcTableMaxHeight(this.$refs.table.$el)
});
}
}
</script>
<style scoped />

View File

@@ -1,322 +0,0 @@
<template>
<el-row>
<el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询"/>
<el-button v-loading="load.list" :disabled="load.list==true" @click="searchXmBudgetLabors" icon="search">查询</el-button>
<span style="float:right;">
<el-button type="primary" @click="showAdd" icon="plus" plain/>
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length===0 || load.del==true" icon="delete" plain/>
</span>
</el-row>
<el-row class="padding-top">
<!--列表 XmBudgetLabor 项目人力成本预算-->
<el-table ref="xmBudgetLaborTable" :data="xmBudgetLabors" v-adaptive="{bottom:50}" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column type="selection" width="55" show-overflow-tooltip fixed="left" />
<el-table-column sortable type="index" width="55" show-overflow-tooltip fixed="left" />
<!--
<el-table-column sortable prop="username" width="55" show-overflow-tooltip fixed="left">
<span class="cell-text"> {{scope.row.username}}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder="" @change="editSomeFields(scope.row,'username',$event)" :maxlength="22"/></span>
</el-table-column>
-->
<el-table-column prop="projectId" label="项目编号" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span> {{scope.row.projectId}} </span>
</template>
</el-table-column>
<el-table-column prop="username" label="项目成员" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.username}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder="" @change="editSomeFields(scope.row,'username',$event)" :maxlength="22"/></span>
</template>
</el-table-column>
<el-table-column prop="subjectId" label="预算科目" min-width="80" show-overflow-tooltip>
<template #default="scope">
<mdp-select item-code="projectSubject" show-style="tag" v-model="scope.row.subjectId" placeholder="预算科目" style="display:block;" @change="editSomeFields(scope.row,'subjectId',$event)"/>
</template>
</el-table-column>
<el-table-column prop="remark" label="用途说明" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.remark}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.remark" placeholder="" @change="editSomeFields(scope.row,'remark',$event)" :maxlength="22"/></span>
</template>
</el-table-column>
<el-table-column prop="budgetAt" label="预算金额" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.budgetAt}} </span>
<span class="cell-bar"><el-input type="number" style="display:inline;" v-model="scope.row.budgetAt" placeholder="" @change="editSomeFields(scope.row,'budgetAt',$event)" :maxlength="22"/></span>
</template>
</el-table-column>
<el-table-column prop="bizMonth" label="费用月份" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.bizMonth}} </span>
<span class="cell-bar">
<el-date-picker
@change="editSomeFields(scope.row,'bizMonth',$event)"
v-model="scope.row.bizMonth"
type="month"
value-format="yyyy-MM"
placeholder="选择年月" />
</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button type="primary" @click="showEdit( scope.row,scope.$index)" icon="edit" plain/>
<el-button type="danger" @click="handleDel(scope.row,scope.$index)" icon="delete" plain/>
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange" @size-change="handleSizeChange" :page-sizes="[10,20, 50, 100, 500]" :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;" />
</el-row>
<el-row>
<!--编辑 XmBudgetLabor 项目人力成本预算界面-->
<mdp-dialog title="编辑项目人力预算" v-model="editFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<xm-budget-labor-edit op-type="edit" :xm-budget-labor="editForm" :visible="editFormVisible" @cancel="editFormVisible=false" @submit="afterEditSubmit" />
</mdp-dialog>
<!--新增 XmBudgetLabor 项目人力成本预算界面-->
<mdp-dialog title="新增项目人力预算" v-model="addFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<xm-budget-labor-add op-type="add" :sel-project="selProject" :visible="addFormVisible" @cancel="addFormVisible=false" @submit="afterAddSubmit" />
</mdp-dialog>
</el-row>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from '@/api/mdp_pub/mdp_config';//全局公共库
import { listXmBudgetLabor, delXmBudgetLabor, batchDelXmBudgetLabor,editSomeFieldsXmBudgetLabor } from '@/api/xm/pro/xmBudgetLabor';
import XmBudgetLaborEdit from './XmBudgetLaborEdit.vue';//新增修改界面
import XmBudgetLaborAdd from './XmBudgetLaborAdd.vue';//新增修改界面
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
name:'xmBudgetLaborMng',
components: {
XmBudgetLaborEdit,XmBudgetLaborAdd
},
props:['visible',"selProject"],
computed: {
...mapState(useUserStore,['userInfo']),
},
watch:{
visible(val){
if(val==true){
this.initData();
this.searchXmBudgetLabors()
}
}
},
data() {
return {
filters: {
key: ''
},
xmBudgetLabors: [],//查询结果
pageInfo:{//分页数据
total:0,//服务器端收到0时会自动计算总记录数如果上传>0的不自动计算。
pageSize:10,//每页数据
count:true,//是否需要重新计算总记录数
pageNum:1,//当前页码、从1开始计算
orderFields:[],//排序列 如 ['sex','student_id'],必须为数据库字段
orderDirs:[]//升序 asc,降序desc 如 性别 升序、学生编号降序 ['asc','desc']
},
load:{ list: false, edit: false, del: false, add: false },//查询中...
sels: [],//列表选中数据
dicts:{
//sex: [{id:'1',name:'男'},{id:'2',name:'女'}]
},//下拉选择框的所有静态数据 params={categoryId:'all',itemCodes:['sex']} 返回结果 {sex: [{id:'1',name:'男'},{id:'2',name:'女'}]}
addFormVisible: false,//新增xmBudgetLabor界面是否显示
addForm: {
projectId:'',userid:'',budgetAt:'',id:'',remark:'',username:'',subjectId:'',bizSdate:'',bizEdate:'',bizMonth:'',instId:'',bizFlowState:'',costType:'',subjectName:'',branchId:'',ubranchId:''
},
editFormVisible: false,//编辑界面是否显示
editForm: {
projectId:'',userid:'',budgetAt:'',id:'',remark:'',username:'',subjectId:'',bizSdate:'',bizEdate:'',bizMonth:'',instId:'',bizFlowState:'',costType:'',subjectName:'',branchId:'',ubranchId:''
},
maxTableHeight:300,
}
},//end data
methods: {
...util,
handleSizeChange(pageSize) {
this.pageInfo.pageSize=pageSize;
this.getXmBudgetLabors();
},
handleCurrentChange(pageNum) {
this.pageInfo.pageNum = pageNum;
this.getXmBudgetLabors();
},
// 表格排序 obj.order=ascending/descending,需转化为 asc/desc ; obj.prop=表格中的排序字段,字段驼峰命名
sortChange( obj ){
if(obj.order==null){
this.pageInfo.orderFields=[];
this.pageInfo.orderDirs=[];
}else{
var dir='asc';
if(obj.order=='ascending'){
dir='asc'
}else{
dir='desc';
}
this.pageInfo.orderFields=[util.toLine(obj.prop)];
this.pageInfo.orderDirs=[dir];
}
this.getXmBudgetLabors();
},
searchXmBudgetLabors(){
this.pageInfo.count=true;
this.getXmBudgetLabors();
},
//获取列表 XmBudgetLabor 项目人力成本预算
getXmBudgetLabors() {
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
total: this.pageInfo.total,
count:this.pageInfo.count
};
if(this.pageInfo.orderFields!=null && this.pageInfo.orderFields.length>0){
let orderBys=[];
for(var i=0;i<this.pageInfo.orderFields.length;i++){
orderBys.push(this.pageInfo.orderFields[i]+" "+this.pageInfo.orderDirs[i])
}
params.orderBy= orderBys.join(",")
}
if(this.filters.key){
params.key=this.filters.key
}
this.load.list = true;
listXmBudgetLabor(params).then((res) => {
var tips=res.tips;
if(tips.isOk){
this.pageInfo.total = res.total;
this.pageInfo.count=false;
this.xmBudgetLabors = res.data;
}else{
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: 'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
},
//显示编辑界面 XmBudgetLabor 项目人力成本预算
showEdit: function ( row,index ) {
this.editFormVisible = true;
this.editForm = Object.assign({}, row);
},
//显示新增界面 XmBudgetLabor 项目人力成本预算
showAdd: function () {
this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm);
},
afterAddSubmit(){
this.addFormVisible=false;
this.pageInfo.count=true;
this.getXmBudgetLabors();
},
afterEditSubmit(){
this.editFormVisible=false;
},
//选择行xmBudgetLabor
selsChange: function (sels) {
this.sels = sels;
},
//删除xmBudgetLabor
handleDel: function (row,index) {
this.$confirm('确认删除该记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
let params = { id:row.id };
delXmBudgetLabor(params).then((res) => {
this.load.del=false;
var tips=res.tips;
if(tips.isOk){
this.searchXmBudgetLabors();
}
this.$notify({ position:'bottom-left', showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.del=false );
});
},
//批量删除xmBudgetLabor
batchDel: function () {
if(this.sels.length<=0){
return;
}
var params=this.sels.map(i=>{
return { id:i.id}
})
this.$confirm('确认删除选中记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
batchDelXmBudgetLabor(params).then((res) => {
this.load.del=false;
var tips=res.tips;
if( tips.isOk ){
this.searchXmBudgetLabors();
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error'});
}).catch( err => this.load.del=false );
});
},
editSomeFields(row,fieldName,$event){
let params={};
if(this.sels.length>0){
if(!this.sels.some(k=> k.id==row.id)){
this.$notify({position:'bottom-left',showClose:true,message:'请编辑选中的行',type:'warning'})
Object.assign(this.editForm,this.editFormBak)
return;
}
params['ids']=this.sels.map(i=>i.id)
}else{
params['ids']=[row].map(i=>i.id)
}
params[fieldName]=$event
var func = editSomeFieldsXmBudgetLabor
func(params).then(res=>{
let tips = res.tips;
if(tips.isOk){
if(this.sels.length>0){
this.searchXmBudgetLabors();
}
this.editFormBak=[...this.editForm]
}else{
Object.assign(this.editForm,this.editFormBak)
this.$notify({position:'bottom-left',showClose:true,message:tips.msg,type:tips.isOk?'success':'error'})
}
}).catch((e)=>Object.assign(this.editForm,this.editFormBak))
},
rowClick: function(row, event, column){
this.editForm=row
this.editFormBak={...row};
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
initData: function(){
},
},//end methods
mounted() {
this.$nextTick(() => {
this.initData()
this.searchXmBudgetLabors();
//this.maxTableHeight =util.calcTableMaxHeight(this.$refs.xmBudgetLaborTable.$el)
});
}
}
</script>
<style scoped />

View File

@@ -1,159 +0,0 @@
<template>
<el-row class="page-header" />
<el-row class="page-main" :style="{overflowX:'auto',height:maxTableHeight+'px'}" ref="table">
<!--编辑界面 XmBudgetNlabor 项目人力成本预算-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editFormRef">
<el-form-item label="项目编号" prop="projectId">
<el-input v-model="editForm.projectId" placeholder="项目编号" :maxlength="50" disabled/>
</el-form-item>
<el-form-item label="预算金额/每月" prop="budgetAt">
<el-input v-model="editForm.budgetAt" placeholder="预算金额/每月" :maxlength="10"/>
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input v-model="editForm.remark" placeholder="备注" />
</el-form-item>
<el-form-item label="预算科目" prop="subjectId">
<mdp-select item-code="projectSubject" placeholder="预算科目编号" v-model="editForm.subjectId"/>
</el-form-item>
<el-form-item label="预算月份" prop="bizMonth">
<el-date-picker
v-model="editForm.bizMonth"
type="month"
value-format="yyyy-MM"
placeholder="选择年月">
</el-date-picker>
</el-form-item>
</el-form>
</el-row>
<el-row class="page-bottom bottom-fixed">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="saveSubmit" :disabled="load.edit==true">提交</el-button>
</el-row>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from "@/api/mdp_pub/mdp_config"; //全局公共库import
import { addXmBudgetNlabor,editXmBudgetNlabor } from '@/api/xm/pro/xmBudgetNlabor';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
name:'xmBudgetNlaborEdit',
components: {
},
computed: {
...mapState(useUserStore,[ 'userInfo' ]),
},
props:['xmBudgetNlabor','visible','opType'],
watch: {
'xmBudgetNlabor':function( xmBudgetNlabor ) {
if(xmBudgetNlabor){
this.editForm = {...xmBudgetNlabor};
}
},
'visible':function(visible) {
if(visible==true){
this.initData()
}
}
},
data() {
return {
currOpType:'add',//add/edit
load:{ list: false, edit: false, del: false, add: false },//查询中...
dicts:{
projectSubject:[],
},//下拉选择框的所有静态数据 params={categoryId:'all',itemCodes:['sex']} 返回结果 {sex: [{id:'1',name:'男'},{id:'2',name:'女'}]}
editFormRules: {
subjectId: [
{ required: true, message: '科目不能为空', trigger: 'change' }
],
username: [
{ required: true, message: '姓名不能为空,如果不确定具体人,请填写岗位代替', trigger: 'change' }
],
budgetAt: [
{ required: true, message: '金额不能为空', trigger: 'change' }
],
remark: [
{ required: true, message: '用途说明不能为空', trigger: 'change' }
]
},
editForm: {
id:'',projectId:'',budgetAt:'',remark:'',subjectId:'',bizSdate:'',bizEdate:'',instId:'',bizFlowState:'',costType:'',bizMonth:'',subjectName:'',branchId:''
},
maxTableHeight:300,
}//end return
},//end data
methods: {
...util,
// 取消按钮点击 父组件监听@cancel="editFormVisible=false" 监听
handleCancel:function(){
this.$refs['editFormRef'].resetFields();
this.$emit('cancel');
},
//新增、编辑提交XmBudgetNlabor 项目人力成本预算父组件监听@submit="afterEditSubmit"
saveSubmit: function () {
this.$refs.editFormRef.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
let params = Object.assign({}, this.editForm);
var func=addXmBudgetNlabor
if(this.currOpType=='edit'){
func=editXmBudgetNlabor
}
func(params).then((res) => {
this.load.edit=false
var tips=res.tips;
if(tips.isOk){
this.editForm=res.data
this.initData()
this.currOpType="edit";
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err =>this.load.edit=false);
});
}else{
this.$notify({ showClose:true, message: "表单验证不通过,请修改表单数据再提交", type: 'error' });
}
});
},
initData: function(){
this.currOpType=this.opType
if(this.xmBudgetNlabor){
this.editForm = Object.assign({},this.xmBudgetNlabor);
}
if(this.opType=='edit'){
}else{
}
},
},//end method
mounted() {
this.$nextTick(() => {
this.initData()
//this.maxTableHeight =util.calcTableMaxHeight(this.$refs.table.$el)
});
}
}
</script>
<style scoped />

View File

@@ -1,338 +0,0 @@
<template>
<el-row>
<el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询"/>
<el-button v-loading="load.list" :disabled="load.list==true" @click="searchXmBudgetNlabors" icon="search">查询</el-button>
<span style="float:right;">
<el-button type="primary" @click="showAdd" icon="plus" plain/>
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length===0 || load.del==true" icon="delete" plain/>
</span>
</el-row>
<el-row class="padding-top">
<!--列表 XmBudgetNlabor 项目人力成本预算-->
<el-table ref="xmBudgetNlaborTable" :data="xmBudgetNlabors" v-adaptive="{bottom:50}" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column type="selection" width="55" show-overflow-tooltip fixed="left" />
<el-table-column sortable type="index" width="55" show-overflow-tooltip fixed="left" />
<!--
<el-table-column sortable prop="username" width="55" show-overflow-tooltip fixed="left">
<span class="cell-text"> {{scope.row.username}}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder="" @change="editSomeFields(scope.row,'username',$event)" :maxlength="22"/></span>
</el-table-column>
-->
<el-table-column prop="projectId" label="项目编号" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.projectId}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder="" @change="editSomeFields(scope.row,'username',$event)" :maxlength="22"/></span>
</template>
</el-table-column>
<el-table-column prop="remark" label="用途说明" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.remark}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.remark" placeholder="" @change="editSomeFields(scope.row,'remark',$event)" :maxlength="22"/></span>
</template>
</el-table-column>
<el-table-column prop="budgetAt" label="预算金额" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.budgetAt}} </span>
<span class="cell-bar"><el-input type="number" style="display:inline;" v-model="scope.row.budgetAt" placeholder="" @change="editSomeFields(scope.row,'budgetAt',$event)" :maxlength="22"/></span>
</template>
</el-table-column>
<el-table-column prop="subjectId" label="预算科目" min-width="80" show-overflow-tooltip>
<template #default="scope">
<div class="cell-text">
{{formatDicts(dicts,'projectSubject',scope.row.subjectId)}}
</div>
<span class="cell-bar">
<el-select v-model="scope.row.subjectId" placeholder="预算科目" style="display:block;" @change="editSomeFields(scope.row,'subjectId',$event)">
<el-option :value="item.id" :label="item.name" v-for="(item,index) in dicts.projectSubject" :key="index"/>
</el-select>
</span>
</template>
</el-table-column>
<el-table-column prop="bizMonth" label="费用月份" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{scope.row.bizMonth}} </span>
<span class="cell-bar">
<el-date-picker
@change="editSomeFields(scope.row,'bizMonth',$event)"
v-model="scope.row.bizMonth"
type="month"
value-format="yyyy-MM"
placeholder="选择年月" />
</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button type="primary" @click="showEdit( scope.row,scope.$index)" icon="edit" plain/>
<el-button type="danger" @click="handleDel(scope.row,scope.$index)" icon="delete" plain/>
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange" @size-change="handleSizeChange" :page-sizes="[10,20, 50, 100, 500]" :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;" />
</el-row>
<el-row>
<!--编辑 XmBudgetNlabor 项目人力成本预算界面-->
<mdp-dialog title="编辑项目非人力预算" v-model="editFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<xm-budget-nlabor-edit op-type="edit" :xm-budget-nlabor="editForm" :visible="editFormVisible" @cancel="editFormVisible=false" @submit="afterEditSubmit" />
</mdp-dialog>
<!--新增 XmBudgetNlabor 项目人力成本预算界面-->
<mdp-dialog title="新增项目非人力预算" v-model="addFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<xm-budget-nlabor-add op-type="add" :sel-project="selProject" :visible="addFormVisible" @cancel="addFormVisible=false" @submit="afterAddSubmit" />
</mdp-dialog>
</el-row>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from '@/api/mdp_pub/mdp_config';//全局公共库
import { listXmBudgetNlabor, delXmBudgetNlabor, batchDelXmBudgetNlabor,editSomeFieldsXmBudgetNlabor } from '@/api/xm/pro/xmBudgetNlabor';
import XmBudgetNlaborEdit from './XmBudgetNlaborEdit.vue';//新增修改界面
import XmBudgetNlaborAdd from './XmBudgetNlaborAdd.vue';//新增修改界面
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
name:'xmBudgetNlaborMng',
components: {
XmBudgetNlaborEdit,XmBudgetNlaborAdd
},
props:["selProject",'xmBudgetNlabor','fieldName','queryType','visible'],
computed: {
...mapState(useUserStore,['userInfo']),
},
watch:{
visible(val){
if(val==true){
this.initData();
this.searchXmBudgetNlabors()
}
}
},
data() {
return {
filters: {
key: ''
},
xmBudgetNlabors: [],//查询结果
pageInfo:{//分页数据
total:0,//服务器端收到0时会自动计算总记录数如果上传>0的不自动计算。
pageSize:10,//每页数据
count:true,//是否需要重新计算总记录数
pageNum:1,//当前页码、从1开始计算
orderFields:[],//排序列 如 ['sex','student_id'],必须为数据库字段
orderDirs:[]//升序 asc,降序desc 如 性别 升序、学生编号降序 ['asc','desc']
},
load:{ list: false, edit: false, del: false, add: false },//查询中...
sels: [],//列表选中数据
dicts:{
//sex: [{id:'1',name:'男'},{id:'2',name:'女'}]
},//下拉选择框的所有静态数据 params={categoryId:'all',itemCodes:['sex']} 返回结果 {sex: [{id:'1',name:'男'},{id:'2',name:'女'}]}
addFormVisible: false,//新增xmBudgetNlabor界面是否显示
addForm: {
id:'',projectId:'',budgetAt:'',remark:'',subjectId:'',bizSdate:'',bizEdate:'',instId:'',bizFlowState:'',costType:'',bizMonth:'',subjectName:'',branchId:''
},
editFormVisible: false,//编辑界面是否显示
editForm: {
id:'',projectId:'',budgetAt:'',remark:'',subjectId:'',bizSdate:'',bizEdate:'',instId:'',bizFlowState:'',costType:'',bizMonth:'',subjectName:'',branchId:''
},
maxTableHeight:300,
}
},//end data
methods: {
...util,
handleSizeChange(pageSize) {
this.pageInfo.pageSize=pageSize;
this.getXmBudgetNlabors();
},
handleCurrentChange(pageNum) {
this.pageInfo.pageNum = pageNum;
this.getXmBudgetNlabors();
},
// 表格排序 obj.order=ascending/descending,需转化为 asc/desc ; obj.prop=表格中的排序字段,字段驼峰命名
sortChange( obj ){
if(obj.order==null){
this.pageInfo.orderFields=[];
this.pageInfo.orderDirs=[];
}else{
var dir='asc';
if(obj.order=='ascending'){
dir='asc'
}else{
dir='desc';
}
this.pageInfo.orderFields=[util.toLine(obj.prop)];
this.pageInfo.orderDirs=[dir];
}
this.getXmBudgetNlabors();
},
searchXmBudgetNlabors(){
this.pageInfo.count=true;
this.getXmBudgetNlabors();
},
//获取列表 XmBudgetNlabor 项目人力成本预算
getXmBudgetNlabors() {
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
total: this.pageInfo.total,
count:this.pageInfo.count
};
if(this.pageInfo.orderFields!=null && this.pageInfo.orderFields.length>0){
let orderBys=[];
for(var i=0;i<this.pageInfo.orderFields.length;i++){
orderBys.push(this.pageInfo.orderFields[i]+" "+this.pageInfo.orderDirs[i])
}
params.orderBy= orderBys.join(",")
}
if(this.filters.key){
params.key=this.filters.key
}
if(this.queryType=='queryByBizMonth'){
params.bizMonth=this.fieldName
params.username=this.budgetCostNouser.username
params.subjectId=this.budgetCostNouser.subjectId
}else if(this.queryType=='queryByUsername'){
params.username=this.budgetCostNouser.username
params.subjectId=this.budgetCostNouser.subjectId
}else if(this.queryType=='queryBySubjectId'){
params.subjectId=this.budgetCostNouser.subjectId
}
if(this.selProject!=null && this.selProject !=undefined){
params.projectId=this.selProject.id
}
this.load.list = true;
listXmBudgetNlabor(params).then((res) => {
var tips=res.tips;
if(tips.isOk){
this.pageInfo.total = res.total;
this.pageInfo.count=false;
this.xmBudgetNlabors = res.data;
}else{
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: 'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
},
//显示编辑界面 XmBudgetNlabor 项目人力成本预算
showEdit: function ( row,index ) {
this.editFormVisible = true;
this.editForm = Object.assign({}, row);
},
//显示新增界面 XmBudgetNlabor 项目人力成本预算
showAdd: function () {
this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm);
},
afterAddSubmit(){
this.addFormVisible=false;
this.pageInfo.count=true;
this.getXmBudgetNlabors();
},
afterEditSubmit(){
this.editFormVisible=false;
},
//选择行xmBudgetNlabor
selsChange: function (sels) {
this.sels = sels;
},
//删除xmBudgetNlabor
handleDel: function (row,index) {
this.$confirm('确认删除该记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
let params = { id:row.id };
delXmBudgetNlabor(params).then((res) => {
this.load.del=false;
var tips=res.tips;
if(tips.isOk){
this.searchXmBudgetNlabors();
}
this.$notify({ position:'bottom-left', showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.del=false );
});
},
//批量删除xmBudgetNlabor
batchDel: function () {
if(this.sels.length<=0){
return;
}
var params=this.sels.map(i=>{
return { id:i.id}
})
this.$confirm('确认删除选中记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
batchDelXmBudgetNlabor(params).then((res) => {
this.load.del=false;
var tips=res.tips;
if( tips.isOk ){
this.searchXmBudgetNlabors();
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error'});
}).catch( err => this.load.del=false );
});
},
editSomeFields(row,fieldName,$event){
let params={};
if(this.sels.length>0){
if(!this.sels.some(k=> k.id==row.id)){
this.$notify({position:'bottom-left',showClose:true,message:'请编辑选中的行',type:'warning'})
Object.assign(this.editForm,this.editFormBak)
return;
}
params['ids']=this.sels.map(i=>i.id)
}else{
params['ids']=[row].map(i=>i.id)
}
params[fieldName]=$event
var func = editSomeFieldsXmBudgetNlabor
func(params).then(res=>{
let tips = res.tips;
if(tips.isOk){
if(this.sels.length>0){
this.searchXmBudgetNlabors();
}
this.editFormBak=[...this.editForm]
}else{
Object.assign(this.editForm,this.editFormBak)
this.$notify({position:'bottom-left',showClose:true,message:tips.msg,type:tips.isOk?'success':'error'})
}
}).catch((e)=>Object.assign(this.editForm,this.editFormBak))
},
rowClick: function(row, event, column){
this.editForm=row
this.editFormBak={...row};
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
initData: function(){
},
},//end methods
mounted() {
this.$nextTick(() => {
this.initData()
this.searchXmBudgetNlabors();
//this.maxTableHeight =util.calcTableMaxHeight(this.$refs.xmBudgetNlaborTable.$el)
});
}
}
</script>
<style scoped />

View File

@@ -1,40 +1,54 @@
<template>
<el-row class="page-header" />
<el-row class="page-main" :style="{overflowX:'auto',height:maxTableHeight+'px'}" ref="table">
<!--编辑界面 XmBudgetLabor 项目人力成本预算-->
<!--编辑界面 XmBudgetRecord 项目人力成本预算-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editFormRef">
<el-form-item label="预算总金额" prop="totalBudgetAt">
<el-input type="number" style="width:40%;" v-model="totalBudgetAt" placeholder="预算金额"/> &nbsp;&nbsp;
&nbsp;&nbsp;平均&nbsp;{{editForm.budgetAt}} &nbsp;&nbsp; /
</el-form-item>
<el-form-item label="用户名称" prop="username">
<el-input v-model="editForm.username" placeholder="用户,如果不确定具体人员,可用岗位代替" />
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input v-model="editForm.remark" placeholder="备注" />
</el-form-item>
<el-form-item label="成本中心" prop="costCenterId">
<MdpSelectDept width="100%" v-model="editForm.costCenterId" placeholder="成本中心" title="成本中心"/>
</el-form-item>
<el-form-item label="预算科目" prop="subjectId">
<mdp-select item-code="projectSubject" placeholder="预算科目编号" v-model="editForm.subjectId"/>
<mdp-select width="100%" item-code="projectSubject" placeholder="预算科目编号" v-model="editForm.subjectId"/>
</el-form-item>
<el-form-item label="预算总金额">
<el-input type="number" v-model="totalBudgetAt" placeholder="预算总金额">
<template #suffix>,{{ parseInt(totalBudgetAt/10000) }}万元</template>
</el-input>
</el-form-item>
<el-form-item label="分摊月份" prop="bizMonth">
<el-space wrap fill>
<el-date-picker
v-model="bizYear"
type="year"
value-format="yyyy"
value-format="YYYY"
placeholder="选择年" />
<div style="margin-top: 20px">
<el-checkbox-group v-model="bizMonths" size="medium">
<div>
<el-checkbox-group v-model="bizMonths" >
<el-checkbox-button v-for="i in bizMonthList" :label="i" :key="i">{{i}}</el-checkbox-button>
</el-checkbox-group>
</div>
<div style="padding-top:20px;">下一年{{secBizYear}}</div>
<div style="margin-top: 20px">
<el-checkbox-group v-model="secBizMonths" size="medium">
</div>
<div>下一年{{secBizYear}}</div>
<div>
<el-checkbox-group v-model="secBizMonths" >
<el-checkbox-button v-for="i in bizMonthList" :label="i" :key="i">{{i}}</el-checkbox-button>
</el-checkbox-group>
</div>
</el-form-item>
</el-space>
</el-form-item>
<el-form-item label="预算金额" prop="budgetAt">
<div>{{ editForm.budgetAt||0 }} <el-text type="primary">/每月</el-text>
</div>
<div>
<el-text type="info"> {{ parseInt((editForm.budgetAt||0)/10000) }} 万元/每月</el-text>
</div>
</el-form-item>
<el-form-item label="费用主责" prop="userid">
<MdpSelectUser width="100%" v-model="editForm.userid" :init-name="editForm.username" @change2="($event)=>editForm.username=$event?.username" />
<el-text type="primary">如果无法确定具体人员请在备注说明方便后续修正</el-text>
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input type="textarea" v-model="editForm.remark" placeholder="备注" />
</el-form-item>
<!--
<el-form-item label="成本类型" prop="costType">
<template>
@@ -45,24 +59,25 @@
</el-form-item>
-->
</el-form>
</el-row>
<el-row class="page-bottom bottom-fixed">
<div class="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="saveSubmit" :disabled="load.edit==true">提交</el-button>
</el-row>
</div>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//
import config from "@/api/mdp_pub/mdp_config"; //import
import { addXmBudgetLabor,editXmBudgetLabor,batchAddXmBudgetLabor } from '@/api/xm/pro/xmBudgetLabor';
import { batchAddXmBudgetRecord,editXmBudgetRecord } from '@/api/xm/pro/xmBudgetRecord';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
name:'xmBudgetLaborEdit',
import {MdpFormMixin} from "@/components/mdp-ui/mixin/MdpFormMixin.js"
export default {
mixins:[MdpFormMixin],
name:'XmBudgetRecordAdd',
components: {
},
@@ -81,17 +96,17 @@ import { useUserStore } from '@/store/modules/user'
if(!this.totalBudgetAt){
return 0;
}
return Math.round(parseFloat(this.totalBudgetAt)/this.allMonths.length);
return parseFloat(this.totalBudgetAt)/this.allMonths.length;
}
},
props:['xmBudgetLabor','visible','opType','selProject'],
props:['formData','visible','subOpType','selProject'],
watch: {
'xmBudgetLabor':function( xmBudgetLabor ) {
if(xmBudgetLabor){
this.editForm = {...xmBudgetLabor};
'formData':function( formData ) {
if(formData){
this.editForm = {...formData};
}
},
@@ -113,10 +128,7 @@ import { useUserStore } from '@/store/modules/user'
var secYear=parseInt(year)+1;
return {
currOpType:'add',//add/edit
load:{ list: false, edit: false, del: false, add: false },//...
dicts:{
projectSubject:[],
},// params={categoryId:'all',itemCodes:['sex']} {sex: [{id:'1',name:''},{id:'2',name:''}]}
editFormRules: {
subjectId: [
{ required: true, message: '科目不能为空', trigger: 'change' }
@@ -128,14 +140,13 @@ import { useUserStore } from '@/store/modules/user'
{ required: true, message: '金额不能为空', trigger: 'change' }
],
remark: [
{ required: true, message: '用途说明不能为空', trigger: 'change' }
]
// remark: [
// { required: true, message: '', trigger: 'change' }
// ]
},
editForm: {
projectId:'',userid:'',budgetAt:'',id:'',remark:'',username:'',subjectId:'',bizSdate:'',bizEdate:'',bizMonth:'',instId:'',bizFlowState:'',costType:'',subjectName:'',branchId:'',ubranchId:''
},
maxTableHeight:300,
totalBudgetAt:0,
bizYear:year+'',
@@ -145,22 +156,18 @@ import { useUserStore } from '@/store/modules/user'
bizMonthList:['01','02','03','04','05','06','07','08','09','10','11','12'],
}//end return
},//end data
methods: {
...util,
// @cancel="editFormVisible=false"
handleCancel:function(){
this.$refs['editFormRef'].resetFields();
this.$emit('cancel');
},
//XmBudgetLabor @submit="afterEditSubmit"
methods: {
//XmBudgetRecord @submit="afterEditSubmit"
saveSubmit: function () {
if(this.bizYear==null || this.bizYear==''){
this.$notify({position:'bottom-left',showClose:true,message:"请选择需要分摊的年份", type: 'error' });
return;
}
if(this.allMonths.length<=0){
this.$notify({position:'bottom-left',showClose:true,message:"请选择需要分摊的月份", type: 'error' });
return;
}
var list=this.allMonths.map(i=>{
let params = Object.assign({}, this.editForm);
params.projectId=this.selProject.id
@@ -173,14 +180,11 @@ import { useUserStore } from '@/store/modules/user'
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
var func=batchAddXmBudgetLabor
var func=batchAddXmBudgetRecord
func(list).then((res) => {
this.load.edit=false
var tips=res.tips;
if(tips.isOk){
this.editForm=res.data
this.initData()
this.currOpType="edit";
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
@@ -191,25 +195,11 @@ import { useUserStore } from '@/store/modules/user'
}
});
},
initData: function(){
this.currOpType=this.opType
if(this.xmBudgetLabor){
this.editForm = Object.assign({},this.xmBudgetLabor);
}
if(this.opType=='edit'){
}else{
}
},
initCurrData: function(){
}
},//end method
mounted() {
this.$nextTick(() => {
this.initData()
//this.maxTableHeight =util.calcTableMaxHeight(this.$refs.table.$el)
});
mounted() {
}
}

View File

@@ -0,0 +1,105 @@
<template>
<!--编辑界面 XmBudgetRecord 项目人力成本预算-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editFormRef">
<el-form-item label="成本中心" prop="costCenterId">
<MdpSelectDept width="100%" v-model="editForm.costCenterId" placeholder="成本中心" title="成本中心"/>
</el-form-item>
<el-form-item label="项目编号" prop="projectId">
<el-input v-model="editForm.projectId" placeholder="项目编号" :maxlength="50" disabled/>
</el-form-item>
<el-form-item label="预算科目" prop="subjectId">
<mdp-select width="100%" item-code="projectSubject" placeholder="预算科目编号" v-model="editForm.subjectId"/>
</el-form-item>
<el-form-item label="预算金额" prop="budgetAt">
<el-input v-model="editForm.budgetAt" placeholder="预算金额/每月" type="number">
<template #suffix>/每月</template>
</el-input>
</el-form-item>
<el-form-item label="费用主责" prop="userid">
<MdpSelectUser width="100%" v-model="editForm.userid" :init-name="editForm.username" @change2="($event)=>editForm.username=$event?.username" />
<el-text type="primary">如果无法确定具体人员请在备注说明方便后续修正</el-text>
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input type="textarea" v-model="editForm.remark" placeholder="备注" />
</el-form-item>
<el-form-item label="预算月份" prop="bizMonth">
<el-date-picker
v-model="editForm.bizMonth"
type="month"
value-format="YYYY-MM"
placeholder="选择年月"/>
</el-form-item>
</el-form>
<el-row class="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="saveSubmit" :disabled="load.edit==true">提交</el-button>
</el-row>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from "@/api/mdp_pub/mdp_config"; //全局公共库import
import { addXmBudgetRecord,editXmBudgetRecord } from '@/api/xm/pro/xmBudgetRecord';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import {MdpFormMixin} from "@/components/mdp-ui/mixin/MdpFormMixin.js"
export default {
mixins:[MdpFormMixin],
name:'xmBudgetRecordEdit',
components: {
},
computed: {
...mapState(useUserStore,[ 'userInfo' ]),
},
props:['formData','visible','subOpType'],
watch: {
},
data() {
return {
currOpType:'add',//add/edit
load:{ list: false, edit: false, del: false, add: false },//查询中...
editFormRules: {
subjectId: [
{ required: true, message: '科目不能为空', trigger: 'change' }
],
username: [
{ required: true, message: '姓名不能为空,如果不确定具体人,请填写岗位代替', trigger: 'change' }
],
budgetAt: [
{ required: true, message: '金额不能为空', trigger: 'change' }
],
// remark: [
// { required: true, message: '用途说明不能为空', trigger: 'change' }
// ]
},
editForm: {
projectId:'',userid:'',budgetAt:'',id:'',remark:'',username:'',subjectId:'',bizSdate:'',bizEdate:'',bizMonth:'',instId:'',bizFlowState:'',costType:'',subjectName:'',branchId:'',ubranchId:''
},
apis:{
edit: editXmBudgetRecord,
}
}//end return
},//end data
methods: {
initCurrData: function(){
},
},//end method
mounted() {
}
}
</script>

View File

@@ -0,0 +1,194 @@
<template>
<ContentWrap>
<template #header>
<el-space>
<MdpSelectDept v-model="filters.costCenterId" placeholder="成本中心" title="成本中心"/>
<mdp-hi-query ref="hiQueryBtn" :column-configs="columnConfigs" v-model="hiQueryParams"
@change="onHiQueryParamsChange" />
<el-button icon="zoom-out" @click="searchReset()" title="重置查询条件并查询" ref="searchResetBtn" />
<el-button icon="download" @click="export2Excel()" title="导出当前结果数据" plain ref="downloadBtn" />
<mdp-table-configs :column-configs="columnConfigs" v-model="checkedColumns" ref="columnConfigsBtn" />
<el-button type="primary" @click="showAdd" icon="plus" plain />
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length === 0 || load.del == true"
icon="delete" plain />
</el-space>
</template>
<el-space>
<XmProjectSelect v-model="filters.projectId" @change2="project = $event" v-if="!selProject?.id" />
<mdp-select item-code="projectSubject" v-model="filters.subjectId" placeholder="科目" />
<mdp-date-range start-key="startBizMonth" end-key="endBizMonth" type="monthrange" v-model="filters" value-format="YYYY-MM" format="YYYY-MM" placeholder="统计时间" :clearable="false" />
<MdpSelect itemCode="bizFlowState" v-model="filters.bizFlowState" placeholder="审核状态"/>
<el-input v-model="filters.name" placeholder="姓名" />
<el-input v-model="filters.name" placeholder="用途" />
<el-button v-loading="load.list" :disabled="load.list == true" @click="searchTableDatas" icon="search">查询</el-button>
</el-space>
</ContentWrap>
<!--列表 XmBudgetRecord 项目成本预算-->
<el-table ref="table" :data="tableDatas" v-adaptive="{ bottom: 50 }" @sort-change="sortChange" highlight-current-row
v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column type="selection" width="55" show-overflow-tooltip fixed="left" />
<el-table-column sortable type="index" width="55" show-overflow-tooltip fixed="left" />
<!--
<el-table-column sortable prop="username" width="55" show-overflow-tooltip fixed="left">
<span class="cell-text"> {{scope.row.username}}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder="" @change="editSomeFields(scope.row,'username',$event)" :maxlength="22"/></span>
</el-table-column>
-->
<el-table-column prop="projectId" label="项目编号" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span> {{ scope.row.projectId }} </span>
</template>
</el-table-column>
<el-table-column prop="bizFlowState" label="审核状态" min-width="80" show-overflow-tooltip>
<template #default="scope">
<MdpSelect itemCode="bizFlowState" v-model="scope.row.bizFlowState" showStyle="tag" @change="editSomeFields(scope.row, 'bizFlowState', $event)"/>
</template>
</el-table-column>
<el-table-column prop="username" label="主责" min-width="80" show-overflow-tooltip/>
<el-table-column prop="subjectId" label="预算科目" min-width="80" show-overflow-tooltip>
<template #default="scope">
<mdp-select item-code="projectSubject" show-style="tag" v-model="scope.row.subjectId" placeholder="预算科目" @change="editSomeFields(scope.row, 'subjectId', $event)" />
</template>
</el-table-column>
<el-table-column prop="remark" label="用途说明" min-width="80" show-overflow-tooltip/>
<el-table-column prop="budgetAt" label="预算金额" min-width="80" show-overflow-tooltip>
<template #default="scope">
{{$mdp.toFixed(scope.row.budgetAt,2)}}
</template>
</el-table-column>
<el-table-column prop="bizMonth" label="费用月份" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{ scope.row.bizMonth }} </span>
<span class="cell-bar">
<el-date-picker @change="editSomeFields(scope.row, 'bizMonth', $event)" v-model="scope.row.bizMonth" type="month"
value-format="YYYY-MM" placeholder="选择年月" />
</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="scope">
<el-button type="warning" @click="showSplit(scope.row, scope.$index)" icon="operation" plain title="费用拆分"/>
<el-button type="primary" @click="showEdit(scope.row, scope.$index)" icon="edit" plain />
<el-button type="danger" @click="handleDel(scope.row, scope.$index)" icon="delete" plain />
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange"
@size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100, 500]" :current-page="pageInfo.pageNum"
:page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;" />
<!--编辑 XmBudgetRecord 项目成本预算界面-->
<mdp-dialog title="编辑项目预算" v-model="editFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<XmBudgetRecordEdit sub-op-type="edit" :formData="editForm" :visible="editFormVisible"
@cancel="editFormVisible = false" @submit="afterEditSubmit" />
</mdp-dialog>
<mdp-dialog title="新增项目预算" v-model="addFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<XmBudgetRecordAdd sub-op-type="add" :selProject="project||(params.projectId?{id:params.projectId,name:params.projectId}:null)" :visible="addFormVisible"
@cancel="addFormVisible = false" @submit="afterAddSubmit" />
</mdp-dialog>
<!--新增 XmBudgetRecord 项目成本预算界面-->
<mdp-dialog ref="splitDlg" title="拆分项目预算" width="60%" append-to-body :close-on-click-modal="false">
<template #default="{dialog,data}">
<XmBudgetRecordSplit sub-op-type="split" :formData="data.formData"
@cancel="dialog.close()" @submit="afterAddSubmit;dialog.close()" />
</template>
</mdp-dialog>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from '@/api/mdp_pub/mdp_config';//全局公共库
import { listXmBudgetRecord, delXmBudgetRecord, batchDelXmBudgetRecord, editSomeFieldsXmBudgetRecord, addXmBudgetRecord, editXmBudgetRecord } from '@/api/xm/pro/xmBudgetRecord';
import XmBudgetRecordEdit from './EditForm.vue';//新增修改界面
import XmBudgetRecordAdd from './AddForm.vue';//新增修改界面
import XmBudgetRecordSplit from './SplitForm.vue';//新增修改界面
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import { MdpTableMixin } from '@/components/mdp-ui/mixin/MdpTableMixin.js'
import XmProjectSelect from '@/views/xm/core/components/XmProjectSelect.vue'
export default {
mixins: [MdpTableMixin],
name: 'xmBudgetRecordMng',
components: {
XmBudgetRecordEdit, XmBudgetRecordAdd, XmProjectSelect,XmBudgetRecordSplit
},
props: ['visible', "selProject"],
computed: {
...mapState(useUserStore, ['userInfo']),
},
watch: {
visible(val) {
if (val == true) {
this.initData();
this.searchTableDatas()
}
}
},
data() {
return {
filters: {
name: '',
remark: '',
subjectId: '',
startBizMonth:'',
endBizMonth:'',
projectId:'',
},
addForm: {
projectId: '', userid: '', budgetAt: '', id: '', remark: '', username: '', subjectId: '', bizSdate: '', bizEdate: '', bizMonth: '', instId: '', bizFlowState: '', costType: '', subjectName: '', branchId: '', ubranchId: ''
},
editForm: {
projectId: '', userid: '', budgetAt: '', id: '', remark: '', username: '', subjectId: '', bizSdate: '', bizEdate: '', bizMonth: '', instId: '', bizFlowState: '', costType: '', subjectName: '', branchId: '', ubranchId: ''
},
apis: {
list: listXmBudgetRecord,
add: addXmBudgetRecord,
edit: editXmBudgetRecord,
del: delXmBudgetRecord,
batchDel: batchDelXmBudgetRecord,
editSomeFields: editSomeFieldsXmBudgetRecord,
},
}
},//end data
methods: {
//获取列表 XmBudgetRecord 项目成本预算
preQueryParamCheck(params) {
return true;
},
editSomeFieldsCheck(row, fieldName, $event, params) {
params[fieldName] = $event
return true;
},
initCurrData: function () {
},
showAdd(){
if(!this.project?.id && !this.params.projectId){
this.$message.warning("请先选中项目")
return
}
this.addFormVisible=true
},
showSplit(row){
this.editForm=row
this.$refs.splitDlg.open({formData:row})
}
},//end methods
mounted() {
this.filters.startBizMonth=this.$mdp.moment().startOf('year').format("YYYY-MM")
this.filters.endBizMonth=this.$mdp.moment().endOf('year').format("YYYY-MM")
this.searchTableDatas();
}
}
</script>
<style scoped />

View File

@@ -1,37 +1,60 @@
<template>
<el-row class="page-header" />
<el-row class="page-main" :style="{overflowX:'auto',height:maxTableHeight+'px'}" ref="table">
<!--编辑界面 XmBudgetNlabor 项目人力成本预算-->
<!--编辑界面 XmBudgetRecord 项目人力成本预算-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editFormRef">
<el-form-item label="预算总金额" prop="totalBudgetAt">
<el-input type="number" style="width:40%;" v-model="totalBudgetAt" placeholder="预算金额"/> &nbsp;&nbsp;
&nbsp;&nbsp;平均&nbsp;{{editForm.budgetAt}} &nbsp;&nbsp; /
<el-form-item label="成本中心" prop="costCenterId">
<MdpSelectDept width="100%" v-model="editForm.costCenterId" placeholder="成本中心" title="成本中心"/>
</el-form-item>
<el-form-item label="原预算科目" prop="subjectId">
<mdp-select width="100%" item-code="projectSubject" placeholder="预算科目编号" :modelValue="formData.subjectId"/>
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input v-model="editForm.remark" placeholder="备注" />
<el-form-item label="原预算总金额">
{{formData?.budgetAt||0}},{{ parseInt((formData?.budgetAt||0)/10000) }}万元
</el-form-item>
<el-form-item label="拆分总金额">
<el-input type="number" v-model="totalBudgetAt" placeholder="拆分金额">
<template #suffix>,{{ parseInt(totalBudgetAt/10000) }}万元</template>
</el-input>
</el-form-item>
<el-form-item label="新预算科目" prop="subjectId">
<mdp-select width="100%" item-code="projectSubject" placeholder="预算科目编号" :modelValue="editForm.subjectId"/>
</el-form-item>
<el-form-item label="预算科目" prop="subjectId">
<mdp-select item-code="projectSubject" placeholder="预算科目编号" v-model="editForm.subjectId"/>
</el-form-item>
<el-form-item label="分摊月份" prop="bizMonth">
<el-space wrap fill>
<el-date-picker
v-model="bizYear"
type="year"
value-format="yyyy"
value-format="YYYY"
placeholder="选择年" />
<div style="margin-top: 20px">
<el-checkbox-group v-model="bizMonths" size="medium">
<div>
<el-checkbox-group v-model="bizMonths" >
<el-checkbox-button v-for="i in bizMonthList" :label="i" :key="i">{{i}}</el-checkbox-button>
</el-checkbox-group>
</div>
<div style="padding-top:20px;">下一年{{secBizYear}}</div>
<div style="margin-top: 20px">
<el-checkbox-group v-model="secBizMonths" size="medium">
</div>
<div>下一年{{secBizYear}}</div>
<div>
<el-checkbox-group v-model="secBizMonths" >
<el-checkbox-button v-for="i in bizMonthList" :label="i" :key="i">{{i}}</el-checkbox-button>
</el-checkbox-group>
</div>
</el-form-item>
</el-space>
</el-form-item>
<el-form-item label="预算金额" prop="budgetAt">
<div>{{ editForm.budgetAt||0 }} <el-text type="primary">/每月</el-text>
</div>
<div>
<el-text type="info"> {{ parseInt((editForm.budgetAt||0)/10000) }} 万元/每月</el-text>
</div>
</el-form-item>
<el-form-item label="费用主责" prop="userid">
<MdpSelectUser width="100%" v-model="editForm.userid" :init-name="editForm.username" @change2="($event)=>editForm.username=$event?.username" />
<el-text type="primary">如果无法确定具体人员请在备注说明方便后续修正</el-text>
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input type="textarea" v-model="editForm.remark" placeholder="备注" />
</el-form-item>
<!--
<el-form-item label="成本类型" prop="costType">
<template>
@@ -42,24 +65,23 @@
</el-form-item>
-->
</el-form>
</el-row>
<el-row class="page-bottom bottom-fixed">
<div class="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click="saveSubmit" :disabled="load.edit==true">提交</el-button>
</el-row>
</div>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//
import config from "@/api/mdp_pub/mdp_config"; //import
import { addXmBudgetNlabor,editXmBudgetNlabor,batchAddXmBudgetNlabor } from '@/api/xm/pro/xmBudgetNlabor';
<script>
import { splitXmBudgetRecord } from '@/api/xm/pro/xmBudgetRecord';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
export default {
name:'xmBudgetNlaborEdit',
import {MdpFormMixin} from "@/components/mdp-ui/mixin/MdpFormMixin.js"
export default {
mixins:[MdpFormMixin],
name:'XmBudgetRecordAdd',
components: {
},
@@ -78,17 +100,17 @@ import { useUserStore } from '@/store/modules/user'
if(!this.totalBudgetAt){
return 0;
}
return Math.round(parseFloat(this.totalBudgetAt)/this.allMonths.length);
return parseFloat(this.totalBudgetAt)/this.allMonths.length;
}
},
props:['xmBudgetNlabor','visible','opType','selProject'],
props:['formData','visible','subOpType'],
watch: {
'xmBudgetNlabor':function( xmBudgetNlabor ) {
if(xmBudgetNlabor){
this.editForm = {...xmBudgetNlabor};
'formData':function( formData ) {
if(formData){
this.editForm = {...formData};
}
},
@@ -103,47 +125,32 @@ import { useUserStore } from '@/store/modules/user'
'budgetAt': function(budgetAt){
this.editForm.budgetAt=budgetAt;
} ,
'editForm.subjectId':function(subjectId) {
var dicts=this.dicts.projectSubject.filter(i=>i.id==subjectId)
if( dicts!=null && dicts.length>0 ){
this.editForm.subjectName=dicts[0].name
}else{
this.editForm.subjectName="";
}
}
} ,
},
data() {
var year=new Date().getFullYear();
var secYear=parseInt(year)+1;
return {
currOpType:'add',//add/edit
load:{ list: false, edit: false, del: false, add: false },//...
dicts:{
projectSubject:[],
},// params={categoryId:'all',itemCodes:['sex']} {sex: [{id:'1',name:''},{id:'2',name:''}]}
editFormRules: {
subjectId: [
{ required: true, message: '科目不能为空', trigger: 'change' }
],
/**
username: [
{ required: true, message: '姓名不能为空', trigger: 'change' }
],
*/
username: [
{ required: true, message: '姓名不能为空,如果不确定具体人,请填写岗位代替', trigger: 'change' }
],
budgetAt: [
{ required: true, message: '金额不能为空', trigger: 'change' }
],
remark: [
{ required: true, message: '用途说明不能为空', trigger: 'change' }
]
// remark: [
// { required: true, message: '', trigger: 'change' }
// ]
},
editForm: {
id:'',projectId:'',budgetAt:'',remark:'',subjectId:'',bizSdate:'',bizEdate:'',instId:'',bizFlowState:'',costType:'',bizMonth:'',subjectName:'',branchId:''
projectId:'',userid:'',budgetAt:'',id:'',remark:'',username:'',subjectId:'',bizSdate:'',bizEdate:'',bizMonth:'',instId:'',bizFlowState:'',costType:'',subjectName:'',branchId:'',ubranchId:''
},
maxTableHeight:300,
totalBudgetAt:0,
bizYear:year+'',
@@ -153,25 +160,20 @@ import { useUserStore } from '@/store/modules/user'
bizMonthList:['01','02','03','04','05','06','07','08','09','10','11','12'],
}//end return
},//end data
methods: {
...util,
// @cancel="editFormVisible=false"
handleCancel:function(){
this.$refs['editFormRef'].resetFields();
this.$emit('cancel');
},
//XmBudgetNlabor @submit="afterEditSubmit"
methods: {
//XmBudgetRecord @submit="afterEditSubmit"
saveSubmit: function () {
if(this.bizYear==null || this.bizYear==''){
this.$notify({position:'bottom-left',showClose:true,message:"请选择需要分摊的年份", type: 'error' });
return;
}
if(this.allMonths.length<=0){
this.$notify({position:'bottom-left',showClose:true,message:"请选择需要分摊的月份", type: 'error' });
return;
}
var list=this.allMonths.map(i=>{
let params = Object.assign({}, this.editForm);
params.projectId=this.selProject.id
let params = Object.assign({}, this.editForm);
params.bizMonth=i
return params;
@@ -181,14 +183,11 @@ import { useUserStore } from '@/store/modules/user'
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
var func=batchAddXmBudgetNlabor
func(list).then((res) => {
var func=splitXmBudgetRecord
func({parentId:this.formData.id,splits:list}).then((res) => {
this.load.edit=false
var tips=res.tips;
if(tips.isOk){
this.editForm=res.data
this.initData()
this.currOpType="edit";
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
@@ -199,25 +198,13 @@ import { useUserStore } from '@/store/modules/user'
}
});
},
initData: function(){
this.currOpType=this.opType
if(this.xmBudgetNlabor){
this.editForm = Object.assign({},this.xmBudgetNlabor);
}
if(this.opType=='edit'){
}else{
}
},
initCurrData: function(){
this.totalBudgetAt=this.formData.budgetAt
this.bizYear=this.formData.bizMonth.substring(0,4)
}
},//end method
mounted() {
this.$nextTick(() => {
this.initData()
//this.maxTableHeight =util.calcTableMaxHeight(this.$refs.table.$el)
});
mounted() {
}
}

View File

@@ -1,182 +0,0 @@
<template>
<ContentWrap>
<template #header>
<el-space>
<mdp-hi-query ref="hiQueryBtn" :column-configs="columnConfigs" v-model="hiQueryParams"
@change="onHiQueryParamsChange" />
<el-button icon="zoom-out" @click="searchReset()" title="重置查询条件并查询" ref="searchResetBtn" />
<el-button icon="download" @click="export2Excel()" title="导出当前结果数据" plain ref="downloadBtn" />
<mdp-table-configs :column-configs="columnConfigs" v-model="checkedColumns" ref="columnConfigsBtn" />
<el-button type="primary" @click="showAdd" icon="plus" plain />
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length === 0 || load.del == true"
icon="delete" plain />
</el-space>
</template>
<el-space>
<el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询" />
<el-button v-loading="load.list" :disabled="load.list == true" @click="searchTableDatas" icon="search">查询</el-button>
</el-space>
</ContentWrap>
<!--列表 XmCostNlabor 项目实际人工成本费用-->
<el-table ref="tableDatas" :data="tableDatas" v-adaptive="{ bottom: 50 }" @sort-change="sortChange" highlight-current-row
v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column type="selection" width="55" show-overflow-tooltip fixed="left" />
<el-table-column sortable type="index" width="55" show-overflow-tooltip fixed="left" />
<!--
<el-table-column sortable prop="username" width="55" show-overflow-tooltip fixed="left">
<span class="cell-text"> {{scope.row.username}}} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder="" @change="editSomeFields(scope.row,'username',$event)" :maxlength="22"/></span>
</el-table-column>
-->
<el-table-column prop="projectName" label="项目名称" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span> {{ scope.row.projectName }} </span>
</template>
</el-table-column>
<el-table-column prop="username" label="费用主责" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{ scope.row.username }} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.username" placeholder=""
@change="editSomeFields(scope.row, 'username', $event)" :maxlength="22" /></span>
</template>
</el-table-column>
<el-table-column prop="remark" label="用途说明" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{ scope.row.remark }} </span>
<span class="cell-bar"><el-input style="display:inline;" v-model="scope.row.remark" placeholder=""
@change="editSomeFields(scope.row, 'remark', $event)" :maxlength="22" /></span>
</template>
</el-table-column>
<el-table-column prop="actAt" label="实际金额" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{ scope.row.actAt }} </span>
<span class="cell-bar"><el-input type="number" style="display:inline;" v-model="scope.row.actAt" placeholder=""
@change="editSomeFields(scope.row, 'actAt', $event)" :maxlength="22" /></span>
</template>
</el-table-column>
<el-table-column prop="subjectId" label="成本科目" min-width="80" show-overflow-tooltip>
<template #default="scope">
<mdp-select item-code="projectSubject" width="100%" show-style="tag" v-model="scope.row.subjectId" placeholder="成本科目" @change="editSomeFields(scope.row, 'subjectId', $event)" />
</template>
</el-table-column>
<el-table-column prop="bizMonth" label="费用月份" min-width="80" show-overflow-tooltip>
<template #default="scope">
<span class="cell-text"> {{ scope.row.bizMonth }} </span>
<span class="cell-bar">
<el-date-picker @change="editSomeFields(scope.row, 'bizMonth', $event)" v-model="scope.row.bizMonth" type="month"
value-format="yyyy-MM" placeholder="选择年月" />
</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button type="primary" @click="showEdit(scope.row, scope.$index)" icon="edit" plain />
<el-button type="danger" @click="handleDel(scope.row, scope.$index)" icon="delete" plain />
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange"
@size-change="handleSizeChange" :page-sizes="[10, 20, 50, 100, 500]" :current-page="pageInfo.pageNum"
:page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;" />
<!--编辑 XmCostNlabor 项目实际人工成本费用界面-->
<mdp-dialog title="编辑项目非人力费用" v-model="editFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<xm-cost-nlabor-edit sub-op-type="edit" :formData="editForm" :visible="editFormVisible"
@cancel="editFormVisible = false" @submit="afterEditSubmit" />
</mdp-dialog>
<!--新增 XmCostNlabor 项目实际人工成本费用界面-->
<mdp-dialog title="新增项目非人力费用" v-model="addFormVisible" width="60%" append-to-body :close-on-click-modal="false">
<xm-cost-nlabor-edit sub-op-type="add" :sel-project="selProject" :visible="addFormVisible" @cancel="addFormVisible = false"
@submit="afterAddSubmit" />
</mdp-dialog>
</template>
<script>
import util from '@/components/mdp-ui/js/util';//全局公共库
import config from '@/api/mdp_pub/mdp_config';//全局公共库
import { listXmCostNlabor, delXmCostNlabor, batchDelXmCostNlabor, editSomeFieldsXmCostNlabor } from '@/api/xm/pro/xmCostNlabor';
import XmCostNlaborEdit from './XmCostNlaborEdit.vue';//新增修改界面
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import { MdpTableMixin } from '@/components/mdp-ui/mixin/MdpTableMixin.js'
export default {
mixins: [MdpTableMixin],
name: 'xmCostNlaborMng',
components: {
XmCostNlaborEdit,
},
props: ['visible', 'selProject'],
computed: {
...mapState(useUserStore, ['userInfo']),
},
watch: {
visible(val) {
if (val == true) {
this.initData();
this.searchTableDatas()
}
}
},
data() {
return {
filters: {
key: ''
},
addFormVisible: false,//新增xmCostNlabor界面是否显示
addForm: {
projectId: '', userid: '', ctime: '', sendTime: '', username: '', projectName: '', remark: '', id: '', taskId: '', taskName: '', subjectId: '', bizSdate: '', bizEdate: '', actAt: '', costType: '', bizMonth: '', bizDate: '', subjectName: '', ubranchId: '', branchId: ''
},
editFormVisible: false,//编辑界面是否显示
editForm: {
projectId: '', userid: '', ctime: '', sendTime: '', username: '', projectName: '', remark: '', id: '', taskId: '', taskName: '', subjectId: '', bizSdate: '', bizEdate: '', actAt: '', costType: '', bizMonth: '', bizDate: '', subjectName: '', ubranchId: '', branchId: ''
},
apis: {
list: listXmCostNlabor,
del: delXmCostNlabor,
batchDel: batchDelXmCostNlabor,
editSomeFields: editSomeFieldsXmCostNlabor,
}
}
},//end data
methods: {
//获取列表 XmCostNlabor 项目实际人工成本费用
preQueryParamCheck(params) {
return true;
},
//显示编辑界面 XmCostNlabor 项目实际人工成本费用
showEdit: function (row, index) {
this.editFormVisible = true;
this.editForm = Object.assign({}, row);
},
//显示新增界面 XmCostNlabor 项目实际人工成本费用
showAdd: function () {
this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm);
},
editSomeFieldsCheck(row, fieldName, $event, params) {
return true;
},
initCurrData: function () {
this.searchTableDatas()
},
},//end methods
mounted() {
}
}
</script>
<style scoped />

View File

@@ -1,24 +1,28 @@
<template>
<!--编辑界面 XmCostNlabor 项目实际人工成本费用-->
<!--编辑界面 XmCostRecord 项目实际人工成本费用-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editFormRef">
<el-form-item label="项目编号" prop="projectId" v-if="currOpType != 'add'">
<el-input v-model="editForm.projectId" placeholder="项目编号" :maxlength="50" disabled />
</el-form-item>
<el-form-item label="项目编号" prop="projectId" v-if="currOpType == 'add'">
<XmProjectSelect width="100%" v-model="editForm.projectId" @change2="($event) => editForm.projectName = $event?.name || ''" />
<XmProjectSelect width="100%" v-model="editForm.projectId" @change2="($event) => editForm.projectName = $event?.name || ''" :disabled="selProject?.id"/>
</el-form-item>
<el-form-item label="费用主责" prop="username">
<MdpSelectUser width="100%" v-model="editForm.userid" @change2="($event)=>editForm.username=$event?.username" />
<MdpSelectUser width="100%" v-model="editForm.userid" :init-name="editForm.username" @change2="($event)=>editForm.username=$event?.username" />
</el-form-item>
<el-form-item label="用途说明" prop="remark">
<el-input v-model="editForm.remark" placeholder="用途说明" />
<el-input type="textarea" v-model="editForm.remark" placeholder="用途说明" />
</el-form-item>
<el-form-item label="实际金额" prop="actAt">
<el-input type="number" v-model="editForm.actAt" placeholder="实际金额" :maxlength="10" />
</el-form-item>
</el-form-item>
<el-form-item label="成本科目" prop="subjectId">
<mdp-select item-code="projectSubject" width="100%" placeholder="科目编号" v-model="editForm.subjectId" />
</el-form-item>
<el-form-item label="成本中心" prop="costCenterId">
<MdpSelectDept width="100%" v-model="editForm.costCenterId" placeholder="成本中心" title="成本中心"/>
</el-form-item>
<el-form-item label="发生日期" prop="bizDate">
<MdpDate v-model="editForm.bizDate" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" autoDefault/>
</el-form-item>
@@ -33,14 +37,14 @@
<script>
import util from '@/components/mdp-ui/js/util';//
import config from "@/api/mdp_pub/mdp_config"; //import
import { addXmCostNlabor, editXmCostNlabor } from '@/api/xm/pro/xmCostNlabor';
import { addXmCostRecord, editXmCostRecord } from '@/api/xm/pro/xmCostRecord';
import { mapState } from 'pinia'
import { useUserStore } from '@/store/modules/user'
import XmProjectSelect from '../../core/components/XmProjectSelect.vue';
import {MdpFormMixin} from "@/components/mdp-ui/mixin/MdpFormMixin.js"
export default {
mixins:[MdpFormMixin],
name: 'xmCostNlaborEdit',
name: 'xmCostRecordEdit',
components: {
XmProjectSelect
},
@@ -86,8 +90,8 @@ export default {
projectId: '', userid: '', ctime: '', sendTime: '', username: '', projectName: '', remark: '', id: '', taskId: '', taskName: '', subjectId: '', bizSdate: '', bizEdate: '', actAt: '', costType: '', bizMonth: '', bizDate: '', subjectName: '', ubranchId: '', branchId: ''
},
apis:{
add: addXmCostNlabor,
edit: editXmCostNlabor,
add: addXmCostRecord,
edit: editXmCostRecord,
}
}//end return
},//end data

Some files were not shown because too many files have changed in this diff Show More