You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
16 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. <template>
  2. <section>
  3. <el-row class="padding-left padding-right">
  4. <el-col :span="6">
  5. <comps-set :comp-ids="compIds" :category="category" @row-click="onCompSelect" ref="compsSet"></comps-set>
  6. </el-col>
  7. <el-col :span="18">
  8. <el-row class="padding">
  9. <span style="float:right;">
  10. <el-button type="text" v-if="isRptShow==true && isRptCfg==false" @click="isRptShow=true" icon="el-icon-time">查看历史报告</el-button>
  11. <el-button type="primary" v-if="isRptShow==true && isRptCfg==false" @click="createRptData" icon="el-icon-time">保存报告(可供历史查询)</el-button>
  12. <el-button type="text" v-if="isRptShow==false && isRptCfg==false" @click="isRptShow=true" icon="el-icon-time">查看报告</el-button>
  13. <el-button type="warning" v-if="isRptShow==true" @click="undoRptShow" icon="el-icon-error">退出报告</el-button>
  14. <el-button type="text" v-if="isRptCfg==false&&isRptShow==false" @click="toRptCfg" icon="el-icon-setting">制作报告</el-button>
  15. <el-button type="primary" v-if="isRptCfg==true" @click="undoRptCfg" icon="el-icon-error">取消制作</el-button>
  16. <el-button type="warning" v-if="isRptCfg==true" @click="finishRptCfg">保存报告</el-button>
  17. <el-button type="text" v-if="paramsVisible==true" @click="paramsVisible=false">隐藏过滤条件</el-button>
  18. <el-button type="text" v-if="paramsVisible==false" @click="paramsVisible=true">显示过滤条件</el-button>
  19. <el-button type="text" v-print="{id:'printBody',popTitle:rptConfigParamsCpd.name+'-报告'}" icon="el-icon-printer"></el-button>
  20. <el-button type="text" @click="exportToPdf">pdf</el-button>
  21. </span>
  22. </el-row>
  23. <el-row :style="{height:maxTableHeight+'px',overflowY:'auto',overflowX:'hidden',}" ref="table">
  24. <div class="empty" v-if="compCfgList.length == 0" >
  25. <el-empty description="暂未选择报表,请至少选择一个报表"></el-empty>
  26. </div>
  27. <div v-else id="printBody" ref="rptBox">
  28. <component style="margin-bottom:80px;" v-for="(item,index) in compCfgList" :key="index" :is="item.compId" :xm-test-plan="xmTestPlan" :xm-product="xmProduct" :xm-project="xmProject" :xm-iteration="xmIteration" :xm-test-casedb="xmTestCasedb" :category="category" :cfg="item.cfg" :ref="item.id" @delete="doDelete(item)" :init-group-by="item.initGroupBy" :show-tool-bar="false" :id="item.id" :show-params="paramsVisible"></component>
  29. </div>
  30. </el-row>
  31. </el-col>
  32. </el-row>
  33. </section>
  34. </template>
  35. <script>
  36. import util from '@/common/js/util';//全局公共库
  37. import seq from '@/common/js/sequence';//全局公共库
  38. import VueGridLayout from 'vue-grid-layout';
  39. import { mapGetters } from 'vuex'
  40. import CompsSet from '@/views/xm/rpt/CompsSet'
  41. import { initDicts,listXmRptConfig, delXmRptConfig,editXmRptConfig,addXmRptConfig,batchDelXmRptConfig,editSomeFieldsXmRptConfig } from '@/api/xm/core/xmRptConfig';
  42. export default {
  43. components: {
  44. GridLayout: VueGridLayout.GridLayout,
  45. GridItem: VueGridLayout.GridItem,
  46. CompsSet,
  47. xmTestRptOverview:()=>import("../core/xmTestPlan/xmTestRptOverview.vue"),
  48. xmMenuDayTrend:()=>import("./product/menuDayTrend.vue"),
  49. xmMenuDayAccumulate:()=>import("./product/menuDayTrend.vue"),
  50. xmMenuAttDist:()=>import('./product/menuAttDist'),
  51. xmMenuAgeDist:()=>import('./product/menuAgeDist.vue'),
  52. xmMenuSort:()=>import('./product/menuSort.vue'),
  53. xmMenuFuncSort:()=>import('./product/menuSort.vue'),
  54. xmMenuProductSort:()=>import('./product/menuSort.vue'),
  55. xmMenuIterationSort:()=>import('./product/menuSort.vue'),
  56. xmProductWorkItemDayList:()=>import('./product/productWorkItemDayList.vue'),
  57. xmTaskDayTrend:()=>import('./project/taskDayTrend.vue'),
  58. xmTaskDayAccumulate:()=>import('./project/taskDayAccumulate.vue'),
  59. xmTaskAttDist:()=>import('./project/taskAttDist.vue'),
  60. xmTaskAgeDist:()=>import('./project/taskAgeDist.vue'),
  61. xmTaskSort:()=>import('./project/taskSort.vue'),
  62. xmProjectWorkItemDayList:()=>import('./project/projectWorkItemDayList.vue'),
  63. xmProjectWorkloadSetDayList:()=>import('./project/projectWorkloadSetDayList.vue'),
  64. xmProjectWorkloadSetMonthList:()=>import('./project/projectWorkloadSetMonthList.vue'),
  65. xmQuestionDayTrend:()=>import('./product/questionDayTrend.vue'),
  66. xmQuestionDayAccumulate:()=>import('./product/questionDayAccumulate.vue'),
  67. xmQuestionAttDist:()=>import('./product/questionAttDist.vue'),
  68. xmQuestionStateDist:()=>import('./product/questionAttDist.vue'),
  69. xmQuestionAgeDist:()=>import('./product/questionAgeDist.vue'),
  70. xmQuestionBugReasonDist:()=>import('./product/questionAttDist.vue'),
  71. xmQuestionBugTypeDist:()=>import('./product/questionAttDist.vue'),
  72. xmQuestionPriorityDist:()=>import('./product/questionAttDist.vue'),
  73. xmQuestionSort:()=>import('./product/questionSort.vue'),
  74. xmQuestionAskUserSort:()=>import('./product/questionSort.vue'),
  75. xmQuestionHandlerUserSort:()=>import('./product/questionSort.vue'),
  76. xmQuestionFuncSort:()=>import('./product/questionSort.vue'),
  77. xmQuestionMenuSort:()=>import('./product/questionSort.vue'),
  78. xmQuestionRetestDist:()=>import('./product/questionRetestDist.vue'),
  79. xmTestPlanCaseExecStatusDist:()=>import('./testPlan/testPlanCaseExecStatusDist.vue'),
  80. xmTestPlanCaseUserDist:()=>import('./testPlan/testPlanCaseUserDist.vue'),
  81. xmTestDayTimesCalc:()=>import('./testPlan/testDayTimesCalc.vue'),
  82. xmTestCaseToPlanCalc:()=>import('./testPlan/testCaseToPlanCalc.vue'),
  83. xmTestCaseSort:()=>import('./testCase/testCaseSort.vue'),
  84. xmTestCaseCuserSort:()=>import('./testCase/testCaseSort.vue'),
  85. xmTestCaseFuncSort:()=>import('./testCase/testCaseSort.vue'),
  86. xmTestCaseMenuSort:()=>import('./testCase/testCaseSort.vue'),
  87. xmIterationMenuDayTrend:()=>import('./iteration/menuDayTrend.vue'),
  88. xmIterationMenuDayAccumulate:()=>import('./iteration/menuDayAccumulate.vue'),
  89. xmIterationBurnout:()=>import('./iteration/burnout.vue'),
  90. xmIterationWorkItemDayList:()=>import('./iteration/iterationWorkItemDayList.vue'),
  91. xmIterationQuestionDayTrend:()=>import('./iteration/questionDayTrend.vue'),
  92. xmIterationQuestionDayAccumulate:()=>import('./iteration/questionDayAccumulate.vue'),
  93. xmBranchWorkItemDayList:()=>import('./branch/branchWorkItemDayList.vue'),
  94. xmBranchQuestionDayTrend:()=>import('./branch/questionDayTrend.vue'),
  95. xmBranchQuestionDayAccumulate:()=>import('./branch/questionDayAccumulate.vue'),
  96. xmBranchMenuDayTrend:()=>import('./branch/menuDayTrend.vue'),
  97. xmBranchMenuDayAccumulate:()=>import('./branch/menuDayAccumulate.vue'),
  98. },
  99. props:['xmTestCasedb','xmTestPlan','xmProduct','xmProject','xmIteration','category','showParams'],
  100. computed: {
  101. ...mapGetters(['userInfo']),
  102. compIds(){
  103. return this.compCfgList.map(k=>k.compId)
  104. },
  105. rptConfigParamsCpd(){
  106. //业务类型1-产品报告,2-迭代报告,3-测试计划报告,4-项目报告,5-企业报告
  107. if(this.rptDatas){
  108. this.rawDatas=this.rptDatas
  109. return;
  110. }
  111. var params={bizType:'5',bizId:this.userInfo.branchId,name:''}
  112. if(this.category=='企业级'){
  113. params.bizType='5';
  114. params.bizId=this.userInfo.branchId
  115. params.name=this.userInfo.branchName
  116. }else if(this.category=='产品级'){
  117. params.bizType='1';
  118. params.bizId=this.xmProduct.id
  119. params.name=this.xmProduct.productName
  120. }else if(this.category=='迭代级'){
  121. params.bizType='2';
  122. params.bizId=this.xmIteration.id
  123. params.name=this.xmIteration.iterationName
  124. }else if(this.category=='项目级'){
  125. params.bizType='4';
  126. params.bizId=this.xmProject.id
  127. params.name=this.xmProject.name
  128. }else if(this.category=='测试级'){
  129. if(this.xmTestPlan && this.xmTestPlan.id){
  130. params.bizType='3';
  131. params.bizId=this.xmTestPlan.id
  132. params.name=this.xmTestPlan.name
  133. }else{
  134. params.bizType='6';
  135. params.bizId=this.xmTestCasedb.id
  136. params.name=this.xmTestCasedb.name
  137. }
  138. }else {
  139. return params;
  140. }
  141. return params;
  142. },
  143. toLoadXmRptConfigCpd(){
  144. return this.isRptCfg || this.isRptShow
  145. }
  146. },
  147. watch: {
  148. xmRptConfig:{
  149. handler(){
  150. this.initCompCfgList();
  151. },
  152. deep:true,
  153. },
  154. toLoadXmRptConfigCpd(){
  155. this.getXmRptConfig();
  156. this.$nextTick(()=>{
  157. this.compCfgList.forEach(k=>{
  158. this.sizeAutoChange(k);
  159. })
  160. })
  161. },
  162. rptConfigParamsCpd(){
  163. if(this.isRptCfg ||this.isRptShow){
  164. this.getXmRptConfig()
  165. }
  166. }
  167. },
  168. data() {
  169. return {
  170. isRptCfg:false,
  171. isRptShow:false,
  172. xmRptConfig:null,
  173. compCfgList:[],
  174. maxTableHeight:300,
  175. // 布局列数
  176. layoutColNum: 12,
  177. paramsVisible:true,
  178. exportToolBarVisible:true,
  179. }
  180. },
  181. methods: {
  182. initData(){
  183. if(this.showParams!=undefined){
  184. this.paramsVisible=this.showParams
  185. }
  186. if(!this.toLoadXmRptConfigCpd){
  187. this.initCompCfgList();
  188. }else{
  189. this.getXmRptConfig();
  190. }
  191. },
  192. createRptData(){
  193. if(this.xmRptConfig==null){
  194. this.$message.error("还没制作报告,请先制作报告")
  195. return;
  196. }
  197. },
  198. undoRptCfg(){
  199. this.xmRptConfig=null;
  200. this.isRptCfg=false;
  201. },
  202. undoRptShow(){
  203. this.isRptShow=false;
  204. this.xmRptConfig=null;
  205. },
  206. toRptCfg(){
  207. this.isRptCfg=true;
  208. this.$message.success("切换到报告制作模式成功。请选择报表加入报告中。")
  209. },
  210. finishRptCfg(){
  211. this.submitXmPrtConfig((res)=>{
  212. var tips = res.data.tips;
  213. if(tips.isOk){
  214. this.isRptCfg=false
  215. this.xmRptConfig=null;
  216. this.$message.success("报告保存成功。将退出报告制作模式")
  217. }else{
  218. this.$message.error(tips.msg)
  219. }
  220. });
  221. },
  222. getXmRptConfig(){
  223. if(!this.toLoadXmRptConfigCpd){
  224. return;
  225. }
  226. if(this.rptDatas){
  227. this.rawDatas=this.rptDatas
  228. return;
  229. }
  230. var params={bizType:this.rptConfigParamsCpd.bizType,bizId:this.rptConfigParamsCpd.bizId}
  231. listXmRptConfig(params).then(res=>{
  232. this.xmRptConfig=res.data.data[0]
  233. })
  234. },
  235. initCompCfgList(){
  236. if(this.xmRptConfig && this.xmRptConfig.cfg){
  237. var cfgJson=JSON.parse(this.xmRptConfig.cfg)
  238. this.compCfgList=cfgJson;
  239. }else{
  240. var defList=this.$refs['compsSet'].rptListCpd
  241. if(defList && defList.length>3){
  242. defList=defList.slice(0,3);
  243. }
  244. this.compCfgList=JSON.parse(JSON.stringify(defList))
  245. }
  246. },
  247. onCompSelect(comp){
  248. if(this.compCfgList.some(k=>k.id==comp.id)){
  249. var compCfg=this.compCfgList.find(k=>k.id==comp.id)
  250. this.$nextTick(()=>{
  251. this.scrollToComp(compCfg)
  252. })
  253. return;
  254. }
  255. var compCfgListTemp=JSON.parse(JSON.stringify(this.compCfgList))
  256. compCfgListTemp.sort((i1,i2)=>{
  257. return i2.i-i1.i
  258. })
  259. var maxI=(compCfgListTemp.length>0?(compCfgListTemp[0].i+1):1);
  260. compCfgListTemp.sort((i1,i2)=>{
  261. return i2.y-i1.y
  262. })
  263. var maxY=(compCfgListTemp.length>0?(compCfgListTemp[0].y+6):0);
  264. var compCfg={...comp,i:maxI, x: 0, y: maxY, w: 12, h: 6,id:comp.compId+seq.sn()}
  265. this.compCfgList.push(compCfg)
  266. this.$nextTick(()=>{
  267. setTimeout(()=>{
  268. this.scrollToComp(compCfg)
  269. },200)
  270. })
  271. },
  272. scrollToComp(compCfg){
  273. var doc=document.getElementById(compCfg.id)
  274. if(doc){
  275. doc.scrollIntoView(true)
  276. }
  277. },
  278. submitXmPrtConfig(callback){
  279. if(this.xmRptConfig==null){
  280. var xmRptConfig={...this.rptConfigParamsCpd,cfg:[]}
  281. var compCfgList=JSON.parse(JSON.stringify(this.compCfgList))
  282. compCfgList=compCfgList.map(k=>{
  283. return {compId:k.compId,id:k.id}
  284. })
  285. compCfgList.forEach(k=>{
  286. if(this.$refs[k.id] && this.$refs[k.id][0].$refs && this.$refs[k.id][0].$refs[k.id]){
  287. var com=this.$refs[k.id][0].$refs[k.id]
  288. k.params=com.params
  289. k.title=com.title
  290. k.remark=com.remark
  291. }else{
  292. var com=this.$refs[k.id][0]
  293. k.params=com.params
  294. k.title=com.title
  295. k.remark=com.remark
  296. }
  297. })
  298. xmRptConfig.cfg=JSON.stringify(compCfgList)
  299. addXmRptConfig(xmRptConfig).then(res=>{
  300. this.xmRptConfig=xmRptConfig;
  301. callback(res)
  302. })
  303. }else{
  304. var xmRptConfig={...this.xmRptConfig,cfg:[]}
  305. var compCfgList=JSON.parse(JSON.stringify(this.compCfgList))
  306. compCfgList=compCfgList.map(k=>{
  307. return {compId:k.compId,id:k.id}
  308. })
  309. compCfgList.forEach(k=>{
  310. if(this.$refs[k.id] && this.$refs[k.id][0].$refs && this.$refs[k.id][0].$refs[k.id]){
  311. var com=this.$refs[k.id][0].$refs[k.id]
  312. k.params=com.params
  313. k.title=com.title
  314. k.remark=com.remark
  315. }else{
  316. var com=this.$refs[k.id][0]
  317. k.params=com.params
  318. k.title=com.title
  319. k.remark=com.remark
  320. }
  321. })
  322. xmRptConfig.cfg=JSON.stringify(compCfgList)
  323. editXmRptConfig(xmRptConfig).then(res=>{
  324. this.xmRptConfig=xmRptConfig;
  325. callback(res)
  326. })
  327. }
  328. },
  329. doDelete(compCfg){
  330. var index=this.compCfgList.findIndex(k=>k.id==compCfg.id)
  331. if(index>=0){
  332. this.compCfgList.splice(index,1)
  333. }
  334. },
  335. sizeAutoChange(k){
  336. },
  337. exportToPdf(){
  338. this.paramsVisible=false
  339. this.$nextTick(()=>{
  340. this.$PDFSave(this.$refs.rptBox, this.rptConfigParamsCpd.name+"-报告");
  341. })
  342. },
  343. },
  344. mounted() {
  345. this.$nextTick(() => {
  346. this.initData();
  347. this.maxTableHeight = util.calcTableMaxHeight(this.$refs.table.$el)
  348. })
  349. },
  350. }
  351. </script>
  352. <style lang="less" scoped>
  353. .toolbar{
  354. z-index: 999;
  355. position:absolute;
  356. top:0px;
  357. right:20px;
  358. }
  359. </style>