活动介绍

this.cardList.push(...this.filterListCard) 括号里面的...是什么意思

时间: 2025-08-30 17:55:46 AIGC 浏览: 7
<think> 我们正在讨论JavaScript中`this.cardList.push(...this.filterListCard)`里的`...`操作符。 根据用户提供的上下文,特别是引用[1]中的Vue示例和引用[2]中的TypeScript泛型示例,我们可以推断用户可能是在Vue或TypeScript环境中使用该代码。 在JavaScript(以及TypeScript)中,`...`在这里是展开操作符(Spread Operator)。 它的作用是将一个数组展开为多个单独的元素。 具体到代码`this.cardList.push(...this.filterListCard)`: - `this.cardList` 是一个数组,我们调用它的`push`方法。 - `push`方法通常可以接收多个参数,每个参数将被依次添加到数组的末尾。 - `this.filterListCard` 是另一个数组,我们想要将它的所有元素添加到`this.cardList`中。 - 如果我们直接写`this.cardList.push(this.filterListCard)`,那么整个`this.filterListCard`数组会作为一个单一的元素(即一个子数组)被添加到`this.cardList`中,这通常不是我们想要的。 - 使用展开操作符`...`,就可以将`this.filterListCard`数组展开,相当于将数组中的每个元素作为单独的参数传递给`push`方法。 例如: 假设`this.filterListCard`是`[1, 2, 3]`,那么: `this.cardList.push(...[1, 2, 3])` 等价于 `this.cardList.push(1, 2, 3)` 这样就会把1,2,3三个元素分别添加到`this.cardList`数组中。 展开操作符是ES6(ECMAScript 2015)引入的特性,现在已被所有现代浏览器支持。 另外,在引用[1]的Vue示例中,我们看到了一个计算属性`activeUsers`,它使用`filter`方法返回活跃用户数组。在Vue中,我们经常需要操作数组,展开操作符在这样的场景中也非常有用。 同时,在引用[2]的TypeScript泛型类中,我们看到在构造函数和`add`方法中操作数组。展开操作符同样可以用于这些场景。 因此,总结:`...`在这里是展开操作符,用于将数组展开为参数序列。 下面我们根据要求生成相关问题。 </think> 在 JavaScript 中,`this.cardList.push(...this.filterListCard)` 语句中的 `...` 是**展开运算符(Spread Operator)**,它的主要作用是将数组 `this.filterListCard` 的元素逐个展开,作为单独的参数传递给 `push()` 方法。 ### 展开运算符的核心作用 数学表达: 设原数组为 $A = [a_1, a_2, \dots, a_n]$,展开操作等价于: $$ \text{push}(A[0], A[1], \dots, A[n-1]) $$ ### 具体行为对比 | **操作方式** | **结果示例** | **说明** | |---------------------------|----------------------------------|--------------------------------------| | `cardList.push(filterListCard)` | `[[1,2,3]]` | 整个数组作为单个元素添加(嵌套数组)| | `cardList.push(...filterListCard)` | `[1,2,3]` | **展开后逐个添加元素** | ### 实际代码示例 ```javascript // 原始数据 this.cardList = [10, 20]; this.filterListCard = [30, 40]; // 使用展开运算符 this.cardList.push(...this.filterListCard); console.log(this.cardList); // 输出: [10, 20, 30, 40] ✅ 元素被逐个添加 ``` ### 关键特性 1. **避免嵌套数组** 直接 `push(array)` 会产生 `[原始元素, [新数组]]` 的结构,而展开运算符会解包数组元素。 2. **性能优化** 比循环遍历 + 单个 `push()` 更高效,一次性传递所有参数[^1]。 3. **浅拷贝机制** 对于对象/数组元素,只复制引用(非深拷贝): ```javascript const objArr = [{id:1}]; cardList.push(...objArr); objArr[0].id = 99; // 会同时修改 cardList 中的对象 ``` 4. **替代 apply()** 传统实现需用 `cardList.push.apply(cardList, filterListCard)`,展开运算符更简洁[^2]。 ### 适用场景 - 合并数组:`combined = [...arr1, ...arr2]` - 函数传参:`myFunc(...argsArray)` - 复制数组:`copy = [...original]`(浅拷贝) - Vue 中响应式更新数组(触发视图刷新)[^3] --- ### 相关问题 1. 展开运算符 `...` 和剩余参数 `...` 有何区别? 2. 在 Vue/React 中使用展开运算符更新数组时,如何确保响应式? 3. 展开运算符在处理多维数组时有哪些限制? 4. `Array.prototype.concat()` 和展开运算符在合并数组时的性能差异? > 通过展开运算符可高效实现数组操作,是 ES6 的核心特性之一。在 Vue 等框架中尤其适用于响应式数据更新[^3]。 [^1]: 引用计算属性中的数组操作示例 [^2]: 引用泛型类中的数组处理方法 [^3]: 引用 Vue 模板中的数组渲染逻辑
阅读全文

相关推荐

<template> {{ item.name }} <el-image v-if="title" style="width: 17px; height: 24px; margin-right: 5px;" :src="require('@/src/images/gdGridMap/homePage/eightMajorThemes/location.png')" fit="contain"> </el-image> {{ title }} <el-link type="info" @click="handleExpand"> {{ title ? (isExpand ? '收起 >>' : '展开全部 <<') : '' }} </el-link> {{ item.name }} <theme-items :items="getCard(item.cardList)" :ref="'themeItemsRef'+index" :year-month="yearMonth"></theme-items> </template> <script> import {myMixins} from "../../mixins/myMixins"; import {targetCardData} from "../../themecard/targetCardData" import themeItems from "../../themecard/ThemeItems"; export default { mixins: [myMixins], name: 'eightMajorThemesRight', components: { themeItems }, props:{ yearMonth: { // 年月 type: String, default: '202508' } }, data() { return { isExpand: false, // 展开全部 activeName: 0, //默认展开面板 title: '', nodeBm: '', themeList: [ { name: '供电质量', cardList: [ {cardName: '', name: 'powerQualityCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '基础管理', cardList: [ {cardName: '', name: 'baseManageCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '诉求处置', cardList: [ {cardName: '', name: 'appealHandCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '停电处置', cardList: [ {cardName: '', name: 'outageHandCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '外部协同', cardList: [ {cardName: '', name: 'externalCollaborationCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '网格建设', cardList: [ {cardName: '', name: 'gridConstructCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '业务受理', cardList: [ {cardName: '', name: 'businessAcceptanceCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '主动服务', cardList: [ {cardName: '', name: 'activeServiceCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] } ], useList: [], loadList: [], observer: null, isManualScroll: false, // 是否正在手动点击跳转 } }, mounted() { window.addEventListener('resize', () => { for (const key in this.loadList) { let themeItemsRefName = 'themeItemsRef' + key; if (this.$refs[themeItemsRefName]) { setTimeout(() => this.$refs[themeItemsRefName][0].$emit("resize"), 500); } } }) }, watch: { loadList: { handler(newValue, oldValue) { this.$nextTick(() => this.observeTheme()); }, immediate: true, // 创建时立即执行一次 handler 回调 deep: true //深度监听 loadList 内部嵌套属性的变化 }, }, methods: { /* 数据来源,必须与myMixins方法同名 */ changeData(val) { this.title = val.nodeMc this.$nextTick(() => { this.useList = JSON.parse(JSON.stringify(this.themeList)); this.loadList = this.useList; }); if (this.nodeBm != val.nodeBm) { //地址切换面板滚到顶部 this.nodeBm = val.nodeBm; if (!val.roll) { this.handleChange(0); } } }, handleChange(val, name) { /* if (this.loadList.length != this.useList.length) { if (val > this.activeName) { this.loadList = this.useList.slice(0, val + 1); } } */ this.activeName = val; this.isManualScroll = true; // 标记为手动操作,防止 Observer 干扰 this.$nextTick(() => { let mainContainer = $('.theme-content') let scrollToContainer = mainContainer.find('#theme_' + val); if (name) { scrollToContainer = mainContainer.find('#' + name); } mainContainer.animate({ scrollTop: scrollToContainer.offset().top - mainContainer.offset().top + mainContainer.scrollTop() }, 1000); // 手动滚动结束后,清除标志(防抖) setTimeout(() => { this.isManualScroll = false; }, 1000); // 与滚动动画时间一致 }) }, getDivStyle(style, index) { if (style == "title") { return index === this.activeName ? 'theme-title title-highlight' : 'theme-title'; } }, /* 展开全部 */ handleExpand() { this.isExpand = !this.isExpand; this.$store.state.isExpand = this.isExpand; }, handleScroll(event) { const {scrollTop, clientHeight, scrollHeight} = event.target; if (scrollTop + clientHeight >= scrollHeight) { /* if (this.loadList.length != this.useList.length) { this.loadList = this.useList.slice(0, this.activeName + 2); } */ } }, getCard(cardList) { let list = cardList.filter(item => item.level.includes(parseInt(this.$store.state.indicatorData.nodeJbdm))); list.forEach(item => { let find = targetCardData().targetCardArr.find(it => it.name == item.name); item.id = find.id; if (!item.hasOwnProperty('space')) { item.space = find.space; } if (!item.hasOwnProperty('isShow')) { item.isShow = true; } }); return list; }, /* 滚动监听,用于动态更新 activeName */ observeTheme() { // (0) 清理之前的观察器(避免重复创建) if (this.observer) { this.observer.disconnect(); } // (1)配置观察器选项 const options = { root: document.querySelector('.theme-content'), // 观察的根元素(滚动容器) rootMargin: "0px", // 根元素的外边距(无扩展) threshold: 0.5, // 触发回调的交叉比例阈值(50%可见) }; // (2)收集目标元素 let sections = []; for (let i = 0; i < this.loadList.length; i++) { sections.push(document.querySelector('#theme_' + i)); } sections = sections.filter(item => item != null); // 过滤无效元素 // (3)回调函数 const callback = (entries, observer) => { if (this.isManualScroll) return; // 手动滚动时不更新 //entries:代表观察到的目标元素的集合。 observer:代表观察者对象。 entries.forEach((entry) => { if (entry.isIntersecting) { // 判断目标元素是否进入视口 const target = entry.target; // 获取当前目标元素 let index = sections.findIndex((section) => section === target); this.activeName = index; } }); }; // (4)创建观察器并监听元素 /* let thresholds = Array(sections.length).fill(0.5); sections.forEach((value, index) => { options.threshold = thresholds[index]; this.observer = new IntersectionObserver(callback, options); this.observer.observe(value); }); */ this.observer = new IntersectionObserver(callback, options); sections.forEach(value => this.observer.observe(value)); }, } } </script> <style scoped> #indicatorPanel { display: flex; } .left-div { height: 100%; width: 10%; } .theme-title { height: 12.2%; width: 100%; display: flex; justify-content: center; align-items: center; background: #E6EDFE; border-radius: 10px; border: 1px snow solid; } .theme-title:hover { cursor: pointer; } .title-highlight { background: #ADCFFD !important; } .text-title { width: 0.1875rem; color: #192C7D; font-size: 0.18rem; font-weight: bold; } .right-div-width1 { width: 82%; /* 100%-左侧10%-左右内边距4%*2 */ } .right-div-width2 { width: 96%; /* 100%-上下内边距2%*2 */ } .right-div { height: 98%; box-shadow: 0 0 10px gainsboro; border-radius: 10px; background-color: white !important; overflow: hidden; padding: 2% 4%; text-align: center; position: relative; } .div-title, .div-expand { display: flex; align-items: center; /* 上下居中 */ } .div-title span { text-align: left; color: #354387; font-size: 0.3rem; font-weight: bold; } .div-expand { position: absolute; top: .25rem; right: .4rem; } .div-expand .el-link { font-size: 12px !important; } .theme-content { width: 100%; height: 93%; overflow-y: scroll; overflow-x: hidden; } .cardNameClass { width: 30%; color: #354387; font-size: .25rem; font-weight: bold; border-bottom: solid 1px #354387; padding-left: .2rem; text-align: left; } </style>这是我的代码,主要问题出在theme_2和theme_4,因为echart图过多,内容很长

<template> 装备中国, 装备世界 今天是 {{ dayjs().format('YYYY年MM月DD日') }}{{ dayjs().format('dddd') }} <appstore-outlined /> 卡片管理 item.cardType === 'homeWelcome')?.ifShow"> {{ state.sloganList?.mainTitle }} {{ state.sloganList?.subTitle }} item.cardType === 'homeManage')?.ifShow"> iPD管理指南 【{{ item.mainTitle }}】{{ item.subTitle }} 查看更多 <right-outlined :style="{ fontSize: '13px' }" /> item.cardType === 'homeFast')?.ifShow"> 快捷操作 <a-popover v-model:visible="state.isStatus.operate" trigger="click" placement="left"> <template #content> 隐藏 设置 </template> </a-popover> <Quick :quickList="state.quickList" /> item.cardType === 'homeWork')?.ifShow"> 任务中心 <TaskCenter /> <CardFrame ref="cardRef" :cardList="state.cardList" :getCardList="getCardList" /> <QuickFrame ref="quickFrame" :getQuick="getQuick" /> <MoreDrawers ref="moreDrawers" /> </template> <script lang="ts" setup> import { ref, onMounted, reactive, nextTick, onUnmounted } from 'vue'; import dayjs from 'dayjs'; import { getHomeWelcomeCard, getHomeManageCard, getIfShowHomeCardList, updateIfShowHomeCard, getFastCardByFlowCategory } from './api'; import { AppstoreOutlined, RightOutlined } from '@ant-design/icons-vue'; import { HomePage } from '../type/homeType'; import CardFrame from '../components/cardFrame.vue'; import QuickFrame from '../components/quickFrame.vue'; import MoreDrawers from '../components/moreDrawers.vue'; import Quick from '../components/quick.vue'; import TaskCenter from '../components/taskCenter.vue'; // import { useUserStore } from '@/store/modules/user'; // const userStore = useUserStore(); // import { useGlobSetting } from '@/hooks/setting'; // const globSetting = useGlobSetting(); // const apiUrl = ref(globSetting.apiUrl); const cardRef = ref(); const quickFrame = ref(); const moreDrawers = ref(); const state = reactive<HomePage>({ sloganList: {}, guideList: [], cardList: [], quickList: [], isStatus: { operate: false, taskCenter: false, guide: false, slogan: false, }, }); //图片 const introduceLeft = ref<HTMLElement | null>(null); const introduceRight = ref<HTMLElement | null>(null); const leftScaleWrapper = ref<HTMLElement | null>(null); const rightScaleWrapper = ref<HTMLElement | null>(null); let resizeTimer: number | null = null; // 卡片管理 const handleCard = () => { cardRef.value.openPopup(); }; // 获取欢迎标语 const getHomeWelcomeCardList = async () => { try { const res = await getHomeWelcomeCard({}); if (res.code === 200) { state.sloganList = res.data; } } catch (err) { console.log(err); } }; // 获取管理指南 const getHomeManageCardList = async () => { try { const res = await getHomeManageCard({}); if (res.code === 200) { state.guideList = res.data.list; } } catch (err) { console.log(err); } }; // 快捷操作 const getQuick = async () => { try { let params = { flowCategory: '', }; const res = await getFastCardByFlowCategory(params); if (res.code === 200) { state.quickList = res.data; state.quickList.forEach((item: { ifShow: Boolean | string }) => { item.ifShow = item.ifShow === 'true' || item.ifShow === true; }); console.log(state.quickList, '快捷'); } } catch (err) { console.log(err); } }; // 查看更多 const handleMore = () => { moreDrawers.value.getGuideList(); moreDrawers.value.okpenTheDrawer(); }; // 查询首页全部卡片是否展示 const getCardList = async () => { try { const res = await getIfShowHomeCardList({}); if (res.code === 200) { state.cardList = res.data; state.cardList.forEach((item: { ifShow: Boolean | string }) => { item.ifShow = item.ifShow === 'true' || item.ifShow === true; }); renderLogoStyle(); } } catch (err) { console.log(err); } }; // 快捷操作设置 const handleQuick = () => { state.isStatus.operate = false; quickFrame.value?.openPopup(); quickFrame.value?.getSourceModule(); quickFrame.value?.getAllModules(); }; // 单个是否显示 const handleShow = async (Type: string) => { try { let obj = state.cardList.find(item => item.cardType === Type); if (!obj) { return; } let params = { ifShow: obj.ifShow === true ? 0 : 1, cardType: obj.cardType, id: obj.id, }; const res = await updateIfShowHomeCard(params); if (res.code === 200) { getCardList(); state.isStatus.operate = false; } } catch (err) { console.log(err); } }; //渲染logo样式 const renderLogoStyle = () => { nextTick(() => { const leftScaleWrapperWidth = leftScaleWrapper.value?.clientWidth || 0; const introduceLeftWidth = introduceLeft.value?.clientWidth || 0; if (leftScaleWrapper.value) { const scale = introduceLeftWidth / leftScaleWrapperWidth; leftScaleWrapper.value.style.transform = scale(${scale}); rightScaleWrapper.value && (rightScaleWrapper.value.style.transform = scale(${scale})); // 正确设置 height 的方式 if (introduceLeft.value) { const scaledHeight = leftScaleWrapper.value.scrollHeight * scale; introduceLeft.value.style.height = ${scaledHeight}px; } if (introduceRight.value) { const scaledHeight = rightScaleWrapper.value && rightScaleWrapper.value.scrollHeight * scale; introduceRight.value.style.height = ${scaledHeight}px; } } }); }; const handleResize = () => { if (resizeTimer) clearTimeout(resizeTimer); resizeTimer = window.setTimeout(() => { renderLogoStyle(); resizeTimer = null; }, 200); }; onMounted(() => { renderLogoStyle(); getCardList(); getQuick(); getHomeManageCardList(); getHomeWelcomeCardList(); window.addEventListener('resize', handleResize); }); onUnmounted(() => { window.removeEventListener('resize', handleResize); if (resizeTimer) clearTimeout(resizeTimer); }); </script> <style scoped lang="less"> .workbenches { .workbenches-content { height: 100%; padding: 15px 10px 5px 10px; background-color: #f7f7f7; } .title { display: flex; justify-content: space-between; .title-left { .left-date { color: #0094ff; font-weight: 500; } .equipment { color: #0094ff; padding: 4px 10px; background: #fff; border-radius: 4px; font-weight: 600; } } .title-right { background: #fff; padding: 4px 10px; border-radius: 4px; display: flex; align-items: center; color: #999; cursor: pointer; } } .introduce { margin-top: 10px; display: flex; width: 100%; .introduce-left { position: relative; width: calc(50% - 6px); flex-shrink: 0; margin-right: 12px; .left-scale-wrapper { transform-origin: top left; background-image: url('../../images/home_slices/banner.png'); background-position: center; background-repeat: no-repeat; background-size: contain; position: relative; width: 838px; height: 130px; .left-title { position: absolute; left: 7%; top: 20%; display: flex; .hello { font-family: 'Source Han Sans CN'; font-weight: 400; font-size: 18px; color: #cfe3ff; } .name { font-family: 'Source Han Sans CN'; font-weight: 700; font-size: 18px; color: #fff; } } .right-img { position: absolute; right: 160px; top: 50%; transform: translateY(-50%); font-family: 'Source Han Sans CN'; font-weight: 500; font-size: 18px; color: #fefeff; } .right-icon { position: absolute; right: 2%; top: 15%; color: #fff; } } // .introduce-img { // object-fit: cover; // } } .introduce-right { background: #fff; border-radius: 10px; width: calc(50% - 6px); flex-shrink: 0; .right-scale-wrapper { transform-origin: top left; display: flex; justify-content: space-between; padding: 14px 10px; width: 838px; height: 130px; .middle { margin: 18px 0; } } } .guide-left { flex: 1; display: flex; flex-direction: column; justify-content: space-between; .first { font-weight: 700; font-size: 16px; position: relative; margin-left: 20px; &::after { content: ''; width: 4px; height: 16px; background: #1890ff; position: absolute; left: -12px; top: 4px; } } .second { margin-left: 10px; display: flex; } .process { color: #0094ff; margin: 0 3px; } } .guide-right { color: #0094ff; display: flex; flex-direction: column; align-items: flex-end; .more { display: flex; align-items: center; .img { width: 14px; height: 14px; } .more-icon { display: flex; margin-right: 15px; cursor: pointer; } } } } .quick { background-color: #fff; margin: 12px 0; border-radius: 8px; .main { padding: 10px 10px 20px 20px; .operate { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; .quick-operate { font-weight: 700; position: relative; &::after { content: ''; width: 4px; height: 16px; background: #1890ff; position: absolute; left: -8px; top: 3px; } .state { cursor: pointer; .state-left { display: inline-block; cursor: pointer; } } } .operate-icon { display: inline-block; color: #0094ff; } } } } .task-Center { background-color: #fff; border-radius: 10px; padding: 10px 10px 20px 20px; .task-title { display: flex; justify-content: space-between; margin-bottom: 10px; .task-left { font-weight: 700; position: relative; &::after { content: ''; width: 4px; height: 16px; background: #1890ff; position: absolute; left: -8px; top: 3px; } } } } } </style> v-show="state.cardList.find(item => item.cardType === 'homeManage')?.ifShow" 这个可以优化吗,四个地方都在用

以下是onlineReportServiceImplTest的代码:package com.jd.jacp.unit.report; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.jd.jacp.client.service.ICicdClient; import com.jd.jacp.client.service.ICmdbClient; import com.jd.jacp.client.service.ItsmClientService; import com.jd.jacp.common.service.UserHelper; import com.jd.jacp.common.vo.UserVO; import com.jd.jacp.common.vo.enums.YesOrNoEnum; import com.jd.jacp.demand.entity.BizDemandUser; import com.jd.jacp.demand.service.IBizDemandUserService; import com.jd.jacp.notify.entity.BizNotifyRule; import com.jd.jacp.notify.entity.BizNotifySetting; import com.jd.jacp.notify.enums.BizNotifySendWayEnum; import com.jd.jacp.notify.service.IBizNotifyRuleService; import com.jd.jacp.notify.service.IBizNotifySettingService; import com.jd.jacp.report.dto.*; import com.jd.jacp.report.entity.BizReport; import com.jd.jacp.report.entity.BizReportItem; import com.jd.jacp.report.enums.AcceptanceReportEnum; import com.jd.jacp.report.service.IBizReportItemService; import com.jd.jacp.report.service.IBizReportService; import com.jd.jacp.report.service.impl.OnlineReportServiceImpl; import com.jd.jacp.report.vo.SprintOnlineReportInfoVO; import com.jd.jacp.space.dto.CardQuery; import com.jd.jacp.space.dto.SubSystemByParamsDTO; import com.jd.jacp.space.entity.BizSpace; import com.jd.jacp.space.entity.BizSpaceCard; import com.jd.jacp.space.entity.BizSpaceSprint; import com.jd.jacp.space.service.IBizSpaceCardService; import com.jd.jacp.space.service.IBizSpaceService; import com.jd.jacp.space.service.IBizSpaceSettingService; import com.jd.jacp.space.service.IBizSpaceSprintService; import com.jd.jacp.space.vo.DetailVO; import com.jd.jacp.space.vo.QueryReportVO; import com.jd.jacp.unit.MockitoBasedTest; import com.msxf.devops.common.PageResult; import com.msxf.fcid.xmsg.reponse.ChatInfoDataResp; import org.apache.velocity.script.VelocityScriptEngine; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import static org.junit.Assert.*; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.when; import static org.mockito.Mockito.*; import javax.script.ScriptEngineManager; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Function; public class OnlineReportServiceImplTest extends MockitoBasedTest { @Spy @InjectMocks private OnlineReportServiceImpl onlineReportService; @Mock private IBizSpaceSprintService bizSpaceSprintService; @Mock private IBizSpaceSettingService spaceSettingService; @Mock private ScriptEngineManager scriptEngineManager; @Mock private IBizSpaceService bizSpaceService; @Mock private IBizReportService bizReportService; @Mock private IBizNotifySettingService bizNotifySettingService; @Mock private IBizNotifyRuleService bizNotifyRuleService; @Mock private ItsmClientService itsmClientService; @Mock private ICmdbClient cmdbClient; @Mock private ICicdClient cicdClient; @Mock private IBizSpaceCardService spaceCardService; @Mock private IBizDemandUserService demandUserService; @Mock private IBizReportItemService reportItemService; @Mock private UserHelper userHelper; @Test(expected = Exception.class) public void selectOnlineReportInfo_SprintNotExist_ThrowsException() { when(bizSpaceSprintService.getById(1)).thenReturn(null); onlineReportService.selectOnlineReportInfo(1); } @Test(expected = Exception.class) public void selectOnlineReportInfo_SpaceNotExist_ThrowsException() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setSpaceId(1); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(bizSpaceService.getById(1)).thenReturn(null); onlineReportService.selectOnlineReportInfo(1); } @Test public void selectOnlineReportInfo_Successful() { // Mock data BizSpaceSprint sprint = new BizSpaceSprint().setId(1).setSpaceId(1); BizSpace space = new BizSpace().setId(1).setKey("key"); BizReport report = new BizReport().setId(1).setExtendInfo("{\"reportName\":\"Test Report\"}"); BizNotifySetting notifySetting = new BizNotifySetting().setId(1); BizNotifyRule notifyRule = new BizNotifyRule(); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(bizSpaceService.getById(1)).thenReturn(space); when(bizReportService.selectReport(any(), any(), anyInt())).thenReturn(report); when(bizNotifySettingService.getOneBy(anyString(), anyString())).thenReturn(notifySetting); when(bizNotifyRuleService.getOneByNotifyId(anyInt())).thenReturn(notifyRule); SprintOnlineReportInfoVO result = onlineReportService.selectOnlineReportInfo(1); assertNotNull(result); assertEquals("Test Report", result.getOnlineReport().getReportName()); assertNotNull(result.getNotifySetting()); } @Test public void selectOnlineReportInfo_NoNotifySetting() { // Mock data BizSpaceSprint sprint = new BizSpaceSprint().setId(1).setSpaceId(1); BizSpace space = new BizSpace().setId(1).setKey("key"); BizReport report = new BizReport().setId(1).setExtendInfo("{\"reportName\":\"Test Report\"}"); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(bizSpaceService.getById(1)).thenReturn(space); when(bizReportService.selectReport(any(), any(), anyInt())).thenReturn(report); when(bizNotifySettingService.getOneBy(anyString(), anyString())).thenReturn(null); SprintOnlineReportInfoVO result = onlineReportService.selectOnlineReportInfo(1); assertNotNull(result); assertEquals("Test Report", result.getOnlineReport().getReportName()); assertNull(result.getNotifySetting()); } @Test public void getOnlineReportBaseInfoDTO_test() { when(bizReportService.selectReport(any(), any(), any())).thenReturn(new BizReport()); when(bizNotifySettingService.getOneBy(any(), any())).thenReturn(null); onlineReportService.getOnlineReportBaseInfoDTO(new BizSpaceSprint(), "1"); } @Test public void saveSprintNotifySetting_Test() { SprintOnlineReportInfoVO reportInfoVO = new SprintOnlineReportInfoVO(); reportInfoVO.setNotifySetting(new NotifySettingDTO()); onlineReportService.saveSprintNotifySetting(reportInfoVO); } @Test(expected = Exception.class) public void saveSpaceNotifySetting_test() { onlineReportService.saveSpaceNotifySetting(new SprintOnlineReportInfoVO()); } @Test public void saveSpaceNotifySetting_test1() { when(bizSpaceSprintService.getById(any())).thenReturn(new BizSpaceSprint().setSpaceId(1)); SprintOnlineReportInfoVO reportInfoVO = new SprintOnlineReportInfoVO(); reportInfoVO.setNotifySetting(new NotifySettingDTO()); reportInfoVO.setOnlineReport(new OnlineReportBaseInfoDTO()); onlineReportService.saveSpaceNotifySetting(reportInfoVO); } @Test public void selectSprintCardPage_NoRecords_ReturnEmptyPage() { CardQuery query = new CardQuery(); query.setPageNum(1); query.setPageSize(10); Page<BizSpaceCard> emptyPage = new Page<>(); emptyPage.setRecords(Collections.emptyList()); when(spaceCardService.queryCardByCondition(any(CardQuery.class))).thenReturn(emptyPage); PageResult<OnlineReportCardDTO> result = onlineReportService.selectSprintCardPage(query); assertTrue(result.getRecords().isEmpty()); assertEquals(1, result.getCurrent()); assertEquals(10, result.getSize()); } @Test public void selectSprintCardPage_WithRecords_ReturnFilledPage() { CardQuery query = new CardQuery(); query.setPageNum(1); query.setPageSize(10); query.setSprintId(1); // Mock card page BizSpaceCard card = new BizSpaceCard(); card.setId(1); Page<BizSpaceCard> cardPage = new Page<>(); cardPage.setRecords(Arrays.asList(card)); when(spaceCardService.queryCardByCondition(any(CardQuery.class))).thenReturn(cardPage); // Mock demand users List<BizDemandUser> demandUsers = Collections.emptyList(); when(demandUserService.selectByDemandIds(anyList(), any(Integer.class))).thenReturn(demandUsers); // Mock report map BizReport uatReport = new BizReport(); BizReport gradationReport = new BizReport(); Map<String, BizReport> reportMap = new java.util.HashMap<>(); reportMap.put(AcceptanceReportEnum.reportType.UAT.name(), uatReport); reportMap.put(AcceptanceReportEnum.reportType.GRADATION.name(), gradationReport); when(bizReportService.selectReportMap(anyList(), any(AcceptanceReportEnum.relationBizType.class), any(Integer.class))).thenReturn(reportMap); // Mock report items List<BizReportItem> reportItems = Collections.emptyList(); when(reportItemService.listReportItemByReportIds(anyList())).thenReturn(reportItems); // Mock user map Map<String, UserVO> userVOMap = new java.util.HashMap<>(); when(userHelper.getUserVoMapWithFSNameByErps(anyList(), any(Function.class), any(Function.class))).thenReturn(userVOMap); PageResult<OnlineReportCardDTO> result = onlineReportService.selectSprintCardPage(query); assertEquals(1, result.getRecords().size()); } @Test public void selectSprintCardPage_WithRecords_ReturnFilledPage2() { CardQuery query = new CardQuery(); query.setPageNum(1); query.setPageSize(10); query.setSprintId(1); // Mock card page BizSpaceCard card = new BizSpaceCard(); card.setId(1); Page<BizSpaceCard> cardPage = new Page<>(); cardPage.setRecords(Arrays.asList(card)); when(spaceCardService.queryCardByCondition(any(CardQuery.class))).thenReturn(cardPage); // Mock demand users List<BizDemandUser> demandUsers = Collections.emptyList(); when(demandUserService.selectByDemandIds(anyList(), any(Integer.class))).thenReturn(demandUsers); // Mock report map BizReport uatReport = new BizReport(); BizReport gradationReport = new BizReport(); Map<String, BizReport> reportMap = new java.util.HashMap<>(); when(bizReportService.selectReportMap(anyList(), any(AcceptanceReportEnum.relationBizType.class), any(Integer.class))).thenReturn(reportMap); // Mock report items List<BizReportItem> reportItems = Collections.emptyList(); when(reportItemService.listReportItemByReportIds(anyList())).thenReturn(reportItems); // Mock user map Map<String, UserVO> userVOMap = new java.util.HashMap<>(); when(userHelper.getUserVoMapWithFSNameByErps(anyList(), any(Function.class), any(Function.class))).thenReturn(userVOMap); PageResult<OnlineReportCardDTO> result = onlineReportService.selectSprintCardPage(query); assertEquals(1, result.getRecords().size()); } @Test public void selectSprintAppList_SprintNotExist_ReturnEmptyList() { when(bizSpaceSprintService.getById(anyInt())).thenReturn(null); List<OnlineReportAppDTO> result = onlineReportService.selectSprintAppList(1); assertEquals(Collections.emptyList(), result); } @Test public void selectSprintAppList_SpaceNotExist_ReturnEmptyList() { BizSpaceSprint bizSpaceSprint = new BizSpaceSprint(); bizSpaceSprint.setId(1); bizSpaceSprint.setSpaceId(1); when(bizSpaceSprintService.getById(anyInt())).thenReturn(bizSpaceSprint); when(bizSpaceService.getById(anyInt())).thenReturn(null); List<OnlineReportAppDTO> result = onlineReportService.selectSprintAppList(1); assertEquals(Collections.emptyList(), result); } @Test public void selectSprintAppList_SprintAndSpaceExist_ReturnAppList() { BizSpaceSprint bizSpaceSprint = new BizSpaceSprint(); bizSpaceSprint.setId(1); bizSpaceSprint.setSpaceId(1); BizSpace bizSpace = new BizSpace(); bizSpace.setId(1); bizSpace.setKey("key"); when(bizSpaceSprintService.getById(anyInt())).thenReturn(bizSpaceSprint); when(bizSpaceService.getById(anyInt())).thenReturn(bizSpace); List<OnlineReportAppDTO> result = onlineReportService.selectSprintAppList(1); } @Test public void selectSprintAppList_test1() { onlineReportService.selectSprintAppList(1, "2"); } @Test public void selectSprintAppList_test2() { QueryReportVO queryReportVO = new QueryReportVO(); queryReportVO.setDetail(Arrays.asList(new DetailVO())); when(itsmClientService.getQueryReport(any(), any())).thenReturn(queryReportVO); onlineReportService.selectSprintAppList(1, "2"); } @Test public void sendOnlineReportNow_SprintNotExist_ShouldThrowException() { SprintOnlineReportInfoVO param = new SprintOnlineReportInfoVO(); param.setSprintId(1); when(bizSpaceSprintService.getById(1)).thenReturn(null); assertThrows(IllegalArgumentException.class, () -> { onlineReportService.sendOnlineReportNow(param); }); } @Test public void sendOnlineReportNow_SpaceNotConfigured_ShouldThrowException() { SprintOnlineReportInfoVO param = new SprintOnlineReportInfoVO(); param.setSprintId(1); BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setSpaceId(1); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(onlineReportService.selectSpaceSwitch(1)).thenReturn(false); assertThrows(IllegalArgumentException.class, () -> { onlineReportService.sendOnlineReportNow(param); }); } @Test public void sendOnlineReportNow_ValidConditions_ShouldSendReport() { SprintOnlineReportInfoVO param = new SprintOnlineReportInfoVO(); param.setSprintId(1); param.setNotifySetting(new NotifySettingDTO()); param.setOnlineReport(new OnlineReportBaseInfoDTO()); BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setSpaceId(1); sprint.setArchived(1); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(onlineReportService.selectSpaceSwitch(1)).thenReturn(true); onlineReportService.sendOnlineReportNow(param); } @Test public void genDefaultOnlineReportName_test() { onlineReportService.genDefaultOnlineReportName(new BizSpaceSprint(), "1", "2"); } @Test public void genDefaultOnlineReportName_test2() { SubSystemByParamsDTO subSystemByParamsDTO = new SubSystemByParamsDTO(); subSystemByParamsDTO.setDepartment("11"); when(cmdbClient.queryProjectByCode(any())).thenReturn(subSystemByParamsDTO); onlineReportService.genDefaultOnlineReportName(new BizSpaceSprint(), "1", ""); } @Test public void sendOnlineReportByNotifySetting_SprintNotArchived_ShouldThrowException() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(YesOrNoEnum.NO.getNumCode()); NotifySettingDTO notifySetting = new NotifySettingDTO(); OnlineReportBaseInfoDTO reportBaseInfoDTO = new OnlineReportBaseInfoDTO(); onlineReportService.sendOnlineReportByNotifySetting(sprint, notifySetting, reportBaseInfoDTO); } @Test public void sendOnlineReportByNotifySetting_SpaceNotExist_ShouldLogWarning() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(YesOrNoEnum.YES.getNumCode()); sprint.setSpaceId(1); NotifySettingDTO notifySetting = new NotifySettingDTO(); OnlineReportBaseInfoDTO reportBaseInfoDTO = new OnlineReportBaseInfoDTO(); when(bizSpaceService.getById(1)).thenReturn(null); onlineReportService.sendOnlineReportByNotifySetting(sprint, notifySetting, reportBaseInfoDTO); verify(bizSpaceService).getById(1); } @Test public void sendOnlineReportByNotifySetting_ReportBaseInfoIsNull_ShouldCreateNew() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(YesOrNoEnum.YES.getNumCode()); sprint.setSpaceId(1); sprint.setId(1); sprint.setName("sprintName"); BizSpace space = new BizSpace(); space.setId(1); space.setKey("key"); NotifySettingDTO notifySetting = new NotifySettingDTO(); notifySetting.setSendWays(Arrays.asList()); OnlineReportBaseInfoDTO reportBaseInfoDTO = null; when(bizSpaceService.getById(1)).thenReturn(space); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(spaceCardService.queryCardByCondition(any())).thenReturn(new Page<>()); onlineReportService.sendOnlineReportByNotifySetting(sprint, notifySetting, reportBaseInfoDTO); verify(bizSpaceService).getById(1); } @Test public void sendOnlineReportByNotifySetting_SendWayIsLark_ShouldCallWKMethod() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(YesOrNoEnum.YES.getNumCode()); sprint.setSpaceId(1); sprint.setId(1); sprint.setName("sprintName"); BizSpace space = new BizSpace(); space.setId(1); space.setKey("key"); NotifySettingDTO notifySetting = new NotifySettingDTO(); notifySetting.setSendWays(Arrays.asList(BizNotifySendWayEnum.LARK.getCode())); ChatInfoDataResp.ChatData chatData = new ChatInfoDataResp.ChatData(); chatData.setChatId("chatId"); notifySetting.setLarks(Arrays.asList(chatData)); OnlineReportBaseInfoDTO reportBaseInfoDTO = new OnlineReportBaseInfoDTO(); when(bizSpaceService.getById(1)).thenReturn(space); when(spaceCardService.queryCardByCondition(any())).thenReturn(new Page<>()); onlineReportService.sendOnlineReportByNotifySetting(sprint, notifySetting, reportBaseInfoDTO); } @Test public void sendOnlineReportByNotifySetting_SendWayIsEmail_ShouldCallEmailMethod() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(YesOrNoEnum.YES.getNumCode()); sprint.setSpaceId(1); sprint.setId(1); sprint.setName("sprintName"); BizSpace space = new BizSpace(); space.setId(1); space.setKey("key"); NotifySettingDTO notifySetting = new NotifySettingDTO(); notifySetting.setSendWays(Arrays.asList(BizNotifySendWayEnum.EMAIL.getCode())); notifySetting.setEmails("[email protected]"); OnlineReportBaseInfoDTO reportBaseInfoDTO = new OnlineReportBaseInfoDTO(); when(bizSpaceService.getById(1)).thenReturn(space); when(spaceCardService.queryCardByCondition(any())).thenReturn(new Page<>()); when(scriptEngineManager.getEngineByName(any())).thenReturn(new VelocityScriptEngine()); onlineReportService.sendOnlineReportByNotifySetting(sprint, notifySetting, reportBaseInfoDTO); } @Test public void sendOnlineReportForSprints_test() { BizSpaceSprint sprint = new BizSpaceSprint(); when(spaceSettingService.checkRequireKeyIsYesCode(any(), any())).thenReturn(true); when(bizSpaceSprintService.listByIds(any())).thenReturn(Arrays.asList(sprint)); onlineReportService.sendOnlineReportForSprints(Arrays.asList(1)); } @Test public void sendOnlineReportForSprints_test1() { BizSpaceSprint sprint = new BizSpaceSprint(); when(bizSpaceSprintService.listByIds(any())).thenReturn(Arrays.asList(sprint)); onlineReportService.sendOnlineReportForSprints(Arrays.asList(1)); } @Test public void sendOnlineReportForSprints_test2() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(0); when(spaceSettingService.checkRequireKeyIsYesCode(any(), any())).thenReturn(true); when(bizSpaceSprintService.listByIds(any())).thenReturn(Arrays.asList(sprint)); onlineReportService.sendOnlineReportForSprints(Arrays.asList(1)); } @Test public void sendOnlineReportForSprints_test3() { BizSpaceSprint sprint = new BizSpaceSprint(); sprint.setArchived(1); when(spaceSettingService.checkRequireKeyIsYesCode(any(), any())).thenReturn(true); BizNotifySetting bizNotifySetting = new BizNotifySetting(); when(bizNotifySettingService.getOneBy(any(), any())).thenReturn(bizNotifySetting); when(bizSpaceSprintService.listByIds(any())).thenReturn(Arrays.asList(sprint)); onlineReportService.sendOnlineReportForSprints(Arrays.asList(1)); } @Test public void selectSpaceNotifySetting_test() { onlineReportService.selectSpaceNotifySetting(1); } @Test public void selectSpaceNotifySetting_test2() { when(bizSpaceSprintService.getSpaceBySprintId(any())).thenReturn(new BizSpace().setId(1)); onlineReportService.selectSpaceNotifySetting(1); } @Test public void selectSpaceNotifySetting_test3() { when(bizSpaceSprintService.getSpaceBySprintId(any())).thenReturn(new BizSpace().setId(1)); when(bizNotifySettingService.getOneBy(any(), any())).thenReturn(new BizNotifySetting().setId(1)); onlineReportService.selectSpaceNotifySetting(1); } @Test public void queryCheckTest() { BizReport bizReport = new BizReport(); bizReport.setExtendInfo("{\"checkPoint\":\"Test CheckPoint\",\"checkPointResult\":\"Test CheckPointResult\",\"omittedIssuesForRecord\":\"Test OmittedIssuesForRecord\"}"); when(bizReportService.selectReport(AcceptanceReportEnum.reportType.ONLINE, AcceptanceReportEnum.relationBizType.SPRINT, 1)).thenReturn(bizReport); OnlineReportCheckDTO result = onlineReportService.queryCheck(1); assertNotNull(result); assertEquals("Test CheckPoint", result.getCheckPoint()); assertEquals("Test CheckPointResult", result.getCheckPointResult()); assertEquals("Test OmittedIssuesForRecord", result.getOmittedIssuesForRecord()); } @Test public void updateCheckTest() { // Mock data BizSpaceSprint sprint = new BizSpaceSprint().setId(1).setSpaceId(1); BizSpace space = new BizSpace().setId(1).setKey("key"); OnlineReportCheckDTO onlineReportCheckDTO = new OnlineReportCheckDTO() .setCheckPoint("Test CheckPoint") .setCheckPointResult("Test CheckPointResult") .setOmittedIssuesForRecord("Test OmittedIssuesForRecord"); when(bizSpaceSprintService.getById(1)).thenReturn(sprint); when(bizSpaceService.getById(1)).thenReturn(space); when(onlineReportService.getOnlineReportBaseInfoDTO(eq(sprint), eq("key"))) .thenReturn(new OnlineReportBaseInfoDTO()); // Act onlineReportService.updateCheck(onlineReportCheckDTO, 1); // Verify verify(bizReportService, times(1)).saveOrUpdateOnlineReport(1, any(OnlineReportBaseInfoDTO.class)); } } 以下是onlineReportService对应类的代码:package com.jd.jacp.report.service.impl; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.jd.jacp.client.dto.CICDAppGrayscaleDeployInfo; import com.jd.jacp.client.dto.GetCiCdTaskQuery; import com.jd.jacp.client.service.ICicdClient; import com.jd.jacp.client.service.ICmdbClient; import com.jd.jacp.client.service.ItsmClientService; import com.jd.jacp.common.feishu.FeiShuMessageSender; import com.jd.jacp.common.service.UserHelper; import com.jd.jacp.common.vo.UserVO; import com.jd.jacp.common.vo.enums.YesOrNoEnum; import com.jd.jacp.demand.entity.BizDemandUser; import com.jd.jacp.demand.service.IBizDemandUserService; import com.jd.jacp.demand.vo.DemandUserTypeEnum; import com.jd.jacp.notify.entity.BizNotifyRule; import com.jd.jacp.notify.entity.BizNotifySetting; import com.jd.jacp.notify.enums.BizNotifySendWayEnum; import com.jd.jacp.notify.enums.BizNotifyTypeEnum; import com.jd.jacp.notify.service.IBizNotifyRuleService; import com.jd.jacp.notify.service.IBizNotifySettingService; import com.jd.jacp.report.dto.*; import com.jd.jacp.report.entity.BizReport; import com.jd.jacp.report.entity.BizReportItem; import com.jd.jacp.report.enums.AcceptanceReportEnum; import com.jd.jacp.report.service.IBizReportItemService; import com.jd.jacp.report.service.IBizReportService; import com.jd.jacp.report.service.IOnlineReportService; import com.jd.jacp.report.vo.SprintOnlineReportInfoVO; import com.jd.jacp.space.dto.CardQuery; import com.jd.jacp.space.dto.SubSystemByParamsDTO; import com.jd.jacp.space.entity.BizSpace; import com.jd.jacp.space.entity.BizSpaceCard; import com.jd.jacp.space.entity.BizSpaceSprint; import com.jd.jacp.space.service.IBizSpaceCardService; import com.jd.jacp.space.service.IBizSpaceService; import com.jd.jacp.space.service.IBizSpaceSettingService; import com.jd.jacp.space.service.IBizSpaceSprintService; import com.jd.jacp.space.service.impl.BizSpaceSettingServiceImpl; import com.jd.jacp.space.vo.DetailVO; import com.jd.jacp.space.vo.QueryReportVO; import com.jd.jacp.util.AssertUtil; import com.jd.jacp.util.EmailSender; import com.msxf.devops.common.PageResult; import com.msxf.fcid.xmsg.reponse.ChatInfoDataResp; import com.msxf.fcid.xmsg.sdk.response.FeishuMessageSendResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import java.io.InputStream; import java.io.StringWriter; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author ke.feng-n */ @Slf4j @Service public class OnlineReportServiceImpl implements IOnlineReportService { @Autowired private IBizSpaceSprintService bizSpaceSprintService; @Autowired private ItsmClientService itsmClientService; @Autowired private IBizReportService bizReportService; @Autowired private ICmdbClient cmdbClient; @Autowired private IBizSpaceService bizSpaceService; @Autowired private IBizNotifySettingService bizNotifySettingService; @Autowired private IBizNotifyRuleService bizNotifyRuleService; @Autowired private IBizSpaceCardService spaceCardService; @Autowired private IBizDemandUserService demandUserService; @Autowired private IBizReportItemService reportItemService; @Autowired private UserHelper userHelper; @Resource(name = "scriptEngineManager") private ScriptEngineManager scriptEngineManager; @Autowired private FeiShuMessageSender feiShuMessageSender; @Autowired private ICicdClient cicdClient; @Autowired private IBizSpaceSettingService spaceSettingService; @Value("${env.domain.name}") private String domain; @Resource EmailSender emailSender; @Override public SprintOnlineReportInfoVO selectOnlineReportInfo(Integer sprintId) { BizSpaceSprint sprint = bizSpaceSprintService.getById(sprintId); Assert.notNull(sprint, "迭代不存在"); BizSpace space = bizSpaceService.getById(sprint.getSpaceId()); Assert.notNull(space, "迭代所属子系统不存在"); //获取报告名称和遗漏问题 OnlineReportBaseInfoDTO onlineReportBaseInfoDTO = getOnlineReportBaseInfoDTO(sprint, space.getKey()); SprintOnlineReportInfoVO reportInfoVO = new SprintOnlineReportInfoVO(); reportInfoVO.setOnlineReport(onlineReportBaseInfoDTO); //获取迭代的通知配置信息 BizNotifySetting sprintNotifySetting = getSprintNotifySetting(sprint); if (ObjectUtil.isEmpty(sprintNotifySetting)) { return reportInfoVO; } BizNotifyRule notifyRule = bizNotifyRuleService.getOneByNotifyId(sprintNotifySetting.getId()); NotifySettingDTO notifySetting = NotifySettingDTO.of(sprintNotifySetting, notifyRule); reportInfoVO.setNotifySetting(notifySetting); return reportInfoVO; } /** * 获取迭代的基础配置信息(报告名称,) * * @param sprint * @param spaceKey * @return */ public OnlineReportBaseInfoDTO getOnlineReportBaseInfoDTO(BizSpaceSprint sprint, String spaceKey) { BizReport bizReport = bizReportService.selectReport(AcceptanceReportEnum.reportType.ONLINE, AcceptanceReportEnum.relationBizType.SPRINT, sprint.getId()); OnlineReportBaseInfoDTO onlineReportBaseInfoDTO; if (ObjectUtil.isNotEmpty(bizReport) && StrUtil.isNotBlank(bizReport.getExtendInfo())) { onlineReportBaseInfoDTO = JSONUtil.toBean(bizReport.getExtendInfo(), OnlineReportBaseInfoDTO.class); } else { BizNotifySetting spaceNotifySetting = bizNotifySettingService.getOneBy(String.valueOf(sprint.getSpaceId()), BizNotifyTypeEnum.SPACE_SPRINT_ONLINE_REPORT.getCode()); onlineReportBaseInfoDTO = genDefaultOnlineReportName(sprint, spaceKey, ObjectUtil.isEmpty(spaceNotifySetting) ? null : spaceNotifySetting.getRelatedObjName()); } return onlineReportBaseInfoDTO; } @Override @Transactional(rollbackFor = Exception.class) public void saveSprintNotifySetting(SprintOnlineReportInfoVO param) { bizReportService.saveOrUpdateOnlineReport(param.getSprintId(), param.getOnlineReport()); Integer notifyId = bizNotifySettingService.saveOrUpdateNotifySetting(BizNotifyTypeEnum.SPRINT_ONLINE_REPORT, String.valueOf(param.getSprintId()), param.getNotifySetting(), null); bizNotifyRuleService.saveOrUpdateNotifyRule(notifyId, param.getNotifySetting().getSendTime()); } @Override @Transactional(rollbackFor = Exception.class) public void saveSpaceNotifySetting(SprintOnlineReportInfoVO param) { BizSpaceSprint sprint = bizSpaceSprintService.getById(param.getSprintId()); Assert.notNull(sprint, "迭代不存在"); Integer notifyId = bizNotifySettingService.saveOrUpdateNotifySetting(BizNotifyTypeEnum.SPACE_SPRINT_ONLINE_REPORT, String.valueOf(sprint.getSpaceId()), param.getNotifySetting(), param.getOnlineReport().getDepartment()); bizNotifyRuleService.saveOrUpdateNotifyRule(notifyId, param.getNotifySetting().getSendTime()); } @Override public PageResult<OnlineReportCardDTO> selectSprintCardPage(CardQuery query) { Page<BizSpaceCard> cardPage = spaceCardService.queryCardByCondition(query); List<OnlineReportCardDTO> cardDTOList = OnlineReportCardDTO.buildFromCardEntity(cardPage.getRecords()); if (CollectionUtil.isEmpty(cardDTOList)) { return PageResult.newEmptyPage(Long.valueOf(query.getPageNum()), Long.valueOf(query.getPageSize())); } //获取需求提报人列表 List<Integer> demandIds = cardDTOList.stream().map(OnlineReportCardDTO::getDemandId).distinct().collect(Collectors.toList()); List<BizDemandUser> bizDemandUsers = demandUserService.selectFeishuUserByDemandIds(demandIds, DemandUserTypeEnum.CONTACT_TYPE_BIZ.getId()); Map<Integer, List<BizDemandUser>> submitterMap = bizDemandUsers.stream().collect(Collectors.groupingBy(BizDemandUser::getDemandId)); List<String> cardErps = cardDTOList.stream() .flatMap(cardDTO -> Stream.of( cardDTO.getProductManagerErp(), cardDTO.getProcessorErp(), cardDTO.getTestLeaderErp() )).distinct() .collect(Collectors.toList()); Map<String, BizReport> reportMap = bizReportService.selectReportMap(Arrays.asList(AcceptanceReportEnum.reportType.UAT, AcceptanceReportEnum.reportType.GRADATION), AcceptanceReportEnum.relationBizType.SPRINT, query.getSprintId()); List<Integer> reportIds = reportMap.values().stream().map(BizReport::getId).collect(Collectors.toList()); //获取验收报告信息 List<String> acceptorErps = Collections.emptyList(); Map<Integer, Map<String, BizReportItem>> reportItemMap = new HashMap<>(); if(CollectionUtil.isNotEmpty(reportIds)) { List<BizReportItem> reportItems = reportItemService.listReportItemByReportIds(reportIds); acceptorErps = reportItems.stream().map(BizReportItem::getAccepters) .flatMap(erp -> JSONUtil.toList(erp, String.class).stream()) .filter(StrUtil::isNotBlank) .distinct() .collect(Collectors.toList()); //报告id-卡片id-报告项 reportItemMap = reportItems.stream().collect(Collectors.groupingBy(BizReportItem::getReportId, Collectors.toMap(BizReportItem::getRelationItemIdentifier, Function.identity(), (v1, v2) -> v1))); } cardErps.addAll(acceptorErps); Map<String, UserVO> userVOMap = userHelper.getUserVoMapWithFSNameByErps(cardErps.stream().filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList()), UserVO::getErp, Function.identity()); for (OnlineReportCardDTO cardDTO : cardDTOList) { //填充需求提报人 cardDTO.setSubmitter(BizDemandUser.buildUserVOList(submitterMap.get(cardDTO.getDemandId()))); //填充卡片相关人信息 cardDTO.setProductManager(userVOMap.get(cardDTO.getProductManagerErp())); cardDTO.setProcessor(userVOMap.get(cardDTO.getProcessorErp())); cardDTO.setTestLeader(userVOMap.get(cardDTO.getTestLeaderErp())); //填充UAT验收信息 BizReport uatReport = reportMap.get(AcceptanceReportEnum.reportType.UAT.name()); cardDTO.fillUATAcceptanceInfo(reportItemMap, uatReport, userVOMap); //填充灰度验收信息 BizReport gradationReport = reportMap.get(AcceptanceReportEnum.reportType.GRADATION.name()); cardDTO.fillGradationAcceptanceInfo(reportItemMap, gradationReport, userVOMap); } return PageResult.newInstance(cardDTOList, cardPage.getPages(), cardPage.getTotal(), cardPage.getCurrent(), cardPage.getSize()); } @Override public List<OnlineReportAppDTO> selectSprintAppList(Integer sprintId) { BizSpaceSprint sprint = bizSpaceSprintService.getById(sprintId); if (ObjectUtil.isEmpty(sprint)) { return Collections.emptyList(); } BizSpace space = bizSpaceService.getById(sprint.getSpaceId()); if (ObjectUtil.isEmpty(space)) { return Collections.emptyList(); } return this.selectSprintAppList(sprintId, space.getKey()); } @Override public List<OnlineReportAppDTO> selectSprintAppList(Integer sprintId, String spaceKey) { DetailVO itsmDetail = getSprintItsmOnlineDetail(sprintId, spaceKey); if (ObjectUtil.isEmpty(itsmDetail) || ObjectUtil.isEmpty(itsmDetail.getApplyCode())) { return Collections.emptyList(); } List<CICDAppGrayscaleDeployInfo> cicdAppGrayscaleDeployInfos = Collections.emptyList(); try { cicdAppGrayscaleDeployInfos = cicdClient.getTaskListByParam(GetCiCdTaskQuery.buildQueryProdTaskQuery(itsmDetail.getApplyCode())); } catch (Exception e) { log.warn("调用CICD接口查询迭代部署完成应用列表失败:", e); } return OnlineReportAppDTO.buildList(cicdAppGrayscaleDeployInfos); } @Override public void sendOnlineReportNow(SprintOnlineReportInfoVO param) { BizSpaceSprint sprint = bizSpaceSprintService.getById(param.getSprintId()); Assert.notNull(sprint, "迭代不存在"); boolean sendSwitch = this.selectSpaceSwitch(sprint.getSpaceId()); Assert.isTrue(sendSwitch, "空间未开启上线报告发送配置"); this.sendOnlineReportByNotifySetting(sprint, param.getNotifySetting(), param.getOnlineReport()); } /** * 查询迭代卡片列表 * * @param sprintId */ public List<OnlineReportCardDTO> selectSprintCardList(Integer sprintId) { CardQuery cardQuery = new CardQuery(); cardQuery.setSprintId(sprintId); cardQuery.setPageNum(1); cardQuery.setPageSize(10000); PageResult<OnlineReportCardDTO> sprintCardPage = this.selectSprintCardPage(cardQuery); return sprintCardPage.getRecords(); } /** * 生成默认的上线报告名称 * * @return */ public OnlineReportBaseInfoDTO genDefaultOnlineReportName(BizSpaceSprint sprint, String spaceKey, String department) { if (StrUtil.isBlank(department)) { SubSystemByParamsDTO subSystemByParamsDTO = cmdbClient.queryProjectByCode(spaceKey); department = ObjectUtil.isNotEmpty(subSystemByParamsDTO) ? subSystemByParamsDTO.getDepartment() : "暂无部门"; } //获取迭代上线流程信息 DetailVO detailVO = getSprintItsmOnlineDetail(sprint.getId(), spaceKey); String deployType = Optional.ofNullable(detailVO).map(DetailVO::getDeployType).orElse(""); String sprintEndDate = ObjectUtil.isNotEmpty(sprint.getEndDate()) ? DateUtil.format(sprint.getEndDate(), DatePattern.PURE_DATE_FORMAT) : ""; String reportName = "版本发布" + "-" + department + "-" + deployType + "-" + sprintEndDate; return new OnlineReportBaseInfoDTO().setReportName(reportName).setDepartment(department).setDeployType(deployType).setSprintEndDate(sprintEndDate); } /** * 获取迭代上线流程信息 * * @param sprintId * @param spaceKey * @return */ private DetailVO getSprintItsmOnlineDetail(Integer sprintId, String spaceKey) { QueryReportVO queryReport = itsmClientService.getQueryReport(sprintId, spaceKey); DetailVO detailVO = null; if (ObjectUtil.isNotEmpty(queryReport) && CollectionUtil.isNotEmpty(queryReport.getDetail())) { detailVO = queryReport.getDetail().get(0); } return detailVO; } @Override public String sprintDeployReportWK(SprintOnlineReportInfoDTO sprintOnlineReportInfoDTO, List<String> chats, boolean acceptanceReportEnable) { SprintDeployReportDTO dto = SprintDeployReportDTO.convertFromSprintOnlineReportInfoDTO(sprintOnlineReportInfoDTO, domain, BizNotifySendWayEnum.LARK.getCode(), acceptanceReportEnable); try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream( acceptanceReportEnable ? "templates/SprintDeployReport.json" : "templates/SprintDeployReport-NoAcceptance.json")) { String content = IOUtils.toString(inputStream); ScriptEngine engine = scriptEngineManager.getEngineByName("velocity"); JSONObject wkParam = JSON.parseObject(JSON.toJSONString(dto)); ScriptContext scriptContext = engine.getContext(); wkParam.keySet().forEach(key -> scriptContext.setAttribute(key, wkParam.get(key), ScriptContext.ENGINE_SCOPE)); scriptContext.setWriter(new StringWriter()); String contentText = engine.eval(content).toString(); FeishuMessageSendResponse response = feiShuMessageSender.withCustomTemplate(contentText, "global-template-notice", chats, null, null); AssertUtil.notNull(response, "no response"); AssertUtil.isTrue(Objects.equals(response.getCode(), "0"), response.getMsg()); AssertUtil.notEmpty(response.getData(), "wk message send fault"); return response.getData().get(0); } catch (Exception e) { log.error("sprint deploy report wk message send error", e); } return null; } @Override public void sendOnlineReportByNotifySetting(BizSpaceSprint sprint, NotifySettingDTO notifySetting, OnlineReportBaseInfoDTO reportBaseInfoDTO) { BizSpace space = bizSpaceService.getById(sprint.getSpaceId()); if (ObjectUtil.isEmpty(space)) { log.warn("【发送上线报告】迭代所属子系统不存在:{}", sprint.getSpaceId()); return; } if(ObjectUtil.isEmpty(reportBaseInfoDTO)) { reportBaseInfoDTO = this.getOnlineReportBaseInfoDTO(sprint, space.getKey()); } List<OnlineReportCardDTO> cardList = this.selectSprintCardList(sprint.getId()); List<OnlineReportAppDTO> appList = this.selectSprintAppList(sprint.getId(), space.getKey()); SprintOnlineReportInfoDTO reportInfoDTO = new SprintOnlineReportInfoDTO() .setSprintId(sprint.getId()) .setSprintName(sprint.getName()) .setSpaceKey(space.getKey()) .setOnlineReportBaseInfo(reportBaseInfoDTO) .setOnlineReportCardList(cardList) .setOnlineReportAppList(appList); List<String> sendWays = notifySetting.getSendWays(); boolean acceptanceReportEnable = spaceSettingService.acceptanceReportEnable(space.getId()); if (sendWays.contains(BizNotifySendWayEnum.LARK.getCode())) { List<String> chatIds = notifySetting.getLarks().stream().map(ChatInfoDataResp.ChatData::getChatId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); this.sprintDeployReportWK(reportInfoDTO, chatIds, acceptanceReportEnable); } if (sendWays.contains(BizNotifySendWayEnum.EMAIL.getCode())) { this.sprintDeployReportEmail(reportInfoDTO, Arrays.asList(notifySetting.getEmails().split(",")), null, acceptanceReportEnable); } } @Override public NotifySettingDTO selectSpaceNotifySetting(Integer sprintId) { BizSpace space = bizSpaceSprintService.getSpaceBySprintId(sprintId); if (ObjectUtil.isEmpty(space)) { return null; } BizNotifySetting spaceNotifySetting = bizNotifySettingService.getOneBy(String.valueOf(space.getId()), BizNotifyTypeEnum.SPACE_SPRINT_ONLINE_REPORT.getCode()); if (ObjectUtil.isEmpty(spaceNotifySetting)) { return null; } BizNotifyRule notifyRule = bizNotifyRuleService.getOneByNotifyId(spaceNotifySetting.getId()); return NotifySettingDTO.of(spaceNotifySetting, notifyRule); } @Override public void sendOnlineReportForSprints(List<Integer> sprintIds) { List<BizSpaceSprint> sprints = bizSpaceSprintService.listByIds(sprintIds); for (BizSpaceSprint sprint : sprints) { if(!this.selectSpaceSwitch(sprint.getSpaceId())) { continue; } if (YesOrNoEnum.NO.getNumCode().equals(sprint.getArchived())) { continue; } BizNotifySetting notifySetting = getSprintNotifySetting(sprint); if (ObjectUtil.isEmpty(notifySetting)) { return; } this.sendOnlineReportByNotifySetting(sprint, NotifySettingDTO.of(notifySetting), null); } } @Override public void sprintDeployReportEmail(SprintOnlineReportInfoDTO sprintOnlineReportInfoDTO, List<String> receiver, List<String> carbon, boolean acceptanceReportEnable) { SprintDeployReportDTO dto = SprintDeployReportDTO.convertFromSprintOnlineReportInfoDTO(sprintOnlineReportInfoDTO, domain, BizNotifySendWayEnum.EMAIL.getCode(), acceptanceReportEnable); try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("templates/SprintDeployReport.html")) { String content = IOUtils.toString(inputStream); ScriptEngine engine = scriptEngineManager.getEngineByName("velocity"); JSONObject htmlParam = JSON.parseObject(JSON.toJSONString(dto)); ScriptContext scriptContext = engine.getContext(); htmlParam.keySet().forEach(key -> { scriptContext.setAttribute(key, htmlParam.get(key), ScriptContext.ENGINE_SCOPE); }); scriptContext.setAttribute("acceptance_report_enable", acceptanceReportEnable, ScriptContext.ENGINE_SCOPE); scriptContext.setWriter(new StringWriter()); String contentText = engine.eval(content).toString(); emailSender.dcpSendEmail(receiver, carbon, String.format("%s一上线报告", dto.getSprintTitle()), contentText); } catch (Exception e) { log.error("sprint deploy report email message send error", e); } } /** * 获取迭代可用的通知配置信息 * * @param sprint * @return */ @Override public BizNotifySetting getSprintNotifySetting(BizSpaceSprint sprint) { if(ObjectUtil.isEmpty(sprint)) { return null; } BizNotifySetting sprintNotifySetting = bizNotifySettingService.getOneBy(String.valueOf(sprint.getId()), BizNotifyTypeEnum.SPRINT_ONLINE_REPORT.getCode()); if (ObjectUtil.isEmpty(sprintNotifySetting)) { sprintNotifySetting = bizNotifySettingService.getOneBy(String.valueOf(sprint.getSpaceId()), BizNotifyTypeEnum.SPACE_SPRINT_ONLINE_REPORT.getCode()); } return sprintNotifySetting; } @Override public boolean selectSpaceSwitch(Integer spaceId) { return spaceSettingService.checkRequireKeyIsYesCode(spaceId, BizSpaceSettingServiceImpl.REQUIRED_SEND_REPORT_AFTER_SPRINT_ARCHIVED); } /** * 根据迭代id查询生产验证情况 * @param sprintId * @return */ @Override public OnlineReportCheckDTO queryCheck(Integer sprintId) { BizReport bizReport = bizReportService.selectReport(AcceptanceReportEnum.reportType.ONLINE, AcceptanceReportEnum.relationBizType.SPRINT, sprintId); OnlineReportBaseInfoDTO onlineReportBaseInfoDTO; OnlineReportCheckDTO onlineReportCheckDTO = new OnlineReportCheckDTO(); if (ObjectUtil.isNotEmpty(bizReport) && StrUtil.isNotBlank(bizReport.getExtendInfo())) { onlineReportBaseInfoDTO = JSONUtil.toBean(bizReport.getExtendInfo(), OnlineReportBaseInfoDTO.class); onlineReportCheckDTO.setCheckPoint(onlineReportBaseInfoDTO.getCheckPoint()); onlineReportCheckDTO.setCheckPointResult(onlineReportBaseInfoDTO.getCheckPointResult()); onlineReportCheckDTO.setOmittedIssuesForRecord(onlineReportBaseInfoDTO.getOmittedIssuesForRecord()); } return onlineReportCheckDTO; } /** * 更新生产验证情况 * @param onlineReportCheckDTO * @param sprintId */ @Override public void updateCheck(OnlineReportCheckDTO onlineReportCheckDTO, Integer sprintId) { BizSpaceSprint sprint = bizSpaceSprintService.getById(sprintId); Assert.notNull(sprint, "迭代不存在"); BizSpace space = bizSpaceService.getById(sprint.getSpaceId()); Assert.notNull(space, "迭代所属子系统不存在"); //获取报告名称和遗漏问题 OnlineReportBaseInfoDTO onlineReportBaseInfoDTO = getOnlineReportBaseInfoDTO(sprint, space.getKey()); //设置数据 onlineReportBaseInfoDTO.setCheckPoint(onlineReportCheckDTO.getCheckPoint()); onlineReportBaseInfoDTO.setCheckPointResult(onlineReportCheckDTO.getCheckPointResult()); onlineReportBaseInfoDTO.setOmittedIssuesForRecord(onlineReportCheckDTO.getOmittedIssuesForRecord()); //如果有数据直接更新,没有生成新数据 bizReportService.saveOrUpdateOnlineReport(sprintId, onlineReportBaseInfoDTO); } } 当运行updateCheckTest时,报错:java.lang.NullPointerException at com.jd.jacp.report.service.impl.OnlineReportServiceImpl.getOnlineReportBaseInfoDTO(OnlineReportServiceImpl.java:163) at com.jd.jacp.unit.report.OnlineReportServiceImplTest.updateCheckTest(OnlineReportServiceImplTest.java:567) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55) Process finished with exit code -1

请为以下函数写一个测试函数: public List<QueryCardBySprintIdRsp> queryCardByItsmApplyCode(String itsmApplyCode) { //使用ITSM流程编码查询迭代编号 Integer sprintId = itsmClientService.getIterationIdByApplyCode(itsmApplyCode); //查询迭代编号下的所有卡片信息 LambdaQueryWrapper<BizSpaceCard> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(BizSpaceCard::getSprintId, sprintId); List<BizSpaceCard> cardList = baseMapper.selectList(wrapper); if (CollectionUtils.isEmpty(cardList)) { return Collections.emptyList(); } //根据所有卡片id查询对应的应用关系信息,保存在一个map中 List<Integer> cardIds = cardList.stream() .map(BizSpaceCard::getId) .collect(Collectors.toList()); Map<Integer, List<BizSpaceCardAppRelation>> cardAppMap = bizSpaceCardAppRelationService.selectAppsByCardIds(cardIds); List<QueryCardBySprintIdRsp> responseList = cardList.stream().map(card -> { QueryCardBySprintIdRsp rsp = new QueryCardBySprintIdRsp(); //表获取卡片状态名称 String cardStatusName = cardStatusService.getStatusNameByCode(card.getSpaceId(), card.getCardStatusId()); rsp.setCardId(card.getId()) .setCardName(card.getCardName()) .setCardStatusId(card.getCardStatusId()) .setCardStatusName(cardStatusName)//卡片状态名称 .setSprintId(card.getSprintId()) .setCardCode(card.getCardCode()) .setProcessorErp(card.getProcessorErp()) .setProcessorName(card.getProcessorName()) .setOwnerCheck(card.getOwnerCheck()) .setArchitectCheck(card.getArchitectCheck()) .setAppRelations(cardAppMap.get(card.getId()));//通过卡片id获取应用关系 return rsp; }).collect(Collectors.toList()); return responseList; }

#include "microphonecard.h" MicrophoneCard::MicrophoneCard(QSharedPointer<EntityMicrophoneList> micList, int w, int h, QWidget *parent) : QWidget(parent) { this->cardList = micList; this->setObjectName("paaa"); // 设置背景颜色 QString styleSheet = QString( "background-color: %1; " "border-radius: %2px; " "border: 1px solid %3;" ) .arg(cardList->getCardBackground()) .arg(cardList->getRadius()) .arg(cardList->getCardBackground()); this->setFixedSize(w, h); this->setStyleSheet(styleSheet); m_gridLayout = new QGridLayout(this); m_gridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); // 元素间距 m_gridLayout->setSpacing(0); // 边距 m_gridLayout->setContentsMargins(0, 0, 0, 0); icon = new QLabel(this); IconHelper::setIconFontIndex(4); IconHelper::setIcon(icon,0xe60b,24); icon->setFixedSize(w / 5, h / 1); // 固定子组件尺寸 icon->setStyleSheet("background: transparent; border: none;"); m_gridLayout->addWidget(icon, 0, 0); people = new QLabel(this); people->setText("参会人员"); people->setFixedSize(w / 5, h / 1); // 固定子组件尺寸 m_gridLayout->addWidget(people, 0, 1); slider = new QSlider(Qt::Horizontal,this); // 设置范围(默认0-99) slider->setRange(0, 100); // 设置初始值 slider->setValue(0); // 设置步长 slider->setSingleStep(1); // 方向键步长 slider->setPageStep(10); // 鼠标点击滑块槽时的步长 slider->setFixedSize(w / 5, h / 1); // 固定子组件尺寸 slider->setStyleSheet(R"( QSlider::groove:horizontal { height: 8px; background: #ddd; } QSlider::handle:horizontal { width: 16px; margin: -6px 0; background: #2196F3; border-radius: 8px; } )"); m_gridLayout->addWidget(slider, 0, 2); decibel = new QLabel(this); decibel->setText("50db"); decibel->setFixedSize(w / 5, h / 1); // 固定子组件尺寸 m_gridLayout->addWidget(decibel, 0, 3); switchButton = new QLabel(this); IconHelper::setIconFontIndex(4); IconHelper::setIcon(switchButton,0xe60b,24); switchButton->setFixedSize(w / 5, h / 1); // 固定子组件尺寸 m_gridLayout->addWidget(switchButton, 0, 4); } 只有子组件演示改变,this样式没变化

@Slf4j @Service public class ImportPersonService { @Autowired private PersonRepository personRepository; @Autowired private GroupRepository groupRepository; @Autowired private AccessCardRepository accessCardRepository; @Autowired private PersonGroupMappingService personGroupMappingService; @Autowired private PersonImportProcessPublisher personImportProcessPublisher; @Autowired private PersonEmailService personEmailService; @Autowired private PersonAppAccountEventPublisher personAppAccountEventPublisher; @Resource(name = ThreadPoolNameConstant.PERSON_IMPORT_EXEC_POOL) private ThreadPoolTaskExecutor executor; /** * 批量导入人员 * * @param request 携带上传excel的fileKey的bean * @return 执行结果 */ public OperationResponse<Void> batchImportPerson(PersonImportDTO request) { // 通过线程池解析excel并不断推送进度 String vmsId = request.getVmsId(); List<AnalysedRow> rowList = request.getAnalysedRows(); int rowCount = rowList.size(); ImportPersonProcessDTO processDTO = new ImportPersonProcessDTO(0, 0, rowCount, false, new ArrayList<>()); OperationResponse<ImportPersonProcessDTO> processResponse = OperationResponse.ok(processDTO); List<String> employeeIdList = rowList.stream().map(AnalysedRow::getPersonDTO).map(PersonDTO::getEmployeeId) .collect(Collectors.toList()); // 传入的数据中,与现有employeeId有冲突的数据 List<String> conflictEmployeeIdList = getConflictEmployeeIds(vmsId, employeeIdList); // 传入的数据库中,与现有employeeId无冲突,但是重复传入的employeeId List<String> duplicateEmployeeIdList = getDuplicateEmployeeIds(employeeIdList, conflictEmployeeIdList); // 收集需要注册APP账号的人员,批量进行处理 List accountRegistrations = new ArrayList<>(); // 收集卡片数据,批量进行保存 List<AccessCardDO> cardsToSave = new ArrayList<>(); // 收集分组映射关系,批量进行保存 List<String> savedPersonIdList = new ArrayList<>(); for (int i = 0; i < rowCount; i++) { AnalysedRow row = rowList.get(i); PersonDTO personDTO = row.getPersonDTO(); PersonDO personDO = DOAndDTOMapperUtils.toPersonDO(personDTO); // 如果在controller层时解析或校验错误,推送错误消息 if (!row.isValid()) { String message = row.getMessage(); publishProcess(processResponse, i, request, false, personDO, message); continue; } // employeeId与数据库中的人员有冲突 if (conflictEmployeeIdList.contains(personDTO.getEmployeeId())) { publishProcess(processResponse, i, request, false, personDO, "employeeId conflict with existing person"); continue; } // employeeId与同一批导入的其他人员有冲突 if (duplicateEmployeeIdList.contains(personDTO.getEmployeeId())) { publishProcess(processResponse, i, request, false, personDO, "employeeId conflict with other person in excel"); continue; } // 保存基本信息到person info表 OperationResponse<String> personIdResponse = personRepository.save(personDO); if (!personIdResponse.isOk() || personIdResponse.getResult() == null) { publishProcess(processResponse, i, request, false, personDO, "save this line failed"); continue; } // 向前台通知导入成功 publishProcess(processResponse, i, request, true, personDO, null); // 保存personId,用于后续批量保存与组的关联信息 String personId = personIdResponse.getResult(); savedPersonIdList.add(personId); // 保存卡片信息,用于后续批量保存 List<AccessCardDO> cardList = row.getCardList().stream().map(DOAndDTOMapperUtils::toAccessCardDO) .map(card -> card.setPersonId(personId)).collect(Collectors.toList()); cardsToSave.addAll(cardList); // 处理人员需要使用app的情况,为他发送邀请邮件及通知Identity Access注册账号 handleUsingApp(personDO, personId, accountRegistrations); } // 异步为人员保存与组的关联信息、卡片信息、注册app账户 executor.submit(() -> handleAsyncBatchDeal(request, savedPersonIdList, cardsToSave, accountRegistrations)); return OperationResponse.ok(); } /** * 查询并返回冲突的employeeId * * @param vmsId vmsId * @param employeeIdList employeeId list * @return 有冲突的employeeId */ private List<String> getConflictEmployeeIds(String vmsId, List<String> employeeIdList) { // 传入的请求中,与数据库现有的数据会发生冲突的数据 return personRepository.getConflictEmployeeIds(vmsId, employeeIdList); } /** * 获取传入的数据中发生重复,且与数据库不冲突的的employeeId * * @param employeeIdList employeeId list * @param conflictEmployeeIdList 与数据库冲突的employeeId * @return 重复且不与数据库冲突的employeeId */ private List<String> getDuplicateEmployeeIds(List<String> employeeIdList, List<String> conflictEmployeeIdList) { // 统计每个employeeId出现的次数 Map<String, Long> countingMap = employeeIdList.stream() .collect(Collectors.groupingBy(id -> id, Collectors.counting())); // 返回重复出现,且与现有的数据库中数据不产生冲突的employeeId return countingMap.entrySet().stream() .filter(entry -> entry.getValue() > 1).map(Entry::getKey).filter(id -> !conflictEmployeeIdList.contains(id)) .collect(Collectors.toList()); } /** * 处理人员需要使用移动App的情况 * * @param personDO personDO * @param personId personId * @param accountRegistrations 记录需要注册app账号的人员信息 */ private void handleUsingApp(PersonDO personDO, String personId, List accountRegistrations) { // 如果人员允许使用app if (personDO.getUsingApp()) { // 发送邀请邮件 personEmailService.sendInvitationEmail(personDO); // 添加人员信息,后续批量发送给Identity Access,为人员添加账号 accountRegistrations.add( new PersonAppAccountDTO().setId(personId) .setFirstName(personDO.getFirstName()) .setLastName(personDO.getLastName()) .setEmployeeId(personDO.getEmployeeId()) .setEmail(personDO.getEmail())); } } /** * 批量异步保存关联信息,包括人员与组的关联信息、卡片信息 * * @param request PersonImportDTO * @param savedPersonIdList 已经保存成功的人员id list * @param cardsToSave 需要保存的卡片 * @param accountRegistrations 需要注册账号的人员账号信息 */ private void handleAsyncBatchDeal(PersonImportDTO request, List<String> savedPersonIdList, List<AccessCardDO> cardsToSave, List accountRegistrations) { // TODO 是否改为按固定批次数目发送,一次性发送数据量可能较大 String vmsId = request.getVmsId(); // 只保留合法的group id List<String> groupIdList = request.getGroupIdList(); groupIdList = groupRepository.filterValidIds(vmsId, groupIdList); // 批量保存人员与组的关联信息 personGroupMappingService.saveAllPersonToAllGroup(vmsId, savedPersonIdList, groupIdList); // 批量保存卡片信息 accessCardRepository.saveAll(cardsToSave); // 批量向Identity Access 发送需要注册app账号的人员 PersonAppAccountEventDTO personAppAccountRegisterEventDTO = new PersonAppAccountEventDTO(vmsId, accountRegistrations); personAppAccountEventPublisher.publishPersonRegisterAccountEvent(personAppAccountRegisterEventDTO); } /** * 更新某一行数据的导入情况,通过消息队列向api-gateway发送导入进度 * * @param processResponse 导入进度实体bean * @param rowNum excel行数 * @param request PersonImportDTO * @param importSuccess 该行数据是否导入成功 * @param personDO PersonDO * @param message 该行数据对应的导入反馈信息 */ private void publishProcess(OperationResponse<ImportPersonProcessDTO> processResponse, int rowNum, PersonImportDTO request, boolean importSuccess, PersonDO personDO, String message) { ImportPersonProcessDTO responseResult = processResponse.getResult(); List<FailedImportPersonDTO> failedList = responseResult.getFailedList(); // 反馈的行数需要加上模板表头的行数 rowNum += ExcelConstant.HEADER_ROW; failedList.add(new FailedImportPersonDTO(rowNum, personDO != null ? personDO.getEmployeeId() : null, personDO != null ? (personDO.getFirstName() + " " + personDO.getLastName()).trim() : null, message)); if (importSuccess) { responseResult.success(); } else { responseResult.fail(); } personImportProcessPublisher.publishPersonImportProcess(processResponse, request.getVmsId(), request.getUserId(), request.getUuid()); } }请为这个类生成使用Junit4和mockito的单元测试代码,要求覆盖所有分支(包括一个或|条件下的所有分支),代码尽量保持简洁。判断返回值可以参考这个:assertEquals(ResponseCode.GROUP_NOT_FOUND.getCode(), response.getErrorCode().intValue());判断是否成功参考assertTrue(response.isOk());。

大家在看

recommend-type

Delphi 在 DBGrid 里面显示分组统计的源代码

Delphi程序在 DBGrid 里面显示分类统计,也就是小计。用 ClientDataSet 的 TAggregateField 的方法,也可以用 DBGridEh。本程序演示了这两种方法。
recommend-type

硬件测试板级测试电源测试用例汇总华为

电源测试用例集.pdf
recommend-type

sony_imx335.zip

IMX335 驱动代码
recommend-type

信贷管理系统需求规格说明书

目录 第1章 1.1 背景概括 …………………………………………………… 5 1.2 可行性分析……………………………………………………… 7 (1) 经济可行性………………………………………………… 7 (2)操作可行性………………………………………………… 8 (3)技术可行性………………………………………………… (4)系统特点……………………………………………………… 8 第2章 需求分析………………………………………………………… 9 4.1 功能……………………………………………… 11 4.2 目标 4.3 业务流程设计……………………………………………… 11 (1) 存款管理……………………………………………………… 9 (2) 贷款管理…………………………………………………… 10 4.4 业务流程重组 4.5 数据流程图………………………………………………… 13 第3章 总体设计………………………………………………………… 11 第6章 详细设计………………………………………………………… 16 6.1 模块设计 ……………………………………………………… 16 6.2 代码设计……………………………………………………… 20 6.3 输入输出设计 ……………………………………………… 20 结束语 ……………………………………………………………………… 21 致谢 …………………………………………………………………………… 22 参考文献……………………………………………………………………… 23
recommend-type

stm32 蓝牙程序

stm32 开发板运行,通过手机蓝牙进行收发数据,需要的下载。

最新推荐

recommend-type

真题版2009年07月自学考试《计算机组成原理》历年真题.doc

真题版2009年07月自学考试《计算机组成原理》历年真题.doc
recommend-type

公司网络报告怎么做(15篇).docx

公司网络报告怎么做(15篇).docx
recommend-type

bitHEX-crx插件:提升cryptowat.ch与Binance平台易读性

根据给定文件信息,我们可以提炼出以下知识点: ### 标题知识点:bitHEX-crx插件 1. **插件名称解析**:该部分涉及一个名为“bitHEX”的插件,这里的“CRX”指的是Chrome扩展程序的文件格式。CRX文件是一种压缩包格式,用于在Google Chrome浏览器中安装扩展程序。这说明该插件是为Chrome浏览器设计的。 2. **插件功能定位**:标题直接表明了插件的功能特点,即调整和优化用户界面,特别是涉及到加密货币交易监控平台“cryptowat.ch”的界面颜色设置,以提升用户的视觉体验和阅读便利性。 ### 描述知识点:更改cryptowat.ch和Binance BASIC的颜色 1. **视觉优化目的**:“更改cryptowat.ch上的颜色”说明该插件的主要作用在于通过改变颜色配置,降低视觉上的饱和度,使得数字和线条的阅读变得更加轻松。 2. **平台适配性**:描述中提到的“至少现在是这样”,意味着插件在特定时间点上的功能可能仅限于调整“cryptowat.ch”的颜色设置。同时提到“和Binance BASIC以便于阅读”,表明该插件未来可能会扩展到对Binance等其他交易平台的颜色调整,提高用户在不同平台上的视觉体验。 3. **技术实现细节**:描述中还暗示了插件目前未能改变“交易平台画布上的饱和色”,表明该插件目前可能只影响了网页上的某些特定元素,而非全部。作者表示这一功能将在后续版本中实现。 ### 标签知识点:扩展程序 1. **软件分类**:标签“扩展程序”准确地揭示了bitHEX-crx的软件类型。扩展程序是可安装在浏览器上的小型软件包,用以增强或改变浏览器的默认功能。Chrome扩展程序特别流行于改变和自定义用户的网络浏览体验。 2. **使用环境**:该标签还表明该插件是专门为使用Google Chrome浏览器的用户设计的。Chrome浏览器作为全球使用最多的浏览器之一,有大量的用户基础,因此这类扩展程序的开发对提高用户体验具有重要意义。 ### 压缩包子文件的文件名称列表:bitHEX.crx 1. **文件格式说明**:从文件列表中我们得知该扩展程序的文件名是“bitHEX.crx”。CRX文件格式是专为Chrome浏览器扩展而设计,用户可以直接从Chrome网上应用店下载或通过开发者提供的URL安装CRX文件。 2. **安装方法**:用户获取该CRX文件后,可以通过简单的拖拽操作或在Chrome浏览器的“扩展程序”页面,启用“开发者模式”,然后点击“加载已解压的扩展程序”来安装该插件。 通过以上知识点的分析,我们可以得出,bitHEX-crx插件是一个针对加密货币交易监控平台用户界面的视觉优化Chrome扩展程序。它通过调整颜色设置来改善用户在使用特定金融交易平台时的视觉体验,目的是让数字和线条的显示更加清晰,以便用户能够舒适、高效地进行市场监控和交易操作。随着开发的推进,该插件未来可能会添加更多平台的颜色调整支持。
recommend-type

UnityML-Agents:相机使用与Python交互教程

### Unity ML-Agents:相机使用与Python交互教程 本文将深入探讨在Unity中为智能体添加相机、查看相机视角以及使用Python与Unity ML-Agents进行交互的详细过程。 #### 为智能体添加新相机 在Unity中,为智能体添加新相机可按以下步骤操作: 1. 使用层级面板,创建一个新相机作为“Balancing Ball”对象(智能体和球的父对象)的子对象。 2. 将新相机重命名为有意义的名称,如“Agent Camera”。 3. 调整新相机的位置,使其指向智能体和球。 4. 在层级面板中选择智能体,使用“Add Component”按钮添加“Camer
recommend-type

INA141仿真

INA141 是一款由 Texas Instruments(TI)生产的电流检测放大器,常用于高侧电流检测,具有较宽的共模电压范围和高精度的增益特性。对 INA141 芯片进行电路仿真时,通常可以使用主流的电路仿真工具如 **Pspice** 或 **Tina**,它们支持对电流检测电路的建模与分析。 ### 仿真方法 在进行 INA141 的电路仿真时,需构建一个完整的电流检测电路模型,包括输入端的采样电阻、负载、电源以及 INA141 的外围电路配置。以下是一个典型的仿真流程: 1. **搭建主电路模型**:将 INA141 的输入端连接至采样电阻两端,该电阻串联在电源与负载之间。
recommend-type

揭露不当行为:UT-Austin教授监控Chrome扩展

根据提供的文件信息,我们可以提炼出以下几点与“Professor Watch-crx插件”相关的知识点: 1. 插件功能定位: “Professor Watch-crx插件”是一款专为德克萨斯大学奥斯汀分校(UT-Austin)定制的Chrome扩展程序,旨在帮助学生和教师了解哪些教授曾经侵犯过学校性行为不当政策。该插件将相关信息整合到学校的课程目录中,以便用户在选课时能够掌握教师的相关背景信息。 2. 插件的作用和重要性: 插件提供了一种透明化的方式,使学生在选择课程和教授时能够做出知情的决定。在某些情况下,教授的不当行为可能会对学生的教育体验产生负面影响,因此该插件帮助用户避免潜在的风险。 3. 插件信息展示方式: 插件通过颜色编码来传达信息,具体如下: - 红色:表示UT的标题IX办公室已经确认某教授违反了性行为不当政策。 - 橙色:表示有主要媒体渠道报告了对某教授的不当行为指控,但截至2020年4月,UT的标题IX办公室尚未对此做出回应或提供相关信息。 4. 插件的数据来源和透明度: 插件中包含的信息来自于学生和教师的活动,并经过了一定的公开披露。该插件并非由德克萨斯大学创建或批准,它将用户引向一个外部网站(https://utmiscondone.wordpress.com/about-the-data/),以获取更多可公开获得的信息。 5. 插件的标签: 根据文件提供的信息,这款插件的标签是“扩展程序”(Extension),说明它属于Chrome浏览器的附加组件类别。 6. 插件文件名称: 插件的压缩包子文件名是“Professor_Watch.crx”,这是一个Chrome扩展程序的常用文件格式,用户可以通过Chrome浏览器直接下载并安装该插件。 7. 相关技术知识: - Chrome扩展程序开发涉及HTML、CSS和JavaScript等Web开发技术,以及Chrome扩展API。 - Chrome扩展程序可以利用各种浏览器提供的接口,如标签页、书签、历史记录、下载项和搜索等进行操作。 - 扩展程序的安装包为.crx文件,它是Chrome浏览器专用的打包格式,其中包含了扩展程序的所有资源和文件。 8. 法律与伦理考量: 使用此类插件可能会触及隐私权和诽谤等法律问题。开发者和用户需要注意不要侵犯他人名誉权,同时也要确保收集和发布的数据是准确和合法的。 9. 学术自由和言论自由的边界: 插件可能引发有关学术自由和言论自由边界的讨论。一方面,学生和教师需要在一个安全和支持的环境中学习和工作,另一方面,这也可能带来对教师声誉的不当影响。 通过这些知识点,我们可以看出“Professor Watch-crx插件”是一个旨在提高教育环境透明度和安全性的工具,它也引发了一系列关于个人隐私、信息准确性、法律义务和社会伦理的深入讨论。
recommend-type

UnityML-Agents合作学习与相机传感器应用指南

### Unity ML-Agents 合作学习与相机传感器应用指南 #### 合作学习环境搭建 在构建合作学习环境时,我们需要完成一系列的代码编写和配置工作。首先是环境管理器脚本部分,它的主要功能是重置定时器、旋转整个区域、为代理和方块分配随机位置和旋转,并将方块设置为活动状态。以下是相关代码: ```csharp item.BlockTransform.transform.SetPositionAndRotation(pos,rot); item.RigidBody.velocity = Vector3.zero; item.RigidBody.angularVelocity = Vec
recommend-type

edge下载linux

在Linux系统上下载和安装Microsoft Edge浏览器可以通过多种方式实现。以下是最常见的几种方法: ### 1. 从 Microsoft Edge Insider 网站下载安装包 Microsoft Edge Insider 网站提供了适用于 Linux 的 `.deb` 和 `.rpm` 安装包,用户可以直接访问该网站下载[^1]。这个方法的优势在于系统可以自动更新浏览器版本。 - 访问地址:[https://www.microsoftedgeinsider.com/zh-cn/download/](https://www.microsoftedgeinsider.com/zh
recommend-type

揭秘快速赚钱系统-免费使用CRX插件

根据给定的文件信息,可以提取以下知识点: 1. 插件类型:标题中提到的是一个名为 "Free Access To Money Making System" 的插件,且文件扩展名为 .crx,表明这是一个专为Google Chrome浏览器设计的扩展程序(也称为插件或扩展)。CRX文件是Chrome扩展程序的官方格式,允许用户通过Chrome Web Store或者直接通过下载安装到浏览器中。 2. 功能描述:从标题和描述可以看出,该插件可能被设计用于通过某种形式帮助用户赚钱。描述中提到“免费使用赚钱系统”,以及“比以往任何时候都更快地产生销售和佣金”,暗示了该插件可能涉及营销、广告、会员联盟或者其它形式的电子商务功能,用户可能可以通过推广产品或服务来赚取收益。 3. 语言信息:描述中提到插件的语言为English,即英语,说明该插件的用户界面和文档可能主要以英语呈现。 4. 安全性和合法性问题:在进行讨论时,需要指出网络上存在着许多声称能够帮助用户快速赚钱的程序,其中不少是诈骗或不合法的。关于这个特定插件,没有足够的信息来评价其合法性或安全性,因此用户在下载和使用此类插件时应保持警惕。合法赚钱系统通常要求用户付出真正的劳动或者提供有价值的服务,而不是依靠简单地安装软件来实现。 5. Chrome扩展程序的特点:Chrome扩展程序通常可以通过Chrome浏览器右上角的菜单访问,用户可以在"更多工具"下找到"扩展程序"选项来管理已安装的扩展。Chrome扩展允许用户对浏览器进行个性化配置,增强功能,如广告拦截、密码管理、视频下载等。扩展程序的来源可能包括Chrome Web Store或者直接从开发者提供的网站下载。 6. 扩展程序文件结构:文件名称 "Free_Access_To_Money_Making_System.crx" 反映了该扩展程序的文件结构。CRX文件通常为ZIP格式压缩包,用户可以通过更改文件扩展名从 .crx 到 .zip 来解压文件内容,以便查看其内部结构,包括插件的源代码、资源文件、插件的权限声明等。 7. 插件权限和隐私:在安装任何扩展程序时,都应该关注其权限请求。根据插件的功能,它可能要求访问用户的浏览数据、读取和修改浏览器历史记录、管理下载等。用户应仔细阅读并理解这些权限,以确保个人隐私和数据的安全。 综上,标题和描述中的知识点围绕一个名为 "Free Access To Money Making System" 的Chrome扩展程序展开,它可能具有帮助用户进行网络赚钱的特性。然而,用户在下载和使用该扩展程序之前,应该对其合法性和安全性进行充分的评估和审查。此外,Chrome扩展程序的管理和使用也是重要的知识点之一,包括对扩展程序文件结构和权限的理解,以及如何安全地安装和维护扩展程序。
recommend-type

高级模仿学习与课程学习指南

### 高级模仿学习与课程学习指南 在机器学习领域,高级模仿学习和课程学习是提升模型性能和效率的重要方法。下面将详细介绍如何使用GAIL(生成对抗模仿学习)进行训练,以及课程学习的概念和应用。 #### 1. 使用GAIL进行训练 ##### 1.1 准备工作 - **重命名场景**:将复制的场景重命名为“GAIL”或类似名称。 - **添加关键对象**: 1. 在项目层次结构中添加一个新的立方体。 2. 将这个立方体重命名为“key”。 ##### 1.2 修改代理代码 - **打开代码文件**:打开`Roller.cs`文件。 - **添加成员变量**:在类中添加以下