fix(新手任务): 增加新手任务成功页面,修复新手引导流程异常问题,调整新手任务权限,优化样式

This commit is contained in:
lan-yonghui 2023-04-06 11:14:43 +08:00 committed by 刘瑞斌
parent eaf42a313e
commit c799050fd5
14 changed files with 382 additions and 84 deletions

View File

@ -1,5 +1,4 @@
import {get, post} from "../plugins/request"
import {getCurrentUserId} from "../utils/token";
import {TASK_DATA} from "../utils/constants";
@ -15,11 +14,6 @@ export function saveTask(data) {
return post(`/novice/save/task`,{'dataOption': JSON.stringify(data)});
}
export function updateUserByResourceId(resourceId) {
let userId = getCurrentUserId();
return get(`/user/update/current-by-resource/${resourceId}`);
}
export function initTaskData(url){
getSideTask().then(res=>{
let taskData = TASK_DATA

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,6 +1,6 @@
@import '~shepherd.js/dist/css/shepherd.css';
.shepherd-has-title.shepherd-element {
width: 220px !important;
width: 220px;
}
.custom-width {
width: 320px !important;

View File

@ -62,16 +62,23 @@ export default {
localStorage.setItem('step', res.data[0].guideStep)
} else {
localStorage.setItem('guide','0')
localStorage.removeItem('step')
}
let microApps = JSON.parse(sessionStorage.getItem("micro_apps"));
if(localStorage.getItem("guide") === '0' && microApps && microApps['project']) {
localStorage.setItem("step", '1')
this.initStep()
let step = localStorage.getItem("step") ? localStorage.getItem("step") : "1"
localStorage.setItem("step", step)
if(step !== '3'){
if(this.$route.path.includes('/project/home')){
this.initStepAll()
}else{
this.initStep()
}
}
}
})
},
initStep() {
initStepAll() {
const _this = this
_this.$nextTick(() => {
const tour = _this.$shepherd({
@ -216,11 +223,84 @@ export default {
tour.start()
})
},
initStep() {
const _this = this
_this.$nextTick(() => {
const tour = _this.$shepherd({
useModalOverlay: true,
exitOnEsc: false,
keyboardNavigation: false,
defaultStepOptions: {
scrollTo: {
behavior: 'smooth',
block: 'center'
},
canClickTarget: false,
//
modalOverlayOpeningPadding: 0,
//
modalOverlayOpeningRadius: 4
}
})
tour.addSteps([
{
attachTo: {
element: document.querySelector('.shepherd-workspace'),
on: 'bottom-start'
},
buttons: [
{
action: function() {
_this.$refs.introduction.resVisible = localStorage.getItem("step") > 1
return _this.gotoCancel(this, true)
},
classes: 'close-btn',
text: _this.$t("shepherd.exit")
},
{
action: function() {
return _this.gotoNext(this, null, 2)
},
classes: 'shep-btn',
text: _this.$t("shepherd.next")
}
],
title: _this.$t("shepherd.step1.title"),
text: _this.$t("shepherd.step1.text")
},
{
attachTo: {
element: document.querySelector('.shepherd-menu'),
on: 'right'
},
buttons: [
{
action: function() {
_this.$refs.introduction.resVisible = localStorage.getItem("step") > 1
return _this.gotoCancel(this, true)
},
classes: 'close-btn',
text: _this.$t("shepherd.exit")
},
{
action: function() {
return _this.gotoNext(this, '/project/home', 3)
},
classes: 'shep-btn',
text: _this.$t("shepherd.next")
}
],
title: _this.$t("shepherd.step2.title"),
text: _this.$t("shepherd.step2.text")
},
])
tour.start()
})
},
skipOpen(path){
if(path){
this.$refs.sideMenu.skipOpen(path);
}
}
}
};

View File

@ -119,7 +119,6 @@ export default {
if(redirectUrl.includes("track")){
this.$emit("skipOpen", "/track/case/all")
this.$router.push("/track/case/all")
// this.$router.go(0);
}else{
this.$router.push({
path: '/track/case/all',

View File

@ -17,6 +17,7 @@
import MsSiteTask from "../../components/sidemenu/components/SiteTask";
import {getSideTask} from "../../api/novice";
import {TASK_DATA} from "../../utils/constants";
import {hasLicense, hasPermissions} from "../../utils/permission";
export default {
@ -46,7 +47,8 @@ export default {
let num = 0
let total = 0
this.taskData.forEach(item =>{
if(!(microApp && microApp[item.name])){
if(!(microApp && microApp[item.name]) || (item.name === 'ui' && !hasLicense()) ||
!hasPermissions(...item.permission)){
item.status = -1
total++
} else {
@ -95,7 +97,7 @@ export default {
.parentBox .contentsBox div {
transition: all 1s;
position: fixed;
right: 0;
right: 16px;
width: 27px;
border-radius: 50px;
background-color: #783787;
@ -113,7 +115,7 @@ export default {
margin-left: 10px;
}
.parentBox .contentsBox div:nth-child(1) {
bottom: 100px;
bottom: 125px;
}
.parentBox .contentsBox div:hover {
right: 0;

View File

@ -1,13 +1,52 @@
<template>
<div>
<div class="csat-popup" v-if="cardVisible">
<div class="csat-popup over" v-if="cardVisible && taskInfo.length === completeNum">
<el-card class="box-card">
<div slot="header" class="clearfix over-header">
<span style="float: right; padding: 5px 0;" class="moon" @click="open()">
<font-awesome-icon :icon="['fa', 'times']" class="icon"/>
</span>
<img src="/assets/guide/talent-requirements.png" class="image" alt="MS">
</div>
<div class="text" :style="language === 'en-US' ? 'text-align: center;height: 200px' :
'text-align: center;height: 165px'">
<span class="title" >
<img src="../../../assets/guide/flower.png" alt="MS">
{{ $t("side_task.over.title") }}
</span>
<p class="text">
<img v-for="num in completeNum" src="../../../assets/guide/moon-dark.png" class="over-moon" alt="MS" :key="num
+ 'd'">
{{ $t("side_task.over.subtitle") }}
</p>
<p class="text">{{ $t("side_task.over.desc") }}</p>
<p class="desc">
<a href="https://blog.fit2cloud.com/categories/metersphere" target="_blank">
{{ $t("side_task.over.blog_url") }}
</a>
</p>
<p class="desc">
<a href="https://space.bilibili.com/510493147/channel/collectiondetail?sid=40439" target="_blank">
{{ $t("side_task.over.live_url") }}
</a>
</p>
</div>
<div class="footer">
<el-button style="float: right; padding: 15px 0;color:#8C8C8C" type="text" @click="skip()">
{{$t('side_task.skip')}}
</el-button>
</div>
</el-card>
</div>
<div class="csat-popup" v-else-if="cardVisible && taskInfo.length > 0">
<template v-for="(item,index) in taskInfo" >
<el-card :key="item.id" v-if="(index + 1) === taskIndex" class="box-card" >
<el-card :key="item.id" v-if="(index + 1) === taskIndex && checkPermissions(item.permission)"
class="box-card" >
<div slot="header" class="clearfix">
<span class="text-header">{{$t(item.title)}}</span>
<el-button style="float: right; padding: 5px 0;" class="moon" type="text" @click="open()">
<font-awesome-icon :icon="['fa', 'chevron-down']" class="icon"/>
</el-button>
<span class="text-header" v-html="$t(item.title)" />
<el-button style="float: right; padding: 3px 0;margin-right: 25px" type="text" >
<img v-for="num in completeNum" src="../../../assets/guide/moon-dark.png"
class="moon" alt="MS" :key="num + 'd'">
@ -16,11 +55,13 @@
<img v-for="num in incompleteNum" src="../../../assets/guide/moon.png"
class="moon" alt="MS" :key="num">
</el-button>
<el-progress :percentage="item.percentage" color="#783787" class="progress-card"></el-progress>
<el-progress :percentage="item.percentage" color="#783787"
:class="language === 'en-US' ? 'progress-card-en' : 'progress-card-zh'"></el-progress>
</div>
<div style="height: 220px">
<template v-for="(val,i) in item.taskData">
<div class="text item" v-permission="val.permission" :key="i">
<div class="text item" v-if="checkPermissions(val.permission)" :key="i">
<p v-if="val.status === 1">
<font-awesome-icon :icon="['far', 'check-circle']" style="color:#783887" />
<label> {{$t(val.name)}}</label>
@ -40,13 +81,14 @@
<el-button v-if="taskIndex > 1" style="float: right;margin-left: 10px; padding: 15px 0" type="text" @click="prev()">
{{$t('side_task.prev')}}
</el-button>
<el-button style="float: right; padding: 15px 0;color:#8C8C8C" type="text" @click="skip()">
<el-button style="float: left; padding: 15px 0;color:#8C8C8C" type="text" @click="skip()">
{{$t('side_task.skip')}}
</el-button>
</div>
</el-card>
</template>
</div>
<div class="csat-popup-gif" v-if="gifVisible">
<el-card class="box-card">
<div slot="header" class="clearfix">
@ -54,17 +96,18 @@
<font-awesome-icon :icon="['fa', 'times']" class="icon"/>
</span>
</div>
<div class="text" style="text-align: center;height: 210px">
<div class="text" :style="language === 'en-US' ? 'text-align: center;height: 230px' :
'text-align: center;height: 216px'">
<el-image
style="width: 340px;border-radius: 4px;"
style="width: 340px;border-radius: 8px;"
:src="gifData.url"
:preview-src-list="[gifData.url]" lazy>
<div slot="placeholder" class="image-slot">
加载中<span class="dot">...</span>
loading<span class="dot">...</span>
</div>
</el-image>
</div>
<div class="gif-footer">
<div :class="language === 'en-US' ? 'gif-footer-en' : 'gif-footer'">
<el-button type="primary" round size="small" class="is-plain" @click="gotoPath(gifData.path)">
{{$t(gifData.name)}}
</el-button>
@ -75,9 +118,7 @@
</template>
<script>
import {hasLicense} from "../../../utils/permission";
import {TASK_DATA, TASK_MODULE} from "../../../utils/constants";
import {getSideTask} from "../../../api/novice";
import {hasPermissions} from "../../../utils/permission";
export default {
name: "SiteTask",
@ -95,7 +136,8 @@ export default {
completeNum: 0,
ongoingNum: 0,
incompleteNum: 0,
totalNum:0,
totalNum: 0,
language: localStorage.getItem('language'),
status: this.$route.query.status
}
},
@ -104,8 +146,6 @@ export default {
},
created() {
console.log("this.status")
console.log(this.status)
if(this.status){
this.skipOpen("/track/case/all")
}
@ -116,7 +156,7 @@ export default {
let completeNum = 0
let ongoingNum = 0
this.taskInfo = []
// status -1 0 1 2
// status -1 访 0 1 2
this.taskData.forEach(item=>{
if(item.status === 1){
completeNum++;
@ -177,17 +217,30 @@ export default {
})
})
}
},
checkPermissions(permission) {
return hasPermissions(...permission);
}
}
}
</script>
<style scoped>
.title {
font-size: 24px;
font-weight: 500;
}
.text {
font-size: 16px;
font-weight: 300;
}
.desc {
color:#783887;
text-align: left;
margin: 3px 6px;
font-size: 12px;
font-weight: 300;
}
.item {
margin-bottom: 10px;
@ -223,7 +276,12 @@ export default {
color:#783887;
}
.progress-card {
.progress-card-en {
margin-top: 10px;
margin-right: 20px;
}
.progress-card-zh {
margin-top: 10px;
margin-right: 40px;
}
@ -239,6 +297,12 @@ export default {
text-align: center;
}
.gif-footer-en {
width: 100%;
margin: 10px 0 44px;
text-align: center;
}
.clearfix:before,
.clearfix:after {
display: table;
@ -255,7 +319,7 @@ export default {
.csat-popup {
position: fixed;
right: 16px;
bottom: 160px;
bottom: 170px;
width: 400px;
border-radius: 8px;
overflow: hidden;
@ -271,7 +335,7 @@ export default {
.csat-popup-gif {
position: fixed;
right: 426px;
bottom: 160px;
bottom: 170px;
width: 400px;
border-radius: 8px;
overflow: hidden;
@ -293,10 +357,27 @@ export default {
height: 20px;
}
.circle {
.over-moon {
vertical-align: bottom;
width: 12px;
height: 12px;
margin-right: 5px;
}
.image {
width: 160px;
height: 120px;
}
.over-header {
text-align: center;
}
::v-deep .over .el-card {
border-radius: 8px;
background-image: linear-gradient(to bottom, #f4f4f4 44%, #FFF 0);
}
::v-deep .el-card__body {
padding: 0 10px;
}
::v-deep .csat-popup .el-card__header {
@ -304,6 +385,11 @@ export default {
padding: 20px 24px 10px 24px;
}
::v-deep .over .el-card__header {
border-bottom: none;
padding: 20px 24px 0px 24px;
}
::v-deep .csat-popup-gif .el-card__header {
border-bottom: none;
padding: 20px 20px 10px 24px;

View File

@ -3575,8 +3575,8 @@ const message = {
button: 'Next: UI Test'
},
ui: {
title: 'Portable UI element library and instruction set',
desc: '<span>Arrange scenario cases based on reusable element libraries and instructions;</span><br> combine your commonly used test steps into new instructions, <br> <span> which can be flexibly called in automation scenarios. </span>',
title: 'Portable UI element library and command set',
desc: '<span>Arrange scenario cases based on reusable element library and commands;</span><br> combine your commonly used test steps into new command, <br> <span> which can be flexibly called in automation scenarios. </span>',
button: 'Next: Performance Test'
},
performance: {
@ -3588,7 +3588,7 @@ const message = {
},
side_task: {
test_tracking: {
title: "Challenging Test Track",
title: "<span>Challenging</span><br><span>Test Track</span>",
task_1: "Join a project",
task_2: "Create a functional test case",
task_3: "Create a review plan",
@ -3598,36 +3598,43 @@ const message = {
task_7: "Add ralated issue to test case",
},
api_test: {
title: "Challenging API Test",
title: "<span>Challenging</span><br><span>API Test</span>",
task_1: "Create an API definition",
task_2: "Import local API definition or API cases",
task_3: "Execute an API testing",
task_4: "Create a new test case based on API testing",
task_5: "Share API documents",
task_6: "Create an automation scenario case",
task_7: "Execute automated API testing with scheduled task ",
task_7: "Execute automated API testing with scheduled task",
},
performance_test: {
title: "Challenging Performance Test",
title: "<span>Challenging</span><br><span>Performance Test</span>",
task_1: "Convert API scenario case into performance testing",
task_2: "Share performance testing report",
},
project_setting: {
title: "Challenging Project Settings",
task_1: "create a new project",
title: "<span>Challenging</span><br><span>Project Settings</span>",
task_1: "Create a new project",
task_2: "Add a project member",
task_3: "Create a project environment",
},
ui_test: {
title: "Challenging UI Test",
title: "<span>Challenging</span><br><span>UI Test</span>",
task_1: "Create an element",
task_2: "Create an automated UI scenario case",
task_3: "Execute an automated UI scenario case",
task_2: "Create an automated UI scenario case",
task_3: "Execute an automated UI scenario case",
},
next: "Next",
prev: "Previous",
skip: "Skip",
novice_task: "Novice Task"
novice_task: "Novice Task",
over: {
title: "Congratulations!",
subtitle: "You have completed all the novice journey, full of energy",
desc: "If you want to continue to learn about advanced tutorials, please follow our technical blog and live channel",
blog_url: "Technical Blog",
live_url: "Live Channel"
}
}
};

View File

@ -3498,7 +3498,14 @@ const message = {
next: "下一章",
prev: "上一章",
skip: "跳过",
novice_task: "新手旅程"
novice_task: "新手旅程",
over: {
title: "恭喜通关!",
subtitle: "您已完成全部新手旅程 能量满载~",
desc: "想继续了解进阶教程,请关注我们的技术博客和直播",
blog_url: "博客地址",
live_url: "直播间地址"
}
}
};

View File

@ -3498,7 +3498,14 @@ const message = {
next: "下一章",
prev: "上一章",
skip: "跳過",
novice_task: "新手旅程"
novice_task: "新手旅程",
over: {
title: "恭喜通關!",
subtitle: "您已完成全部新手旅程 能量滿載~",
desc: "想繼續了解進階教程,請關注我們的技術博客和直播",
blog_url: "博客地址",
live_url: "直播間地址"
}
}
};

View File

@ -267,23 +267,24 @@ export const SECOND_LEVEL_ROUTE_PERMISSION_MAP = {
export const TASK_PATH = [
"/test/case/add",
"/test/case/review/save",
"/test/case/review/comment/save",
"/test/case/comment/save",
"/test/plan/add",
"/test/plan/relevance",
"/issues/add",
"issues/add",
"test/case/issues/relate",
"/api/definition/create",
"/api/definition/run/debug",
"/api/testcase/create",
"/share/info/generateApiDocumentShareInfo",
"/share/generate/api/document",
"/api/definition/import",
"/api/automation/create",
"/api/automation/schedule/update",
"/api/automation/schedule/create",
"/performance/save",
"/share/info/generateShareInfoWithExpired",
"/share/generate/expired",
"/project/add",
"/project/member/add",
"/user/project/member/add",
"/api/environment/add",
"/setting/user/project/member/add",
"/environment/add",
"/ui/element/add",
"/ui/automation/create",
"/ui/automation/run/debug",
@ -295,14 +296,15 @@ export const TASK_DATA = [
name: "track",
title: "side_task.test_tracking.title",
percentage: 14,
permission: ['PROJECT_MANAGER:READ', 'WORKSPACE_PROJECT_MANAGER:READ','PROJECT_TRACK_CASE:READ+CREATE','PROJECT_TRACK_REVIEW:READ+CREATE','PROJECT_TRACK_REVIEW:READ+COMMENT','PROJECT_TRACK_PLAN:READ+CREATE','PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL','PROJECT_TRACK_ISSUE:READ+CREATE','PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'],
taskData: [
{ id: 1, name: "side_task.test_tracking.task_1", status: 1, permission: ['PROJECT_MANAGER:READ', 'WORKSPACE_PROJECT_MANAGER:READ'], api: [''], path: '/setting/project/:type', url: "" },
{ id: 2, name: "side_task.test_tracking.task_2", status: 0, permission: ['PROJECT_TRACK_CASE:READ+CREATE'], api: ["/test/case/add"], path: '/track/case/all', url: "/assets/guide/track/task-2.gif" },
{ id: 3, name: "side_task.test_tracking.task_3", status: 0, permission: ['PROJECT_TRACK_REVIEW:READ+CREATE'], api: ["/test/case/review/save"], path: '/track/review/all', url: "/assets/guide/track/task-3.gif" },
{ id: 4, name: "side_task.test_tracking.task_4", status: 0, permission: ['PROJECT_TRACK_REVIEW:READ+COMMENT'], api: ["/test/case/review/comment/save"], path: '/track/review/all', url: "/assets/guide/track/task-4.gif" },
{ id: 4, name: "side_task.test_tracking.task_4", status: 0, permission: ['PROJECT_TRACK_REVIEW:READ+COMMENT'], api: ["/test/case/comment/save"], path: '/track/review/all', url: "/assets/guide/track/task-4.gif" },
{ id: 5, name: "side_task.test_tracking.task_5", status: 0, permission: ['PROJECT_TRACK_PLAN:READ+CREATE'], api: ["/test/plan/add"], path: '/track/plan/all', url: "/assets/guide/track/task-5.gif" },
{ id: 6, name: "side_task.test_tracking.task_6", status: 0, permission: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL'], api: ["/test/plan/relevance"], path: '/track/plan/all', url: "/assets/guide/track/task-6.gif" },
{ id: 7, name: "side_task.test_tracking.task_7", status: 0, permission: ['PROJECT_TRACK_ISSUE:READ+CREATE'], api: ["/issues/add"], path: '/track/issue', url: "/assets/guide/track/task-7.gif" },
{ id: 7, name: "side_task.test_tracking.task_7", status: 0, permission: ['PROJECT_TRACK_ISSUE:READ+CREATE','PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'], api: ["issues/add","test/case/issues/relate"], path: '/track/issue', url: "/assets/guide/track/task-7.gif" },
],
rate: 1,
status: 0
@ -312,14 +314,15 @@ export const TASK_DATA = [
name: "api",
title: 'side_task.api_test.title',
percentage: 0,
permission: ['PROJECT_API_DEFINITION:READ+CREATE_API','PROJECT_API_DEFINITION:READ+IMPORT_API','PROJECT_API_DEFINITION:READ+DEBUG','PROJECT_API_DEFINITION:READ+CREATE_CASE','PROJECT_API_DEFINITION:READ','PROJECT_API_SCENARIO:READ+CREATE','PROJECT_API_SCENARIO:READ+SCHEDULE'],
taskData: [
{id: 1, name: "side_task.api_test.task_1", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+CREATE_API'], api: ["/api/definition/create"], url: "/assets/guide/api/task-1.gif" },
{id: 2, name: "side_task.api_test.task_2", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+IMPORT_API'], api: ["/api/definition/import"], url: "/assets/guide/api/task-2.gif" },
{id: 3, name: "side_task.api_test.task_3", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+DEBUG'], api: ["/api/definition/run/debug"], url: "/assets/guide/api/task-3.gif" },
{id: 4, name: "side_task.api_test.task_4", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+CREATE_CASE'], api: ["/api/testcase/create"], url: "/assets/guide/api/task-4.gif" },
{id: 5, name: "side_task.api_test.task_5", status: 0, path: '/api/automation', permission: ['PROJECT_API_DEFINITION:READ'], api: ["/share/info/generateApiDocumentShareInfo"], url: "/assets/guide/api/task-5.gif" },
{id: 5, name: "side_task.api_test.task_5", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ'], api: ["/share/generate/api/document"], url: "/assets/guide/api/task-5.gif" },
{id: 6, name: "side_task.api_test.task_6", status: 0, path: '/api/automation', permission: ['PROJECT_API_SCENARIO:READ+CREATE'], api: ["/api/automation/create"], url: "/assets/guide/api/task-6.gif" },
{id: 7, name: "side_task.api_test.task_7", status: 0, path: '/api/automation', permission: ['PROJECT_API_SCENARIO:READ+SCHEDULE'], api: ["/api/automation/schedule/update"], url: "/assets/guide/api/task-7.gif" },
{id: 7, name: "side_task.api_test.task_7", status: 0, path: '/api/automation', permission: ['PROJECT_API_SCENARIO:READ+SCHEDULE'], api: ["/api/automation/schedule/create"], url: "/assets/guide/api/task-7.gif" },
],
rate: 0,
status: 0
@ -329,9 +332,10 @@ export const TASK_DATA = [
name: "performance",
title: 'side_task.performance_test.title',
percentage: 0,
permission: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE',"PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH",'PROJECT_PERFORMANCE_REPORT:READ'],
taskData: [
{id: 1, name: 'side_task.performance_test.task_1', status: 0, path: '/performance/test/all', permission: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE',"PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH"], api: ["/performance/save"], url: "/assets/guide/performance/task-1.gif" },
{id: 2, name: 'side_task.performance_test.task_2', status: 0, path: '/performance/report/all', permission: ['PROJECT_PERFORMANCE_REPORT:READ'], api: ["/share/info/generateShareInfoWithExpired"], url: "/assets/guide/performance/task-2.gif" },
{id: 2, name: 'side_task.performance_test.task_2', status: 0, path: '/performance/report/all', permission: ['PROJECT_PERFORMANCE_REPORT:READ'], api: ["/share/generate/expired"], url: "/assets/guide/performance/task-2.gif" },
],
rate: 0,
status: 0
@ -341,10 +345,11 @@ export const TASK_DATA = [
name: "project",
title: 'side_task.project_setting.title',
percentage: 0,
permission: ['WORKSPACE_PROJECT_MANAGER:READ+CREATE','PROJECT_USER:READ+CREATE','PROJECT_ENVIRONMENT:READ+CREATE'],
taskData: [
{id: 1, name: 'side_task.project_setting.task_1', status: 0, permission: ['WORKSPACE_PROJECT_MANAGER:READ+CREATE'], api: ["/project/add"], path: '/setting/project/:type', url: "/assets/guide/project/task-1.gif" },
{id: 2, name: 'side_task.project_setting.task_2', status: 0, permission: ['PROJECT_USER:READ+CREATE'], api: ["/project/member/add","/user/project/member/add"], path: '/project/member', url: "/assets/guide/project/task-2.gif" },
{id: 3, name: 'side_task.project_setting.task_3', status: 0, permission: ['PROJECT_ENVIRONMENT:READ+CREATE'], api: ["/api/environment/add"], path: '/project/env', url: "/assets/guide/project/task-3.gif" },
{id: 2, name: 'side_task.project_setting.task_2', status: 0, permission: ['PROJECT_USER:READ+CREATE'], api: ["/project/member/add","/setting/user/project/member/add"], path: '/project/member', url: "/assets/guide/project/task-2.gif" },
{id: 3, name: 'side_task.project_setting.task_3', status: 0, permission: ['PROJECT_ENVIRONMENT:READ+CREATE'], api: ["/environment/add"], path: '/project/env', url: "/assets/guide/project/task-3.gif" },
],
rate: 0,
status: 0
@ -354,10 +359,11 @@ export const TASK_DATA = [
name: "ui",
title: 'side_task.ui_test.title',
percentage: 0,
permission: ['PROJECT_UI_ELEMENT:READ+CREATE','PROJECT_UI_SCENARIO:READ+CREATE','PROJECT_UI_SCENARIO:READ+RUN','PROJECT_UI_SCENARIO:READ+DEBUG'],
taskData: [
{id: 1, name: 'side_task.ui_test.task_1', status: 0, permission: ['PROJECT_UI_ELEMENT:READ+CREATE'], api: ["/ui/element/add"], path: '/ui/element', url: "/assets/guide/ui/task-1.gif" },
{id: 2, name: 'side_task.ui_test.task_2', status: 0, permission: ['PROJECT_UI_ELEMENT:READ+CREATE'], api: ["/ui/automation/create"], path: '/ui/automation', url: "/assets/guide/ui/task-2.gif" },
{id: 2, name: 'side_task.ui_test.task_3', status: 0, permission: ['PROJECT_UI_SCENARIO:READ+RUN'], api: ["/ui/automation/run/debug"], path: '/ui/report', url: "/assets/guide/ui/task-3.gif" },
{id: 2, name: 'side_task.ui_test.task_2', status: 0, permission: ['PROJECT_UI_SCENARIO:READ+CREATE'], api: ["/ui/automation/create"], path: '/ui/automation', url: "/assets/guide/ui/task-2.gif" },
{id: 2, name: 'side_task.ui_test.task_3', status: 0, permission: ['PROJECT_UI_SCENARIO:READ+RUN','PROJECT_UI_SCENARIO:READ+DEBUG'], api: ["/ui/automation/run/debug"], path: '/ui/automation', url: "/assets/guide/ui/task-3.gif" },
],
rate: 0,
status: 0

View File

@ -9,7 +9,6 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
@ -53,7 +52,6 @@ public class NoviceService {
long systemTime = System.currentTimeMillis();
if(noviceInfo != null && noviceInfo.size() > 0){
NoviceStatistics noviceStatistics = noviceInfo.get(0);
noviceStatistics.setGuideStep(stepRequest.getGuideStep());
noviceStatistics.setGuideNum(noviceStatistics.getGuideNum() + 1);
noviceStatistics.setUpdateTime(systemTime);
NoviceStatisticsExample example = new NoviceStatisticsExample();
@ -65,7 +63,7 @@ public class NoviceService {
noviceStatistics.setId(UUID.randomUUID().toString());
noviceStatistics.setUserId(SessionUtils.getUserId());
noviceStatistics.setGuideStep(stepRequest.getGuideStep());
noviceStatistics.setGuideStep(1);
noviceStatistics.setGuideNum(1);
noviceStatistics.setCreateTime(systemTime);
noviceStatistics.setUpdateTime(systemTime);

View File

@ -136,6 +136,7 @@
</el-row>
</el-card>
<ms-introduction ref="introduction"/>
<edit-project ref="editProject" :is-show-app="isShowApp"/>
</ms-main-container>
</ms-container>
@ -149,10 +150,11 @@ import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {hasPermission} from "metersphere-frontend/src/utils/permission";
import {getProject, getProjectMemberSize} from "../../api/project";
import EditProject from "./EditProject";
import MsIntroduction from "metersphere-frontend/src/components/guide/components/Introduction";
export default {
name: "ProjectHome",
components: {MsMainContainer, MsContainer, EditProject},
components: {MsMainContainer, MsContainer, EditProject, MsIntroduction},
data() {
return {
project: {
@ -166,6 +168,12 @@ export default {
isShowApp: false
}
},
mounted() {
this.$refs.introduction.resVisible = false
if(localStorage.getItem("step") === '3') {
this.initStep()
}
},
methods: {
click(str, permissions) {
for (let permission of permissions) {
@ -178,7 +186,102 @@ export default {
},
edit() {
this.$refs.editProject.edit(this.project);
}
},
initStep() {
const _this = this
_this.$nextTick(() => {
const tour = _this.$shepherd({
useModalOverlay: true,
exitOnEsc: false,
keyboardNavigation: false,
defaultStepOptions: {
scrollTo: {
behavior: 'smooth',
block: 'center'
},
canClickTarget: false,
//
modalOverlayOpeningPadding: 0,
//
modalOverlayOpeningRadius: 4
}
})
tour.addSteps([
{
attachTo: {
element: document.querySelector('.shepherd-project'),
on: 'bottom-end'
},
classes: "custom-width",
buttons: [
{
action: function() {
_this.$refs.introduction.resVisible = true
return _this.gotoCancel(this, true)
},
classes: 'close-btn',
text: _this.$t("shepherd.exit")
},
{
action: function() {
return _this.gotoNext(this, null, 4)
},
classes: 'shep-btn',
text: _this.$t("shepherd.next")
}
],
title: _this.$t("shepherd.step3.title"),
text: _this.$t("shepherd.step3.text")
},
{
attachTo: {
element: document.querySelector('.shepherd-project-menu'),
on: 'bottom-start'
},
buttons: [
{
action: function() {
_this.$refs.introduction.resVisible = true
return _this.gotoCancel(this, true)
},
classes: 'close-btn',
text: _this.$t("shepherd.exit")
},
{
action: function() {
return _this.gotoNext(this, null, 5)
},
classes: 'shep-btn',
text: _this.$t("shepherd.next")
}
],
title: _this.$t("shepherd.step4.title"),
text: _this.$t("shepherd.step4.text")
},
{
arrow:true,
modalOverlayOpeningPadding: 8,
attachTo: {
element: document.querySelector('.shepherd-project-name'),
on: 'right'
},
buttons: [
{
action: function() {
_this.$refs.introduction.resVisible = true
return _this.gotoCancel(this, false)
},
classes: 'close-btn',
text: _this.$t("shepherd.know")
}
],
title: _this.$t("shepherd.step5.title"),
text: _this.$t("shepherd.step5.text")
}
])
tour.start()
})
},
},
computed: {
projectId() {
@ -195,6 +298,7 @@ export default {
.then(res => {
this.memberSize = res.data;
})
}
}
</script>

View File

@ -1,10 +1,18 @@
CREATE TABLE `novice_statistics` (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户id',
`guide_step` tinyint NOT NULL DEFAULT '0' COMMENT '新手引导完成的步骤',
`guide_num` int NOT NULL DEFAULT '1' COMMENT '新手引导的次数',
`data_option` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'data option (JSON format)',
`create_time` bigint DEFAULT NULL,
`update_time` bigint DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
SET SESSION innodb_lock_wait_timeout = 7200;
CREATE TABLE `novice_statistics`
(
`id` varchar(50) NOT NULL COMMENT 'ID',
`user_id` varchar(64) NOT NULL COMMENT '用户id',
`guide_step` tinyint NOT NULL DEFAULT '0' COMMENT '新手引导完成的步骤',
`guide_num` int(10) NOT NULL DEFAULT '1' COMMENT '新手引导的次数',
`data_option` longtext DEFAULT NULL COMMENT 'data option (JSON format)',
`create_time` bigint(13) NOT NULL COMMENT 'Create timestamp',
`update_time` bigint(13) NOT NULL COMMENT 'Update timestamp',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci;
SET SESSION innodb_lock_wait_timeout = DEFAULT;