update
This commit is contained in:
parent
327b8c5b35
commit
95c845c628
@ -1,3 +1,4 @@
|
||||
<!-- eslint-disable vue/valid-v-model -->
|
||||
<template>
|
||||
<div class="header-container">
|
||||
<div class="header-content">
|
||||
@ -47,18 +48,19 @@
|
||||
<svg-icon icon="post" class-name="icon" />
|
||||
{{ $t('Post') }}
|
||||
</button>
|
||||
<div class="form-check form-switch header-switch-container">
|
||||
<div class="form-check form-switch header-switch-container" @click="gotoProfile">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
:checked="userProfile?.account?.provider?.accepting_request"
|
||||
id="personal-earning-now-checkbox"
|
||||
disabled
|
||||
/>
|
||||
<label class="form-check-label" for="personal-earning-now-checkbox">
|
||||
<span>{{ $t('Providing service') }}</span>
|
||||
</label>
|
||||
<div class="header-switch-desc">
|
||||
<div v-if="!userProfile?.account?.provider?.accepting_request" class="header-switch-desc">
|
||||
{{ $t('Please go to profile page to add money receiving method') }}
|
||||
</div>
|
||||
</div>
|
||||
@ -70,7 +72,10 @@
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
id="accountButton"
|
||||
src="@/assets/profile.png"
|
||||
:src="userProfile?.account?.basic?.photo?.base64
|
||||
? userProfile?.account?.basic?.photo?.base64
|
||||
: profileUrl
|
||||
"
|
||||
/>
|
||||
<ul class="dropdown-menu" aria-labelledby="accountButton">
|
||||
<li>
|
||||
@ -95,6 +100,8 @@
|
||||
<script>
|
||||
import { UserAuthApi } from '@/utils/backend/index'
|
||||
import LaguageSwitch from '@/components/LaguageSwitch.vue'
|
||||
import { UserProfileApi } from '@/utils/index'
|
||||
import profileUrl from '@/assets/profile.png'
|
||||
|
||||
export default {
|
||||
name: 'HeaderGuest',
|
||||
@ -108,6 +115,9 @@ export default {
|
||||
},
|
||||
unreadRequest() {
|
||||
return this.$store.getters['basic/unreadRequest']
|
||||
},
|
||||
userProfile() {
|
||||
return this.$store.getters['userProfile/profile']
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -115,9 +125,11 @@ export default {
|
||||
this.userIdentityNote = this.userIdentityNote.slice(0, 5) + '...'
|
||||
}
|
||||
this.$store.dispatch('basic/initWebsocket', this.mnx_getUserAuthToken())
|
||||
this.fetchProfile()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
profileUrl,
|
||||
userIdentityNote: this.mnx_getUserIdentity(),
|
||||
activePath: this.$route.meta.activePath
|
||||
}
|
||||
@ -157,7 +169,16 @@ export default {
|
||||
this.mnx_logoutRole()
|
||||
this.mnx_navToFrontDoor()
|
||||
},
|
||||
|
||||
fetchProfile() {
|
||||
UserProfileApi.fetchUserProfile()
|
||||
.then((response) => {
|
||||
this.$store.dispatch('userProfile/updateProfile', response.data || {})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error)
|
||||
this.mnx_backendErrorHandler(error)
|
||||
})
|
||||
},
|
||||
signout() {
|
||||
UserAuthApi.signout(this.mnx_getUserIdentity(), this.mnx_getUserAuthToken())
|
||||
.then((response) => {
|
||||
@ -289,6 +310,7 @@ export default {
|
||||
|
||||
.header-switch-container {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
.header-switch-desc {
|
||||
position: absolute;
|
||||
|
||||
@ -208,4 +208,5 @@ export default {
|
||||
'Some update in your request': 'Some update in your request',
|
||||
'min(s)': 'min(s)',
|
||||
'line(s)': 'line(s)',
|
||||
'Issues management': 'Issues management'
|
||||
}
|
||||
|
||||
@ -190,4 +190,5 @@ export default {
|
||||
'Some update in your request': 'Some update in your request',
|
||||
'min(s)': '响应时间',
|
||||
'line(s)': '每周产出代码',
|
||||
'Issues management': '问题管理'
|
||||
}
|
||||
|
||||
@ -39,7 +39,9 @@ export default {
|
||||
mnx_navToNewUserSetFlid(suggested_flid) {
|
||||
this.$router.push('/new-user-set-flid/' + suggested_flid)
|
||||
},
|
||||
|
||||
mnx_navToProjectIssue(project_id) {
|
||||
this.$router.push(`/project-issue/${project_id}`)
|
||||
},
|
||||
mnx_navToRequestIssue(loadFrom) {
|
||||
this.$router.push('/request-issue/' + loadFrom)
|
||||
},
|
||||
|
||||
@ -592,18 +592,12 @@ export default {
|
||||
|
||||
methods: {
|
||||
fetchProfile() {
|
||||
UserProfileApi.fetchUserProfile()
|
||||
.then((response) => {
|
||||
this.userProfile = response.data
|
||||
this.userProfile = this.$store.getters['userProfile/profile']
|
||||
this.updateLocalIdentityData()
|
||||
this.updateLocalEmailData()
|
||||
this.updateLocalMobileData()
|
||||
this.updateLocalPersonalData()
|
||||
this.updateLocalPaymentData()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
})
|
||||
},
|
||||
updateLocalIdentityData() {
|
||||
this.identityOperation.first_name = this.userProfile.account.basic.first_name
|
||||
@ -611,6 +605,9 @@ export default {
|
||||
this.identityOperation.photo.base64 = this.userProfile.account.basic.photo.base64
|
||||
this.identityOperation.photo.filename = this.userProfile.account.basic.photo.filename
|
||||
},
|
||||
updateLocalProfileData() {
|
||||
this.$store.dispatch('userProfile/updateProfile', this.userProfile || {})
|
||||
},
|
||||
//User identity operation
|
||||
edittingFirstname($event) {
|
||||
elementHandler.edittingInput($event.target)
|
||||
@ -646,6 +643,7 @@ export default {
|
||||
.then((response) => {
|
||||
this.userProfile.account.basic.photo = response.data.photo
|
||||
this.updateLocalIdentityData()
|
||||
this.updateLocalProfileData()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
@ -885,8 +883,8 @@ export default {
|
||||
textAreaAujuster.adjustHight(element)
|
||||
},
|
||||
updateSelfIntro() {
|
||||
this.personalOperation.self_intro.content_html =
|
||||
this.$refs.personal_self_intro_editor_div.innerHTML
|
||||
// this.personalOperation.self_intro.content_html =
|
||||
// this.$refs.personal_self_intro_editor_div.innerHTML
|
||||
if (!this.personalOperation.self_intro.content_html) {
|
||||
return
|
||||
}
|
||||
@ -948,6 +946,8 @@ export default {
|
||||
if (response.data.accepting_request && response.data.account_link != '') {
|
||||
window.location = response.data.account_link
|
||||
}
|
||||
|
||||
this.updateLocalProfileData()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
@ -1144,7 +1144,7 @@ export default {
|
||||
.btn-group-container {
|
||||
position: absolute;
|
||||
right: 32px;
|
||||
top: 10px;
|
||||
top: -30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +82,14 @@ export default {
|
||||
components: { SvgIcon },
|
||||
name: 'MessageHub',
|
||||
props: {},
|
||||
mounted() {},
|
||||
mounted() {
|
||||
this.$store.dispatch('basic/updateConversationsPage', {
|
||||
token: this.mnx_getUserAuthToken(),
|
||||
cb: error => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userIdentityNote: this.mnx_getUserIdentity(),
|
||||
@ -103,7 +110,7 @@ export default {
|
||||
this.messages = n_val[0].messages || []
|
||||
this.clearUnreadMessageBy(n_val[0])
|
||||
} else {
|
||||
if (this.selConversation.id === n_val?.[0]?.id) {
|
||||
if (n_val?.[0] && this.selConversation?.id === n_val?.[0]?.id) {
|
||||
this.messages = n_val[0].messages || []
|
||||
this.clearUnreadMessageBy(n_val[0])
|
||||
}
|
||||
|
||||
@ -474,7 +474,18 @@
|
||||
class="accordion-collapse collapse"
|
||||
data-bs-parent="#collapse-project-issue"
|
||||
>
|
||||
<div class="project-invite-collaborator-containter">
|
||||
<div class="project-code-git-url-container">
|
||||
<button
|
||||
class="project-code-copy-git-url"
|
||||
@click="gotoIssueManage(project)"
|
||||
>
|
||||
{{$t('Issues management')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="currentChartData" autoresize />
|
||||
</div>
|
||||
<!-- <div class="project-invite-collaborator-containter">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
@ -509,13 +520,10 @@
|
||||
</button>
|
||||
</div>
|
||||
<textarea type="text" v-model="newIssueDescriptions[project_index]" />
|
||||
<!-- <div class="project-new-issue-action-container">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<!-- <div>
|
||||
<div
|
||||
class="project-issue-container"
|
||||
v-for="(issue, issue_index) in project.project.issue.open_issues"
|
||||
@ -593,7 +601,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -700,6 +708,10 @@ export default {
|
||||
console.error('unexpected value:' + project.status)
|
||||
}
|
||||
},
|
||||
gotoIssueManage(project) {
|
||||
// requestIssueUtils.fillProjectIssue(project)
|
||||
this.mnx_navToProjectIssue(project.id)
|
||||
},
|
||||
fromIntToProjectStatus(statusInt) {
|
||||
return convertIntoToProjectStatus(statusInt)
|
||||
},
|
||||
@ -1242,6 +1254,7 @@ export default {
|
||||
@extend .w-20;
|
||||
}
|
||||
|
||||
// ...
|
||||
.project-issue-bar-container {
|
||||
@extend .flex-row-container;
|
||||
@extend .justify-content-between;
|
||||
@ -1272,6 +1285,7 @@ export default {
|
||||
text-align: center;
|
||||
@extend .initiate-button;
|
||||
}
|
||||
// ...
|
||||
|
||||
.project-milestones-table {
|
||||
border: 0;
|
||||
|
||||
472
frontend/src/pages/user/workspace/projectIssue/Issue.vue
Normal file
472
frontend/src/pages/user/workspace/projectIssue/Issue.vue
Normal file
@ -0,0 +1,472 @@
|
||||
<template>
|
||||
<div class="workspace-container">
|
||||
<div class="workspace-body">
|
||||
<div class="accordion" id="workspace-project-accordion">
|
||||
<div v-if="project.id" class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapse-project-issue"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapse-project-issue"
|
||||
>
|
||||
<div class="project-issue-bar-container dashed-container">
|
||||
<div class="project-issue-open-issues">
|
||||
<label class="project-item-label">{{ $t('Summary') }}</label>
|
||||
<p class="project-item-text">{{ project.title }}</p>
|
||||
</div>
|
||||
<div class="project-issue-open-issues">
|
||||
<label class="project-item-label">{{ $t('Open issues') }}</label>
|
||||
<p class="project-item-text">
|
||||
{{ project.project.issue.number_of_open_issues }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="project-issue-resolved-issues">
|
||||
<label class="project-item-label">{{ $t('Resolved issues') }}</label>
|
||||
<p class="project-item-text">
|
||||
{{ project.project.issue.number_of_resolved_issues }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="project-issue-closed-issues">
|
||||
<label class="project-item-label">{{ $t('Closed issues') }}</label>
|
||||
<p class="project-item-text">
|
||||
{{ project.project.issue.number_of_closed_issues }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
id="collapse-project-issue"
|
||||
class="accordion-collapse collapse"
|
||||
data-bs-parent="#collapse-project-issue"
|
||||
>
|
||||
<div class="project-invite-collaborator-containter">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
ref="issueAddBtn"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapse-project-new-issue"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapse-project-issue"
|
||||
>
|
||||
<div class="project-invite-collaborator">+ {{ $t('Add Issue') }}</div>
|
||||
</button>
|
||||
<div
|
||||
id="collapse-project-new-issue"
|
||||
class="accordion-collapse collapse"
|
||||
data-bs-parent="#collapse-project-new-issue"
|
||||
>
|
||||
<div class="project-issue-description-container">
|
||||
<div class="project-issue-description">
|
||||
<label class="project-item-label">{{
|
||||
$t('New issue description')
|
||||
}}</label>
|
||||
<button
|
||||
class="project-issue-description-btn"
|
||||
@click="
|
||||
postNewIssue(
|
||||
project.request.product_id,
|
||||
project.project_id,
|
||||
newIssueDescriptions
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ $t('Submit') }}
|
||||
</button>
|
||||
</div>
|
||||
<textarea ref="issueBtn" type="text" v-model="newIssueDescriptions" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="project-issue-container"
|
||||
v-for="(issue, issue_index) in project.project.issue.open_issues"
|
||||
:key="issue_index"
|
||||
:id="'project-issue-' + issue_index"
|
||||
>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
:data-bs-target="'#collapse-project-issue-details' + issue_index"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapse-project-issue-details"
|
||||
>
|
||||
<div class="project-issue-header dashed-container">
|
||||
<div class="project-issue-title">
|
||||
<label class="project-item-label">{{ $t('Issue title') }}</label>
|
||||
<p class="project-item-text">{{ issue.title }}</p>
|
||||
</div>
|
||||
<div class="project-issue-status">
|
||||
<label class="project-item-label">{{ $t('Status') }}</label>
|
||||
<p class="project-item-text">
|
||||
{{ fromIntToProjectIssueStatus(issue.status) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="project-issue-update">
|
||||
<label class="project-item-label">{{ $t('Last updated') }}</label>
|
||||
<p class="project-item-text">
|
||||
{{ getDateFromFulltimeString(issue.update_time) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
:id="'collapse-project-issue-details' + issue_index"
|
||||
class="accordion-collapse collapse"
|
||||
:data-bs-parent="'#collapse-project-issue-details' + issue_index"
|
||||
>
|
||||
<div class="project-issue-description-container">
|
||||
<div class="project-issue-description">
|
||||
<label class="project-item-label">{{
|
||||
$t('Issue description')
|
||||
}}</label>
|
||||
<button
|
||||
:hidden="
|
||||
!showIssueActionButton(project.project, issue, 'Resolve')
|
||||
"
|
||||
class="project-issue-description-btn"
|
||||
@click="setProjectIssueStatus(issue.id, 1)"
|
||||
>
|
||||
{{ $t('Resolve') }}
|
||||
</button>
|
||||
<button
|
||||
:hidden="
|
||||
!showIssueActionButton(project.project, issue, 'Confirm')
|
||||
"
|
||||
class="project-issue-description-btn"
|
||||
@click="setProjectIssueStatus(issue.id, 2)"
|
||||
>
|
||||
{{ $t('Confirm') }}
|
||||
</button>
|
||||
<button
|
||||
:hidden="!showIssueActionButton(project.project, issue, 'Reopen')"
|
||||
class="project-issue-description-btn"
|
||||
@click="setProjectIssueStatus(issue.id, 0)"
|
||||
>
|
||||
{{ $t('Reopen') }}
|
||||
</button>
|
||||
</div>
|
||||
<p class="project-item-text">{{ issue.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { DateUtils, WorksapceApi } from '@/utils/index'
|
||||
import { projectStatusEnum, convertIntoToProjectIssueStatus, projectIssueStatusEnum } from '@/types/index'
|
||||
export default {
|
||||
name: 'projectIssue',
|
||||
props: {
|
||||
project_id: {
|
||||
required: true,
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
project: {},
|
||||
newIssueDescriptions: ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchView()
|
||||
},
|
||||
methods: {
|
||||
fetchView() {
|
||||
WorksapceApi.fetchWorkspaceView()
|
||||
.then((response) => {
|
||||
const projects = response.data || []
|
||||
for (let i = 0; i < projects.length; i ++) {
|
||||
if (projects[i].id == this.project_id) {
|
||||
this.project = projects[i]
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
})
|
||||
},
|
||||
isOngoingProject(project) {
|
||||
return project.status == projectStatusEnum.ONGOING
|
||||
},
|
||||
fromIntToProjectIssueStatus(issueStatus) {
|
||||
return convertIntoToProjectIssueStatus(issueStatus)
|
||||
},
|
||||
getDateFromFulltimeString(fulltime) {
|
||||
return DateUtils.FromJsonToDateString(fulltime)
|
||||
},
|
||||
postNewIssue(product_id, project_id, issue_description) {
|
||||
if (issue_description == null || issue_description == '') {
|
||||
alert(this.$t('Please input issue description'))
|
||||
return
|
||||
}
|
||||
WorksapceApi.postIssueForProduct(product_id, project_id, issue_description)
|
||||
.then((response) => {
|
||||
this.$refs.issueBtn.blur()
|
||||
this.$refs.issueAddBtn.click()
|
||||
this.fetchView()
|
||||
this.newIssueDescriptions = ''
|
||||
})
|
||||
.catch((error) => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
})
|
||||
},
|
||||
setProjectIssueStatus(issue_id, status) {
|
||||
WorksapceApi.setProductIssueStatus(issue_id, status)
|
||||
.then((response) => {
|
||||
this.fetchView()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.mnx_backendErrorHandler(error)
|
||||
})
|
||||
},
|
||||
showIssueActionButton(project, issue, button_text) {
|
||||
switch (issue.status) {
|
||||
case projectIssueStatusEnum.OPEN:
|
||||
if (button_text === this.$t('Resolve')) {
|
||||
return project.providers.includes(project.current_user_id)
|
||||
}
|
||||
break
|
||||
case 1:
|
||||
if (button_text === this.$t('Reopen') || button_text === this.$t('Confirm')) {
|
||||
return project.issuers.includes(project.current_user_id)
|
||||
}
|
||||
break
|
||||
case projectIssueStatusEnum.CLOSED:
|
||||
if (button_text === this.$t('Reopen')) {
|
||||
return project.issuers.includes(project.current_user_id)
|
||||
}
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.workspace-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.workspace-header {
|
||||
@extend .flex-row-container;
|
||||
@extend .justify-content-end;
|
||||
}
|
||||
|
||||
.workspace-body {
|
||||
width: 100%;
|
||||
max-width: $body-width;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.project-issue-bar-container {
|
||||
@extend .flex-row-container;
|
||||
@extend .justify-content-between;
|
||||
}
|
||||
|
||||
.project-issue-resolved-issues {
|
||||
@extend .text-start;
|
||||
@extend .w-20;
|
||||
}
|
||||
|
||||
.project-issue-open-issues {
|
||||
@extend .text-start;
|
||||
@extend .w-20;
|
||||
}
|
||||
|
||||
.project-issue-closed-issues {
|
||||
@extend .text-start;
|
||||
@extend .w-20;
|
||||
}
|
||||
|
||||
.project-issue-last-update {
|
||||
@extend .text-start;
|
||||
@extend .w-20;
|
||||
}
|
||||
|
||||
.project-add-new-issue {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
@extend .initiate-button;
|
||||
}
|
||||
|
||||
.project-item-label {
|
||||
@extend .label-text-light;
|
||||
}
|
||||
|
||||
.project-item-text {
|
||||
@extend .text-start;
|
||||
margin-bottom: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.project-invite-collaborator-containter {
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
|
||||
.accordion-button {
|
||||
// border: 1px solid $primary;
|
||||
// color: $primary;
|
||||
// background-color: #F3F6FF;
|
||||
padding: 12px !important;
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.project-invite-collaborator {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
@extend .initiate-button;
|
||||
color: $primary;
|
||||
background-color: #f3f6ff;
|
||||
}
|
||||
|
||||
.project-invite-collaborator-form-container {
|
||||
margin: 12px;
|
||||
height: 37px;
|
||||
display: flex;
|
||||
padding: 0 12px;
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
border: 1px solid #e7e8eb;
|
||||
&:focus-within {
|
||||
border: 1px solid #1748f8;
|
||||
}
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
margin-right: 12px;
|
||||
border: none;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.project-invite-enter {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 3px;
|
||||
background: #f3f3f5;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-invite-collaborator-form {
|
||||
@extend .text-start;
|
||||
@extend .flex-grow-1;
|
||||
}
|
||||
|
||||
.project-invite-collaborator-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.project-invite-collaborator-action-button {
|
||||
@extend .initiate-button;
|
||||
@extend .float-end;
|
||||
}
|
||||
.project-new-issue-textarea {
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.project-new-issue-action-button {
|
||||
@extend .initiate-button;
|
||||
@extend .float-end;
|
||||
}
|
||||
|
||||
.project-new-issue-action-container {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.project-issue-description-container {
|
||||
padding: 12px;
|
||||
|
||||
textarea {
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e1e1e1;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
.project-issue-description {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
label {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.project-issue-description-btn {
|
||||
@extend .btn;
|
||||
@extend .btn-link;
|
||||
padding: 0;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-issue-action-container {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.project-issue-action-button {
|
||||
@extend .btn;
|
||||
@extend .btn-link;
|
||||
@extend .float-end;
|
||||
}
|
||||
|
||||
.project-issue-statistics-container {
|
||||
@extend .border;
|
||||
height: 100px;
|
||||
@extend .p-3;
|
||||
}
|
||||
|
||||
.project-issue-container {
|
||||
@extend .justify-content-between;
|
||||
}
|
||||
|
||||
.project-issue-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.project-issue-title {
|
||||
@extend .text-start;
|
||||
@extend .flex-grow-1;
|
||||
}
|
||||
|
||||
.project-issue-status {
|
||||
@extend .text-start;
|
||||
@extend .w-10;
|
||||
}
|
||||
|
||||
.project-issue-update {
|
||||
@extend .text-start;
|
||||
@extend .w-10;
|
||||
}
|
||||
|
||||
.project-issue-manage-button {
|
||||
@extend .initiate-button;
|
||||
@extend .float-end;
|
||||
}
|
||||
</style>
|
||||
@ -23,6 +23,8 @@ import MyWorkspaceRequests from '@/pages/user/workspace/requestManage/Home.vue'
|
||||
import IssueRequest from '@/pages/user/workspace/requestIssue/Issue.vue'
|
||||
import RequestSubmitted from '@/pages/user/workspace/requestIssue/Submitted.vue'
|
||||
|
||||
import ProjectIssue from '@/pages/user/workspace/projectIssue/Issue.vue'
|
||||
|
||||
//Workspace Proposals
|
||||
import MyWorkspaceProposals from '@/pages/user/workspace/proposalManage/Home.vue'
|
||||
|
||||
@ -170,6 +172,13 @@ const router = createRouter({
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'project-issue',
|
||||
path: '/project-issue/:project_id',
|
||||
meta: { requiredRoles: [userRoleEnum.PERSONAL] },
|
||||
components: { default: ProjectIssue, footer: FooterUser, header: HeaderUser },
|
||||
props: true
|
||||
},
|
||||
{
|
||||
name: 'request-issue2',
|
||||
path: '/request-issue/:loadFrom/:requestId',
|
||||
|
||||
@ -4,6 +4,7 @@ import { WsConnectionFactory } from '@/utils/backend/websocket'
|
||||
import { MessageHubApi } from '@/utils/backend/messageHub'
|
||||
|
||||
const ignoreEventType = ['test']
|
||||
let timer = null
|
||||
const GWT = new Date('01 Jan 1970 00:00:00 GMT').toISOString()
|
||||
const unreadWorkspaceRules = [
|
||||
{subject:'request', event:'quoted'},
|
||||
@ -23,6 +24,45 @@ const checkUnreadRulesBy = (message, rules = []) => {
|
||||
return false
|
||||
}
|
||||
|
||||
const updateConversations =(state, {token ,cb}, data) => {
|
||||
MessageHubApi.fetchConversations(GWT, token).then((response) => {
|
||||
const conversations = response.data.conversations || []
|
||||
let updateLength = 0
|
||||
if (conversations.length === 0) {
|
||||
state.unreadConversationCount = 0
|
||||
localStorage.setItem('unreadConversationCount', 0)
|
||||
}
|
||||
if (data && data.event !== 'connected') {
|
||||
updateLength = conversations.length - state.conversations.length
|
||||
if (updateLength === 0) updateLength = 1
|
||||
for (let i = 0; i < updateLength; i++) {
|
||||
conversations[i]['unread'] = true
|
||||
}
|
||||
}
|
||||
state.conversations = conversations
|
||||
localStorage.setItem('conversations', JSON.stringify(conversations))
|
||||
const conversation = conversations[0]
|
||||
if (conversation?.id) {
|
||||
MessageHubApi.fetchMessages(
|
||||
conversation.id,
|
||||
conversation.message_update_time ? conversation.message_update_time : GWT,
|
||||
token
|
||||
).then((response) => {
|
||||
conversations[0].messages = response?.data || []
|
||||
conversations[0].message_update_time = new Date().toISOString()
|
||||
// state.conversations = conversations
|
||||
state.unreadConversationCount = updateLength
|
||||
// localStorage.setItem('conversations', JSON.stringify(conversations))
|
||||
localStorage.setItem('unreadConversationCount', updateLength)
|
||||
})
|
||||
}
|
||||
}).catch(err => {
|
||||
if (cb && cb instanceof Function) {
|
||||
cb(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const basicStore = {
|
||||
namespaced: true,
|
||||
state() {
|
||||
@ -46,7 +86,7 @@ const basicStore = {
|
||||
token,
|
||||
() => {
|
||||
// keep
|
||||
setInterval(() => {
|
||||
timer = setInterval(() => {
|
||||
state.downstream_web_socket.send('keep alive')
|
||||
}, 1000 * 60)
|
||||
console.log('downstream_web_socket open')
|
||||
@ -80,39 +120,16 @@ const basicStore = {
|
||||
state.unreadWorkspace = true
|
||||
}
|
||||
|
||||
MessageHubApi.fetchConversations(GWT, token).then((response) => {
|
||||
const conversations = response.data.conversations || []
|
||||
let updateLength = 0
|
||||
if (data.event !== 'connected') {
|
||||
updateLength = conversations.length - state.conversations.length
|
||||
if (updateLength === 0) updateLength = 1
|
||||
for (let i = 0; i < updateLength; i++) {
|
||||
conversations[i]['unread'] = true
|
||||
}
|
||||
}
|
||||
const conversation = conversations[0]
|
||||
if (conversation?.id) {
|
||||
MessageHubApi.fetchMessages(
|
||||
conversation.id,
|
||||
conversation.message_update_time ? conversation.message_update_time : GWT,
|
||||
token
|
||||
).then((response) => {
|
||||
conversations[0].messages = response?.data || []
|
||||
conversations[0].message_update_time = new Date().toISOString()
|
||||
state.conversations = conversations
|
||||
state.unreadConversationCount = updateLength
|
||||
localStorage.setItem('conversations', JSON.stringify(conversations))
|
||||
localStorage.setItem('unreadConversationCount', updateLength)
|
||||
})
|
||||
}
|
||||
})
|
||||
updateConversations(state,{token},data)
|
||||
|
||||
},
|
||||
() => {
|
||||
console.log('downstream_web_socket error')
|
||||
},
|
||||
() => {
|
||||
console.log('downstream_web_socket closed')
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -128,6 +145,9 @@ const basicStore = {
|
||||
}
|
||||
}
|
||||
},
|
||||
updateConversationsPage(state, token) {
|
||||
updateConversations(state, token)
|
||||
},
|
||||
clearUnreadWorkspace(state) {
|
||||
state.unreadWorkspace = false
|
||||
},
|
||||
@ -145,6 +165,9 @@ const basicStore = {
|
||||
readMessageBy(context, sender) {
|
||||
context.commit('readMessageBy', sender)
|
||||
},
|
||||
updateConversationsPage(context, {token, cb}) {
|
||||
context.commit('updateConversationsPage', {token, cb})
|
||||
},
|
||||
clearUnreadWorkspace(context) {
|
||||
context.commit('clearUnreadWorkspace')
|
||||
},
|
||||
|
||||
@ -4,7 +4,8 @@ const userProfileStore = {
|
||||
namespaced: true,
|
||||
state() {
|
||||
return {
|
||||
role: userRoleEnum.NONE
|
||||
role: userRoleEnum.NONE,
|
||||
profile: {}
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
@ -16,6 +17,18 @@ const userProfileStore = {
|
||||
if (localStorage.role) {
|
||||
state.role = Number(localStorage.role)
|
||||
}
|
||||
},
|
||||
setProfile(state, profile) {
|
||||
state.profile = profile
|
||||
localStorage.setItem('profile', JSON.stringify(profile || {}))
|
||||
},
|
||||
loadProfile(state) {
|
||||
try {
|
||||
const pj = localStorage.getItem('profile')
|
||||
state.profile = JSON.parse(pj)
|
||||
} catch (error) {
|
||||
console.log('err', error)
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -24,14 +37,22 @@ const userProfileStore = {
|
||||
},
|
||||
logoutRoles(context) {
|
||||
context.commit('setRole', { role: userRoleEnum.NONE })
|
||||
context.commit('setProfile', {})
|
||||
},
|
||||
loadRoleLocal(context) {
|
||||
context.commit('loadRole')
|
||||
context.commit('loadProfile')
|
||||
},
|
||||
updateProfile(context, profile) {
|
||||
context.commit('setProfile', profile)
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
userRole(state) {
|
||||
return state.role
|
||||
},
|
||||
profile(state) {
|
||||
return state.profile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,14 @@ class RequestIssueUtils {
|
||||
return this.drafted_request
|
||||
}
|
||||
|
||||
fillProjectIssue(issue) {
|
||||
this.projectIssue = issue
|
||||
}
|
||||
|
||||
fetchProjectIssue() {
|
||||
return this.projectIssue
|
||||
}
|
||||
|
||||
fillTemplatedRequest(request) {
|
||||
this.templated_request = request
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user