update
This commit is contained in:
parent
c11642d797
commit
73ea1e43e6
@ -14,9 +14,11 @@
|
|||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bootstrap": "^5.3.1",
|
"bootstrap": "^5.3.1",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
|
"echarts": "^5.5.1",
|
||||||
"pdfjs-dist": "^4.3.136",
|
"pdfjs-dist": "^4.3.136",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
"vue-echarts": "^6.7.3",
|
||||||
"vue-i18n": "^9.13.1",
|
"vue-i18n": "^9.13.1",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.2.4",
|
||||||
"vuex": "^4.1.0"
|
"vuex": "^4.1.0"
|
||||||
|
|||||||
@ -11,88 +11,102 @@
|
|||||||
@mouseup.stop="selectionEnd"
|
@mouseup.stop="selectionEnd"
|
||||||
/>
|
/>
|
||||||
<div v-if="!disabled" class="editor-control" :style="editorCtrlStyle">
|
<div v-if="!disabled" class="editor-control" :style="editorCtrlStyle">
|
||||||
<div v-for="(item, index) in iconList" :key="index" class="editor-item">
|
<template v-if="!inputing">
|
||||||
<button
|
<div v-for="(item, index) in iconList" :key="index" class="editor-item">
|
||||||
class="item-icon"
|
<button
|
||||||
:class="{
|
class="item-icon"
|
||||||
activity: commandStates.indexOf(item.type) !== -1,
|
:class="{
|
||||||
last: index === iconList.length - 1
|
activity: commandStates.indexOf(item.type) !== -1,
|
||||||
}"
|
last: index === iconList.length - 1
|
||||||
:data-info="item.name"
|
}"
|
||||||
@click="iconClick($event, item.type)"
|
:data-info="item.name"
|
||||||
:data-bs-toggle="item.drop ? 'dropdown' : ''"
|
@click="iconClick($event, item.type)"
|
||||||
data-bs-auto-close="outside"
|
:data-bs-toggle="item.drop ? 'dropdown' : ''"
|
||||||
aria-expanded="false"
|
data-bs-auto-close="outside"
|
||||||
>
|
aria-expanded="false"
|
||||||
<svg-icon :icon="item.icon" class-name="icon" />
|
>
|
||||||
</button>
|
<svg-icon :icon="item.icon" class-name="icon" />
|
||||||
<div class="dropmenu drop-style" v-if="item.type === 'style'">
|
</button>
|
||||||
<ul>
|
<div class="dropmenu drop-style" v-if="item.type === 'style'">
|
||||||
<li>
|
<ul>
|
||||||
<a href="#" @click="iconClick($event, 'p', 'style')"><p>Text</p></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'p', 'style')"><p>Text</p></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'pre', 'style')"><pre>code</pre></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'pre', 'style')"><pre>code</pre></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'blockquote', 'style')"
|
<li>
|
||||||
><blockquote>引用</blockquote></a
|
<a href="#" @click="iconClick($event, 'blockquote', 'style')"
|
||||||
>
|
><blockquote>引用</blockquote></a
|
||||||
</li>
|
>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'h1', 'style')"><h1>Caption 1</h1></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'h1', 'style')"><h1>Caption 1</h1></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'h2', 'style')"><h2>Caption 2</h2></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'h2', 'style')"><h2>Caption 2</h2></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'h3', 'style')"><h3>Caption 3</h3></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'h3', 'style')"><h3>Caption 3</h3></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'h4', 'style')"><h4>Caption 4</h4></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'h4', 'style')"><h4>Caption 4</h4></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'h5', 'style')"><h5>Caption 5</h5></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'h5', 'style')"><h5>Caption 5</h5></a>
|
||||||
<li>
|
</li>
|
||||||
<a href="#" @click="iconClick($event, 'h6', 'style')"><h6>Caption 6</h6></a>
|
<li>
|
||||||
</li>
|
<a href="#" @click="iconClick($event, 'h6', 'style')"><h6>Caption 6</h6></a>
|
||||||
</ul>
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="dropmenu drop-style" v-if="item.type === 'alignjustify'">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyCenter', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-aligncenter"></i>
|
||||||
|
<span>middle</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyLeft', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-alignleft"></i>
|
||||||
|
<span>left aligned</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyRight', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-alignright"></i>
|
||||||
|
<span>right aligned</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyFull', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-alignjustify"></i>
|
||||||
|
<span>default aligned</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropmenu drop-style" v-if="item.type === 'alignjustify'">
|
</template>
|
||||||
<ul>
|
<template v-if="inputing">
|
||||||
<li>
|
<div class="editor-item">
|
||||||
<a href="#" @click="iconClick($event, 'justifyCenter', 'alignjustify')">
|
<button class="item-icon item-icon-back" @click="backAction">
|
||||||
<i class="iconfont icon-aligncenter"></i>
|
<svg-icon icon="fe-back" class-name="icon" />
|
||||||
<span>middle</span>
|
</button>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#" @click="iconClick($event, 'justifyLeft', 'alignjustify')">
|
|
||||||
<i class="iconfont icon-alignleft"></i>
|
|
||||||
<span>left aligned</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#" @click="iconClick($event, 'justifyRight', 'alignjustify')">
|
|
||||||
<i class="iconfont icon-alignright"></i>
|
|
||||||
<span>right aligned</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#" @click="iconClick($event, 'justifyFull', 'alignjustify')">
|
|
||||||
<i class="iconfont icon-alignjustify"></i>
|
|
||||||
<span>default aligned</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="editor-item">
|
||||||
|
<input type="text" v-model="linkUrl" autofocus @keydown.enter="inputAction">
|
||||||
|
<svg-icon icon="msg-enter" class-name="item-enter-icon" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import SvgIcon from '@/components/SvgIcon.vue'
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
import { websiteValidator } from '@/utils/validator'
|
||||||
export default {
|
export default {
|
||||||
name: 'FreeleapsEditor',
|
name: 'FreeleapsEditor',
|
||||||
props: {
|
props: {
|
||||||
@ -112,6 +126,8 @@ export default {
|
|||||||
selectedRange: '',
|
selectedRange: '',
|
||||||
editorCtrlStyle: {},
|
editorCtrlStyle: {},
|
||||||
commandStates: [],
|
commandStates: [],
|
||||||
|
inputing: false,
|
||||||
|
linkUrl: '',
|
||||||
iconList: [
|
iconList: [
|
||||||
// {
|
// {
|
||||||
// name: 'lable', // hover name
|
// name: 'lable', // hover name
|
||||||
@ -175,7 +191,14 @@ export default {
|
|||||||
icon: 'fe-orderedlist',
|
icon: 'fe-orderedlist',
|
||||||
drop: false,
|
drop: false,
|
||||||
canChoose: true
|
canChoose: true
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name: 'link',
|
||||||
|
type: 'link',
|
||||||
|
icon: 'fe-link',
|
||||||
|
drop: false,
|
||||||
|
canChoose: true
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// name: 'align-justify',
|
// name: 'align-justify',
|
||||||
// type: 'alignjustify',
|
// type: 'alignjustify',
|
||||||
@ -225,6 +248,10 @@ export default {
|
|||||||
this.$refs.editor.focus()
|
this.$refs.editor.focus()
|
||||||
this.selectedRange = this.getSelect()
|
this.selectedRange = this.getSelect()
|
||||||
this.restoreSelection()
|
this.restoreSelection()
|
||||||
|
if (type === 'link') {
|
||||||
|
this.inputing = true
|
||||||
|
return
|
||||||
|
}
|
||||||
this.changeStyle(type)
|
this.changeStyle(type)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (dropType) {
|
if (dropType) {
|
||||||
@ -238,6 +265,24 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
backAction() {
|
||||||
|
this.inputing = false
|
||||||
|
this.$refs.editor.focus()
|
||||||
|
this.restoreSelection()
|
||||||
|
},
|
||||||
|
inputAction() {
|
||||||
|
const error = websiteValidator.validate(this.linkUrl)
|
||||||
|
if (error) {
|
||||||
|
alert(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const a_node = document.createElement('a')
|
||||||
|
a_node.setAttribute('href', this.linkUrl)
|
||||||
|
this.selectedRange.surroundContents(a_node)
|
||||||
|
this.backAction()
|
||||||
|
this.$refs.editor.blur()
|
||||||
|
this.editorCtrlStyle = { display: 'none' }
|
||||||
|
},
|
||||||
getSelect() {
|
getSelect() {
|
||||||
if (window.getSelection) {
|
if (window.getSelection) {
|
||||||
let sel = window.getSelection()
|
let sel = window.getSelection()
|
||||||
@ -417,6 +462,30 @@ export default {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
input {
|
||||||
|
height: 24px;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 24px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-enter-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 3px;
|
||||||
|
background-color: #e1e1e1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.item-icon {
|
.item-icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
@ -486,6 +555,9 @@ export default {
|
|||||||
&.activity + .dropmenu {
|
&.activity + .dropmenu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
&.item-icon-back {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
:class="activePath == 'Workspace' ? 'active' : ''"
|
:class="activePath == 'Workspace' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<svg-icon icon="workspace" class-name="icon" />
|
<svg-icon icon="workspace" class-name="icon" />
|
||||||
Workspace
|
{{$t('Workspace')}}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="navigation-item"
|
class="navigation-item"
|
||||||
@ -23,7 +23,7 @@
|
|||||||
:class="activePath == 'Requests' ? 'active' : ''"
|
:class="activePath == 'Requests' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<svg-icon icon="requests" class-name="icon" />
|
<svg-icon icon="requests" class-name="icon" />
|
||||||
Requests
|
{{$t('Requests')}}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="navigation-item"
|
class="navigation-item"
|
||||||
@ -31,7 +31,7 @@
|
|||||||
:class="activePath == 'Providers' ? 'active' : ''"
|
:class="activePath == 'Providers' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<svg-icon icon="providers" class-name="icon" />
|
<svg-icon icon="providers" class-name="icon" />
|
||||||
Providers
|
{{$t('Providers')}}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="navigation-item"
|
class="navigation-item"
|
||||||
@ -39,7 +39,7 @@
|
|||||||
:class="activePath == 'Post' ? 'active' : ''"
|
:class="activePath == 'Post' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<svg-icon icon="post" class-name="icon" />
|
<svg-icon icon="post" class-name="icon" />
|
||||||
Post
|
{{$t('Post')}}
|
||||||
</button>
|
</button>
|
||||||
<div class="form-check form-switch header-switch-container">
|
<div class="form-check form-switch header-switch-container">
|
||||||
<input
|
<input
|
||||||
@ -50,10 +50,10 @@
|
|||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="personal-earning-now-checkbox">
|
<label class="form-check-label" for="personal-earning-now-checkbox">
|
||||||
<span>Providing service</span>
|
<span>{{$t('Providing service')}}</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="header-switch-desc">
|
<div class="header-switch-desc">
|
||||||
Please go to profile page to add money receiving method
|
{{$t('Please go to profile page to add money receiving method')}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<laguage-switch class="laguage-switch" />
|
<laguage-switch class="laguage-switch" />
|
||||||
@ -68,17 +68,17 @@
|
|||||||
/>
|
/>
|
||||||
<ul class="dropdown-menu" aria-labelledby="accountButton">
|
<ul class="dropdown-menu" aria-labelledby="accountButton">
|
||||||
<li>
|
<li>
|
||||||
<button class="account-menu-button" @click="gotoProfile">Profile</button>
|
<button class="account-menu-button" @click="gotoProfile">{{$t('Profile')}}</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button class="account-menu-button" @click="gotoHistory">History</button>
|
<button class="account-menu-button" @click="gotoHistory">{{$t('History')}}</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<hr class="dropdown-divider" />
|
<hr class="dropdown-divider" />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button class="account-menu-button" @click="signout">
|
<button class="account-menu-button" @click="signout">
|
||||||
Log out ({{ userIdentityNote }})
|
{{$t('Log out')}} ({{ userIdentityNote }})
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -95,6 +95,7 @@ export default {
|
|||||||
components: { LaguageSwitch },
|
components: { LaguageSwitch },
|
||||||
computed: {
|
computed: {
|
||||||
unreadCount() {
|
unreadCount() {
|
||||||
|
console.log('unreadCount', this.$store.getters['basic/unreadCount'])
|
||||||
return this.$store.getters['basic/unreadCount']
|
return this.$store.getters['basic/unreadCount']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
1
frontend/src/icons/fe-back.svg
Normal file
1
frontend/src/icons/fe-back.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16315" width="64" height="64"><path d="M189.056 547.072l554.666667 384A42.666667 42.666667 0 0 0 810.666667 896V128a42.666667 42.666667 0 0 0-66.944-35.114667l-554.666667 384a42.794667 42.794667 0 0 0 0 70.186667z" p-id="16316"></path></svg>
|
||||||
|
After Width: | Height: | Size: 325 B |
1
frontend/src/icons/fe-link.svg
Normal file
1
frontend/src/icons/fe-link.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4251" width="64" height="64"><path d="M607.934444 417.856853c-6.179746-6.1777-12.766768-11.746532-19.554358-16.910135l-0.01228 0.011256c-6.986111-6.719028-16.47216-10.857279-26.930349-10.857279-21.464871 0-38.864146 17.400299-38.864146 38.864146 0 9.497305 3.411703 18.196431 9.071609 24.947182l-0.001023 0c0.001023 0.001023 0.00307 0.00307 0.005117 0.004093 2.718925 3.242857 5.953595 6.03853 9.585309 8.251941 3.664459 3.021823 7.261381 5.997598 10.624988 9.361205l3.203972 3.204995c40.279379 40.229237 28.254507 109.539812-12.024871 149.820214L371.157763 796.383956c-40.278355 40.229237-105.761766 40.229237-146.042167 0l-3.229554-3.231601c-40.281425-40.278355-40.281425-105.809861 0-145.991002l75.93546-75.909877c9.742898-7.733125 15.997346-19.668968 15.997346-33.072233 0-23.312962-18.898419-42.211381-42.211381-42.211381-8.797363 0-16.963347 2.693342-23.725354 7.297197-0.021489-0.045025-0.044002-0.088004-0.066515-0.134053l-0.809435 0.757247c-2.989077 2.148943-5.691629 4.669346-8.025791 7.510044l-78.913281 73.841775c-74.178443 74.229608-74.178443 195.632609 0 269.758863l3.203972 3.202948c74.178443 74.127278 195.529255 74.127278 269.707698 0l171.829484-171.880649c74.076112-74.17435 80.357166-191.184297 6.282077-265.311575L607.934444 417.856853z" fill="#5D5D5D" p-id="4252"></path><path d="M855.61957 165.804257l-3.203972-3.203972c-74.17742-74.178443-195.528232-74.178443-269.706675 0L410.87944 334.479911c-74.178443 74.178443-78.263481 181.296089-4.085038 255.522628l3.152806 3.104711c3.368724 3.367701 6.865361 6.54302 10.434653 9.588379 2.583848 2.885723 5.618974 5.355985 8.992815 7.309476 0.025583 0.020466 0.052189 0.041956 0.077771 0.062422l0.011256-0.010233c5.377474 3.092431 11.608386 4.870938 18.257829 4.870938 20.263509 0 36.68962-16.428158 36.68962-36.68962 0-5.719258-1.309832-11.132548-3.645017-15.95846l0 0c-4.850471-10.891048-13.930267-17.521049-20.210297-23.802102l-3.15383-3.102664c-40.278355-40.278355-24.982998-98.79612 15.295358-139.074476l171.930791-171.830507c40.179095-40.280402 105.685018-40.280402 145.965419 0l3.206018 3.152806c40.279379 40.281425 40.279379 105.838513 0 146.06775l-75.686796 75.737962c-10.296507 7.628748-16.97358 19.865443-16.97358 33.662681 0 23.12365 18.745946 41.87062 41.87062 41.87062 8.048303 0 15.563464-2.275833 21.944801-6.211469 0.048095 0.081864 0.093121 0.157589 0.141216 0.240477l1.173732-1.083681c3.616364-2.421142 6.828522-5.393847 9.529027-8.792247l79.766718-73.603345C929.798013 361.334535 929.798013 239.981676 855.61957 165.804257z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
@ -180,5 +180,32 @@ export default {
|
|||||||
'Payment plan proposed by the service provider': 'Payment plan proposed by the service provider',
|
'Payment plan proposed by the service provider': 'Payment plan proposed by the service provider',
|
||||||
'Execution plan proposed by the service provider':
|
'Execution plan proposed by the service provider':
|
||||||
'Execution plan proposed by the service provider',
|
'Execution plan proposed by the service provider',
|
||||||
'Proceed to workspace': 'Proceed to workspace'
|
'Proceed to workspace': 'Proceed to workspace',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'Workspace': 'Workspace',
|
||||||
|
'Requests': 'Requests',
|
||||||
|
'Providers': 'Providers',
|
||||||
|
'Post': 'Post',
|
||||||
|
'Providing service': 'Providing service',
|
||||||
|
'Please go to profile page to add money receiving method': 'Please go to profile page to add money receiving method',
|
||||||
|
'History': 'History',
|
||||||
|
'Log out': 'Log out',
|
||||||
|
'Proposals': 'Proposals',
|
||||||
|
'Milestone(s)': 'Milestone(s)',
|
||||||
|
'Information': 'Information',
|
||||||
|
'Operation Complete': 'Operation Complete',
|
||||||
|
'Wait for completion': 'Wait for completion',
|
||||||
|
'Mission complete': 'Mission complete',
|
||||||
|
'Wait for payment': 'Wait for payment',
|
||||||
|
'Wait for confirmation': 'Wait for confirmation',
|
||||||
|
'Confirm receipt': 'Confirm receipt',
|
||||||
|
'Ready': 'Ready',
|
||||||
|
'Not available': 'Not available',
|
||||||
|
'Please input issue description': 'Please input issue description',
|
||||||
|
'day(s)': 'day(s)',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
<p class="error-msg">{{ message }}</p>
|
<p class="error-msg">{{ message }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<freeleaps-editor v-model:content="message" style="margin-top: 20px" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -34,8 +35,10 @@ import {
|
|||||||
// userProfileValidator,
|
// userProfileValidator,
|
||||||
} from '@/utils/index'
|
} from '@/utils/index'
|
||||||
import { signinActionEnum } from '@/types/index'
|
import { signinActionEnum } from '@/types/index'
|
||||||
|
import FreeleapsEditor from '../../components/FreeleapsEditor.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: { FreeleapsEditor },
|
||||||
name: 'FrontDoor',
|
name: 'FrontDoor',
|
||||||
props: {},
|
props: {},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@ -271,7 +271,7 @@
|
|||||||
class="profile-photo"
|
class="profile-photo"
|
||||||
alt="user portrait"
|
alt="user portrait"
|
||||||
id="personal-photo-operation-image"
|
id="personal-photo-operation-image"
|
||||||
src="@/assets/profile.png"
|
:src="userProfile.account.basic.photo.base64 ? userProfile.account.basic.photo.base64 : profileUrl"
|
||||||
/>
|
/>
|
||||||
<label class="profile-item-label" for="personal-photo-operation-image">{{
|
<label class="profile-item-label" for="personal-photo-operation-image">{{
|
||||||
$t('Portrait')
|
$t('Portrait')
|
||||||
@ -362,7 +362,7 @@
|
|||||||
class="user-portrait-img"
|
class="user-portrait-img"
|
||||||
id="personal-photo-operation-image"
|
id="personal-photo-operation-image"
|
||||||
alt="user portrait"
|
alt="user portrait"
|
||||||
src="@/assets/profile.png"
|
:src="userProfile.account.basic.photo.base64 ? userProfile.account.basic.photo.base64 : profileUrl"
|
||||||
v-tooltip
|
v-tooltip
|
||||||
title="Click to update"
|
title="Click to update"
|
||||||
@click="selectUserPhoto()"
|
@click="selectUserPhoto()"
|
||||||
@ -521,7 +521,7 @@
|
|||||||
<div class="panel-table-content">
|
<div class="panel-table-content">
|
||||||
<span class="panel-table-label">{{ $t('On Freeleaps') }}</span>
|
<span class="panel-table-label">{{ $t('On Freeleaps') }}</span>
|
||||||
<span class="panel-table-span">
|
<span class="panel-table-span">
|
||||||
{{ userProfile.achievemnt.activeness.days_of_staying_on }} day(s)
|
{{ userProfile.achievemnt.activeness.days_of_staying_on }} {{$t('day(s)')}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -724,7 +724,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import SvgIcon from '@/components/SvgIcon.vue'
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
import { moneyCollectionTypeEnum } from '@/types/index'
|
import { moneyCollectionTypeEnum } from '@/types/index'
|
||||||
|
import profileUrl from '@/assets/profile.png'
|
||||||
import { UserProfileApi, elementHandler, textAreaAujuster, passwordValidator } from '@/utils/index'
|
import { UserProfileApi, elementHandler, textAreaAujuster, passwordValidator } from '@/utils/index'
|
||||||
import FreeleapsEditor from '@/components/FreeleapsEditor.vue'
|
import FreeleapsEditor from '@/components/FreeleapsEditor.vue'
|
||||||
|
|
||||||
@ -764,6 +764,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
profileUrl,
|
||||||
userProfile: null,
|
userProfile: null,
|
||||||
message: null,
|
message: null,
|
||||||
accountNeedAttention: false,
|
accountNeedAttention: false,
|
||||||
@ -886,7 +887,7 @@ export default {
|
|||||||
updatePhoto(base64, filename) {
|
updatePhoto(base64, filename) {
|
||||||
UserProfileApi.updateUserPhoto(base64, filename)
|
UserProfileApi.updateUserPhoto(base64, filename)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.userProfile.account.basic.photo = response.data
|
this.userProfile.account.basic.photo = response.data.photo
|
||||||
this.updateLocalIdentityData()
|
this.updateLocalIdentityData()
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
class="conversation-container"
|
class="conversation-container"
|
||||||
:class="{
|
:class="{
|
||||||
selected: current_thread?.conversation?.id === conversation.id
|
selected: selConversation.id === conversation.id
|
||||||
}"
|
}"
|
||||||
@click="selectConversation(conversation)"
|
@click="selectConversation(conversation)"
|
||||||
>
|
>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<span class="conversation-last-update-date">{{
|
<span class="conversation-last-update-date">{{
|
||||||
getDateFromFulltimeString(conversation.create_time)
|
getDateFromFulltimeString(conversation.create_time)
|
||||||
}}</span>
|
}}</span>
|
||||||
<!-- <span v-if="unreadCountMapper()" class="conversation-unreadcount">2</span> -->
|
<!-- <span v-if="unreadCountMapper" class="conversation-unreadcount">{{unreadCountMapper}}</span> -->
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="conversation-summary-highlight-container">
|
<!-- <div class="conversation-summary-highlight-container">
|
||||||
{{ conversation.summary.last_message?.message_body }}
|
{{ conversation.summary.last_message?.message_body }}
|
||||||
@ -35,12 +35,12 @@
|
|||||||
{{ $t('Empty conversation') }}
|
{{ $t('Empty conversation') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="message-panel-container">
|
<div class="message-panel-container">
|
||||||
<div v-if="current_thread" class="message-thread-container">
|
<div v-if="messages && messages.length > 0" class="message-thread-container">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in current_thread.conversation.messages"
|
v-for="(item, index) in messages"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="message-item-container"
|
class="message-item-container"
|
||||||
:class="item.raw_data.sender_id == userIdentityNote ? 'me' : ''"
|
:class="item.sender_id == userIdentityNote ? 'me' : ''"
|
||||||
>
|
>
|
||||||
<div class="message-item-header-container">
|
<div class="message-item-header-container">
|
||||||
<img
|
<img
|
||||||
@ -49,17 +49,17 @@
|
|||||||
src="@/assets/profile.png"
|
src="@/assets/profile.png"
|
||||||
/>
|
/>
|
||||||
<span class="message-item-sender-fullname">
|
<span class="message-item-sender-fullname">
|
||||||
{{ item.sender_profile.first_name }}
|
{{ item.sender_firstname }}
|
||||||
{{ item.sender_profile.last_name }}
|
{{ item.sender_lastname }}
|
||||||
</span>
|
</span>
|
||||||
<span class="message-item-create-time">
|
<span class="message-item-create-time">
|
||||||
{{ getDateFromFulltimeString(item.raw_data.create_time) }}</span
|
{{ getDateFromFulltimeString(item.create_time) }}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-item-message-body">{{ item.raw_data.message_body }}</div>
|
<div class="message-item-message-body">{{ item.message_body }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!current_thread" class="message-thread-empty-container">
|
<div v-if="!messages || messages.length == 0" class="message-thread-empty-container">
|
||||||
{{ $t('Please choose conversation') }}
|
{{ $t('Please choose conversation') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="message-writing-panel-container">
|
<div class="message-writing-panel-container">
|
||||||
@ -68,7 +68,7 @@
|
|||||||
class="writing-message-input"
|
class="writing-message-input"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="writtenMessage"
|
v-model="writtenMessage"
|
||||||
@keypress.enter="sendMessage(current_thread.conversation.information.conversation_id)"
|
@keypress.enter="sendMessage(selConversation.id)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -85,39 +85,44 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.fetchConversations()
|
this.fetchConversations()
|
||||||
},
|
},
|
||||||
watch: {
|
// watch: {
|
||||||
conversations: {
|
// conversations: {
|
||||||
handler: function (val) {
|
// handler: function (val) {
|
||||||
if (val && val.length > 0) {
|
// if (val && val.length > 0) {
|
||||||
//this.current_thread = val[0]
|
// this.current_thread = val[0]
|
||||||
//this.clearUnreadMessageBy(val[0])
|
// this.clearUnreadMessageBy(val[0])
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
deep: false
|
// deep: false
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userIdentityNote: this.mnx_getUserIdentity(),
|
userIdentityNote: this.mnx_getUserIdentity(),
|
||||||
conversations: [],
|
conversations: [],
|
||||||
current_thread: null,
|
selConversation: null,
|
||||||
|
messages: [],
|
||||||
writtenMessage: null
|
writtenMessage: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// computed: {
|
computed: {
|
||||||
// unreadCountMapper() {
|
unreadCountMapper() {
|
||||||
// return this.$store.getters['basic/unreadCountMapper']
|
if (this.selConversation) {
|
||||||
// }
|
return this.$store.getters['basic/unreadCountMapper']
|
||||||
// },
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetchConversations() {
|
fetchConversations() {
|
||||||
MessageHubApi.fetchConversations(new Date('01 Jan 1970 00:00:00 GMT').toISOString())
|
MessageHubApi.fetchConversations(new Date('01 Jan 1970 00:00:00 GMT').toISOString())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.conversations = response.data.conversations
|
const conversations = response.data.conversations || []
|
||||||
//TEST
|
this.conversations = conversations
|
||||||
this.conversations.forEach((conversation) => {
|
if (conversations.length > 0) {
|
||||||
this.fetchMessageForConversation(conversation.id)
|
this.selectConversation(conversations[0])
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.mnx_backendErrorHandler(error)
|
this.mnx_backendErrorHandler(error)
|
||||||
@ -129,7 +134,7 @@ export default {
|
|||||||
new Date('01 Jan 1975 00:00:00 GMT').toISOString()
|
new Date('01 Jan 1975 00:00:00 GMT').toISOString()
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
messages = response.data
|
this.messages = response?.data || []
|
||||||
console.log('Received message for conversation:', conversation_id)
|
console.log('Received message for conversation:', conversation_id)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -137,12 +142,14 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
selectConversation(conversation) {
|
selectConversation(conversation) {
|
||||||
this.current_thread = conversation
|
this.selConversation = conversation
|
||||||
|
this.fetchMessageForConversation(conversation.id)
|
||||||
this.clearUnreadMessageBy(conversation)
|
this.clearUnreadMessageBy(conversation)
|
||||||
},
|
},
|
||||||
clearUnreadMessageBy(current) {
|
clearUnreadMessageBy(current) {
|
||||||
const sender = current.conversation.messages?.[0].raw_data.sender_id
|
const sender = current.initiator_id
|
||||||
if (sender) {
|
if (sender) {
|
||||||
|
console.log('clear unread message by:', current)
|
||||||
this.$store.dispatch('basic/readMessageBy', sender)
|
this.$store.dispatch('basic/readMessageBy', sender)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -150,7 +157,12 @@ export default {
|
|||||||
MessageHubApi.sendMessageToConversation(conversation_id, this.writtenMessage)
|
MessageHubApi.sendMessageToConversation(conversation_id, this.writtenMessage)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
let new_message = response.data
|
let new_message = response.data
|
||||||
this.current_thread.conversation.messages.push(new_message)
|
this.messages.push({
|
||||||
|
...new_message.raw_data,
|
||||||
|
sender_firstname: new_message.sender_profile.first_name,
|
||||||
|
sender_lastname: new_message.sender_profile.last_name,
|
||||||
|
sender_photo: new_message.sender_profile.photo
|
||||||
|
})
|
||||||
this.writtenMessage = null
|
this.writtenMessage = null
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
>{{ $t('Stay on Freeleaps') }}</label
|
>{{ $t('Stay on Freeleaps') }}</label
|
||||||
>
|
>
|
||||||
<span class="provider-stay-on-freeleaps-span" id="provider-stay-on-freeleaps">
|
<span class="provider-stay-on-freeleaps-span" id="provider-stay-on-freeleaps">
|
||||||
{{ provider.activeness_achievement.days_of_staying_on }} day(s)</span
|
{{ provider.activeness_achievement.days_of_staying_on }} {{$t('day(s)')}}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="provider-delivered-projects-container">
|
<div class="provider-delivered-projects-container">
|
||||||
@ -101,7 +101,7 @@
|
|||||||
$t('Project delivering time')
|
$t('Project delivering time')
|
||||||
}}</label>
|
}}</label>
|
||||||
<span class="dd-project-span" id="delivery-time-per-project">
|
<span class="dd-project-span" id="delivery-time-per-project">
|
||||||
{{ provider.provider_deliveries.delivering_time_per_project_in_day }} day(s)
|
{{ provider.provider_deliveries.delivering_time_per_project_in_day }} {{$t('day(s)')}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="dd-project-container">
|
<div class="dd-project-container">
|
||||||
|
|||||||
@ -119,7 +119,7 @@
|
|||||||
>
|
>
|
||||||
<span class="issuer-achievement-stay-content-text">
|
<span class="issuer-achievement-stay-content-text">
|
||||||
{{ request.issuer_achievement.activeness.days_of_staying_on }}
|
{{ request.issuer_achievement.activeness.days_of_staying_on }}
|
||||||
day(s)</span
|
{{$t('day(s)')}}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -199,7 +199,7 @@
|
|||||||
/>
|
/>
|
||||||
<label :for="`stage-duration-content-${index}`">{{ $t('Duration') }}</label>
|
<label :for="`stage-duration-content-${index}`">{{ $t('Duration') }}</label>
|
||||||
</div>
|
</div>
|
||||||
<span class="btn-start">day(s)</span>
|
<span class="btn-start">{{$t('day(s)')}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -266,7 +266,7 @@
|
|||||||
{{ $t('Total payment') }}:{{ summary.total_payment }} {{ summary.currency }}
|
{{ $t('Total payment') }}:{{ summary.total_payment }} {{ summary.currency }}
|
||||||
</span>
|
</span>
|
||||||
<span id="summary-total-duration-content">
|
<span id="summary-total-duration-content">
|
||||||
{{ $t('Total duration') }}:{{ summary.total_duration_in_days }} day(s)
|
{{ $t('Total duration') }}:{{ summary.total_duration_in_days }} {{$t('day(s)')}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -207,7 +207,7 @@
|
|||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion-body" v-if="isOngoingProject(project)">
|
<div class="accordion-body inline-accordion-body" v-if="isOngoingProject(project)">
|
||||||
<div class="project-invite-collaborator-containter">
|
<div class="project-invite-collaborator-containter">
|
||||||
<button
|
<button
|
||||||
class="accordion-button collapsed"
|
class="accordion-button collapsed"
|
||||||
@ -225,23 +225,8 @@
|
|||||||
data-bs-parent="#collapse-project-invite-collaborator"
|
data-bs-parent="#collapse-project-invite-collaborator"
|
||||||
>
|
>
|
||||||
<div class="project-invite-collaborator-form-container">
|
<div class="project-invite-collaborator-form-container">
|
||||||
<div class="project-invite-collaborator-form">
|
<input type="text" v-model="newInviteCollaborator[project_index]" :placeholder="$t('Input E-mail to invite other')" @keydown.enter="inviteCollaborator(project.project_id, newInviteCollaborator[project_index])">
|
||||||
<label class="project-item-label">{{
|
<svg-icon icon="msg-enter" class-name="project-invite-enter" />
|
||||||
$t('Input E-mail to invite other')
|
|
||||||
}}</label>
|
|
||||||
<input
|
|
||||||
class="project-invite-collaborator-input"
|
|
||||||
v-model="newInviteCollaborator[project_index]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="project-invite-collaborator-action-button"
|
|
||||||
@click="
|
|
||||||
inviteCollaborator(project.project_id, newInviteCollaborator[project_index])
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ $t('Submit') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -256,7 +241,7 @@
|
|||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="collapse-project-milestone"
|
aria-controls="collapse-project-milestone"
|
||||||
>
|
>
|
||||||
<div class="project-milestone-bar-container">
|
<div class="project-milestone-bar-container dashed-container">
|
||||||
<div class="project-milestone-bar-progress">
|
<div class="project-milestone-bar-progress">
|
||||||
<label class="project-item-label">{{ $t('Progress') }}</label>
|
<label class="project-item-label">{{ $t('Progress') }}</label>
|
||||||
<p class="project-item-text">
|
<p class="project-item-text">
|
||||||
@ -296,65 +281,72 @@
|
|||||||
class="accordion-collapse collapse"
|
class="accordion-collapse collapse"
|
||||||
data-bs-parent="#collapse-project-milestone"
|
data-bs-parent="#collapse-project-milestone"
|
||||||
>
|
>
|
||||||
<div class="project-milestones-containter">
|
<table class="project-milestones-table">
|
||||||
<div
|
<tbody v-for="milestone in project.project.progress.milestones" :key="milestone.index" :id="'project-milestone-' + milestone.index">
|
||||||
class="project-milestone-container"
|
<tr>
|
||||||
v-for="milestone in project.project.progress.milestones"
|
<td>
|
||||||
:key="milestone.index"
|
<div class="project-milestones-table-content">
|
||||||
:id="'project-milestone-' + milestone.index"
|
<span class="project-milestones-table-label">{{ $t('Milestone') }}</span>
|
||||||
>
|
<span class="project-milestones-table-span">{{ milestone.index }}</span>
|
||||||
<div class="project-milestone-index">
|
</div>
|
||||||
<label class="project-item-label">{{ $t('Milestone') }}</label>
|
</td>
|
||||||
<p class="project-item-text">
|
<td>
|
||||||
{{ milestone.index }}
|
<div class="project-milestones-table-content">
|
||||||
</p>
|
<span class="project-milestones-table-label">{{ $t('Description') }}</span>
|
||||||
</div>
|
<span class="project-milestones-table-span">{{ milestone.description }}</span>
|
||||||
<div class="project-milestone-description">
|
</div>
|
||||||
<label class="project-item-label">{{ $t('Description') }}</label>
|
</td>
|
||||||
<p class="project-item-text">
|
<td>
|
||||||
{{ milestone.description }}
|
<div class="project-milestones-table-content">
|
||||||
</p>
|
<span class="project-milestones-table-label">{{ $t('Status') }}</span>
|
||||||
</div>
|
<span class="project-milestones-table-span">{{ fromIntToMilestoneStatus(milestone.status) }}</span>
|
||||||
<div class="project-milestone-status">
|
</div>
|
||||||
<label class="project-item-label">{{ $t('Status') }}</label>
|
</td>
|
||||||
<p class="project-item-text">
|
<td>
|
||||||
{{ fromIntToMilestoneStatus(milestone.status) }}
|
<div class="project-milestones-table-content">
|
||||||
</p>
|
<span class="project-milestones-table-label">{{ $t('Payment') }}</span>
|
||||||
</div>
|
<span class="project-milestones-table-span">
|
||||||
<div class="project-milestone-payment">
|
{{ milestone.actual_paid }} / {{ milestone.expected_payment }}
|
||||||
<label class="project-item-label">{{ $t('Payment') }}</label>
|
{{ project.project.progress.payment_currency }}
|
||||||
<p class="project-item-text">
|
</span>
|
||||||
{{ milestone.actual_paid }} / {{ milestone.expected_payment }}
|
</div>
|
||||||
{{ project.project.progress.payment_currency }}
|
</td>
|
||||||
</p>
|
<td>
|
||||||
</div>
|
<div class="project-milestones-table-content">
|
||||||
<div class="project-milestone-update">
|
<span class="project-milestones-table-label">{{ $t('Update') }}</span>
|
||||||
<label class="project-item-label">{{ $t('Update') }}</label>
|
<span class="project-milestones-table-span">{{ getDateFromFulltimeString(milestone.update_time) }}</span>
|
||||||
<p class="project-item-text">
|
</div>
|
||||||
{{ getDateFromFulltimeString(milestone.update_time) }}
|
</td>
|
||||||
</p>
|
<td>
|
||||||
</div>
|
<div class="project-milestones-table-content">
|
||||||
<div class="project-milestone-action-button-container">
|
<span class="project-milestones-table-label">{{ $t('Action') }}</span>
|
||||||
<button
|
<button
|
||||||
class="project-milestone-action-button"
|
class="btn btn-link"
|
||||||
:disabled="isMilestoneActionButtonDisabled(project.project, milestone)"
|
:disabled="isMilestoneActionButtonDisabled(project.project, milestone)"
|
||||||
:hidden="isMilestoneActionButtonHidden(project.project, milestone)"
|
:hidden="isMilestoneActionButtonHidden(project.project, milestone)"
|
||||||
@click="handleMilestoneAction(project.project, milestone)"
|
@click="handleMilestoneAction(project.project, milestone)"
|
||||||
>
|
>
|
||||||
{{ fetchMilestoneActionButtonText(project.project, milestone) }}
|
{{ fetchMilestoneActionButtonText(project.project, milestone) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<!-- <span class="project-milestones-table-span">{{ getDateFromFulltimeString(milestone.update_time) }}</span> -->
|
||||||
<div v-if="this.qrCode.index === milestone.index">
|
</div>
|
||||||
<img width="100" height="100" :src="this.qrCode.imageUrl" />
|
</td>
|
||||||
<button
|
</tr>
|
||||||
class="project-milestone-payment-confirm-button"
|
<tr v-if="this.qrCode.index === milestone.index">
|
||||||
@click="handlePaymentAction(project.project, milestone)"
|
<td colspan="6">
|
||||||
>
|
<div class="project-milestones-qrcode-content">
|
||||||
{{ $t('Mark As Paid') }}
|
<img :src="this.qrCode.imageUrl" alt="freeleaps">
|
||||||
</button>
|
<button
|
||||||
</div>
|
class="project-milestones-qrcode-button"
|
||||||
</div>
|
@click="handlePaymentAction(project.project, milestone)"
|
||||||
</div>
|
>
|
||||||
|
{{ $t('Mark As Paid') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
@ -367,7 +359,7 @@
|
|||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="collapse-project-code"
|
aria-controls="collapse-project-code"
|
||||||
>
|
>
|
||||||
<div class="project-code-bar-container">
|
<div class="project-code-bar-container dashed-container">
|
||||||
<div class="project-code-git-status">
|
<div class="project-code-git-status">
|
||||||
<label class="project-item-label">{{ $t('Code Depot') }}</label>
|
<label class="project-item-label">{{ $t('Code Depot') }}</label>
|
||||||
<p class="project-item-text">{{ getGitStatus(project) }}</p>
|
<p class="project-item-text">{{ getGitStatus(project) }}</p>
|
||||||
@ -408,9 +400,12 @@
|
|||||||
{{ $t('copy git url') }}
|
{{ $t('copy git url') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="project-code-statistics-container">
|
<!-- <div class="project-code-statistics-container">
|
||||||
<button class="project-code-manage-button">{{ $t('Manage') }}</button>
|
<button class="project-code-manage-button">{{ $t('Manage') }}</button>
|
||||||
{{ $t('TO BE IMPLEMENTED.') }}
|
{{ $t('TO BE IMPLEMENTED.') }}
|
||||||
|
</div> -->
|
||||||
|
<div class="chart-container">
|
||||||
|
<v-chart :option="currentChartData" autoresize />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -425,7 +420,7 @@
|
|||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="collapse-project-issue"
|
aria-controls="collapse-project-issue"
|
||||||
>
|
>
|
||||||
<div class="project-issue-bar-container">
|
<div class="project-issue-bar-container dashed-container">
|
||||||
<div class="project-issue-open-issues">
|
<div class="project-issue-open-issues">
|
||||||
<label class="project-item-label">{{ $t('Open issues') }}</label>
|
<label class="project-item-label">{{ $t('Open issues') }}</label>
|
||||||
<p class="project-item-text">
|
<p class="project-item-text">
|
||||||
@ -452,11 +447,7 @@
|
|||||||
class="accordion-collapse collapse"
|
class="accordion-collapse collapse"
|
||||||
data-bs-parent="#collapse-project-issue"
|
data-bs-parent="#collapse-project-issue"
|
||||||
>
|
>
|
||||||
<!-- <div class="project-issue-statistics-container">
|
<div class="project-invite-collaborator-containter">
|
||||||
<button class="project-issue-manage-button">Manage</button>
|
|
||||||
TO BE IMPLEMENTED.
|
|
||||||
</div> -->
|
|
||||||
<div class="project-new-issue-containter">
|
|
||||||
<button
|
<button
|
||||||
class="accordion-button collapsed"
|
class="accordion-button collapsed"
|
||||||
type="button"
|
type="button"
|
||||||
@ -465,7 +456,7 @@
|
|||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="collapse-project-issue"
|
aria-controls="collapse-project-issue"
|
||||||
>
|
>
|
||||||
<div class="project-add-new-issue">+ {{ $t('Add Issue') }}</div>
|
<div class="project-invite-collaborator">+ {{ $t('Add Issue') }}</div>
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
id="collapse-project-new-issue"
|
id="collapse-project-new-issue"
|
||||||
@ -474,18 +465,9 @@
|
|||||||
>
|
>
|
||||||
<div class="project-issue-description-container">
|
<div class="project-issue-description-container">
|
||||||
<div class="project-issue-description">
|
<div class="project-issue-description">
|
||||||
<label class="project-item-label">{{
|
<label class="project-item-label">{{ $t('New issue description') }}</label>
|
||||||
$t('New issue description')
|
|
||||||
}}</label>
|
|
||||||
<textarea
|
|
||||||
class="project-new-issue-textarea"
|
|
||||||
type="text"
|
|
||||||
v-model="newIssueDescriptions[project_index]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="project-new-issue-action-container">
|
|
||||||
<button
|
<button
|
||||||
class="project-new-issue-action-button"
|
class="project-issue-description-btn"
|
||||||
@click="
|
@click="
|
||||||
postNewIssue(
|
postNewIssue(
|
||||||
project.request.product_id,
|
project.request.product_id,
|
||||||
@ -497,10 +479,17 @@
|
|||||||
{{ $t('Submit') }}
|
{{ $t('Submit') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<textarea
|
||||||
|
type="text"
|
||||||
|
v-model="newIssueDescriptions[project_index]"
|
||||||
|
/>
|
||||||
|
<!-- <div class="project-new-issue-action-container">
|
||||||
|
|
||||||
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="project-issues-containter">
|
<div>
|
||||||
<div
|
<div
|
||||||
class="project-issue-container"
|
class="project-issue-container"
|
||||||
v-for="(issue, issue_index) in project.project.issue.open_issues"
|
v-for="(issue, issue_index) in project.project.issue.open_issues"
|
||||||
@ -517,21 +506,23 @@
|
|||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="collapse-project-issue-details"
|
aria-controls="collapse-project-issue-details"
|
||||||
>
|
>
|
||||||
<div class="project-issue-title">
|
<div class="project-issue-header dashed-container">
|
||||||
<label class="project-item-label">{{ $t('Issue title') }}</label>
|
<div class="project-issue-title">
|
||||||
<p class="project-item-text">{{ issue.title }}</p>
|
<label class="project-item-label">{{ $t('Issue title') }}</label>
|
||||||
</div>
|
<p class="project-item-text">{{ issue.title }}</p>
|
||||||
<div class="project-issue-status">
|
</div>
|
||||||
<label class="project-item-label">{{ $t('Status') }}</label>
|
<div class="project-issue-status">
|
||||||
<p class="project-item-text">
|
<label class="project-item-label">{{ $t('Status') }}</label>
|
||||||
{{ fromIntToProjectIssueStatus(issue.status) }}
|
<p class="project-item-text">
|
||||||
</p>
|
{{ fromIntToProjectIssueStatus(issue.status) }}
|
||||||
</div>
|
</p>
|
||||||
<div class="project-issue-update">
|
</div>
|
||||||
<label class="project-item-label">{{ $t('Last updated') }}</label>
|
<div class="project-issue-update">
|
||||||
<p class="project-item-text">
|
<label class="project-item-label">{{ $t('Last updated') }}</label>
|
||||||
{{ getDateFromFulltimeString(issue.update_time) }}
|
<p class="project-item-text">
|
||||||
</p>
|
{{ getDateFromFulltimeString(issue.update_time) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
@ -541,34 +532,32 @@
|
|||||||
:data-bs-parent="'#collapse-project-issue-details' + issue_index"
|
:data-bs-parent="'#collapse-project-issue-details' + issue_index"
|
||||||
>
|
>
|
||||||
<div class="project-issue-description-container">
|
<div class="project-issue-description-container">
|
||||||
<label class="project-item-label">{{
|
<div class="project-issue-description">
|
||||||
$t('Issue description')
|
<label class="project-item-label">{{ $t('Issue description') }}</label>
|
||||||
}}</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>
|
<p class="project-item-text">{{ issue.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="project-issue-action-container">
|
|
||||||
<button
|
|
||||||
:hidden="!showIssueActionButton(project.project, issue, 'Resolve')"
|
|
||||||
class="project-issue-action-button"
|
|
||||||
@click="setProjectIssueStatus(issue.id, 1)"
|
|
||||||
>
|
|
||||||
{{ $t('Resolve') }}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
:hidden="!showIssueActionButton(project.project, issue, 'Confirm')"
|
|
||||||
class="project-issue-action-button"
|
|
||||||
@click="setProjectIssueStatus(issue.id, 2)"
|
|
||||||
>
|
|
||||||
{{ $t('Confirm') }}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
:hidden="!showIssueActionButton(project.project, issue, 'Reopen')"
|
|
||||||
class="project-issue-action-button"
|
|
||||||
@click="setProjectIssueStatus(issue.id, 0)"
|
|
||||||
>
|
|
||||||
{{ $t('Reopen') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -603,8 +592,15 @@ import {
|
|||||||
convertIntoToMilestoneStatus,
|
convertIntoToMilestoneStatus,
|
||||||
convertIntoToProjectIssueStatus
|
convertIntoToProjectIssueStatus
|
||||||
} from '@/types/index'
|
} from '@/types/index'
|
||||||
|
import { use } from 'echarts/core';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { LineChart } from 'echarts/charts';
|
||||||
|
import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components';
|
||||||
|
import VChart from 'vue-echarts';
|
||||||
|
use([ CanvasRenderer, LineChart, LegendComponent, GridComponent, TooltipComponent ]);
|
||||||
export default {
|
export default {
|
||||||
name: 'Workspace',
|
name: 'Workspace',
|
||||||
|
components: { VChart },
|
||||||
props: {},
|
props: {},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchView()
|
this.fetchView()
|
||||||
@ -620,7 +616,26 @@ export default {
|
|||||||
imageUrl: null,
|
imageUrl: null,
|
||||||
index: null
|
index: null
|
||||||
},
|
},
|
||||||
|
currentChartData: {
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||||
|
type: 'line',
|
||||||
|
areaStyle: {color: 'rgba(63,73,255,0.1)'},
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
connectNulls: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
downstream_web_socket: null
|
downstream_web_socket: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -670,14 +685,14 @@ export default {
|
|||||||
getTitleForItemInfo(project) {
|
getTitleForItemInfo(project) {
|
||||||
switch (project.status) {
|
switch (project.status) {
|
||||||
case projectStatusEnum.RECRUITING:
|
case projectStatusEnum.RECRUITING:
|
||||||
return 'Proposals'
|
return this.$t('Proposals')
|
||||||
case projectStatusEnum.PENDING:
|
case projectStatusEnum.PENDING:
|
||||||
case projectStatusEnum.REJECTED:
|
case projectStatusEnum.REJECTED:
|
||||||
return 'Issuer'
|
return this.$('Issuer')
|
||||||
case projectStatusEnum.ONGOING:
|
case projectStatusEnum.ONGOING:
|
||||||
return 'Milestone(s)'
|
return this.$t('Milestone(s)')
|
||||||
default:
|
default:
|
||||||
return 'Information'
|
return this.$t('Information')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getContentForItemInfo(project) {
|
getContentForItemInfo(project) {
|
||||||
@ -779,6 +794,10 @@ export default {
|
|||||||
WorksapceApi.setMillestoneStatus(project.id, milestone.index, milestoneStatusEnum.PAID)
|
WorksapceApi.setMillestoneStatus(project.id, milestone.index, milestoneStatusEnum.PAID)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.fetchView()
|
this.fetchView()
|
||||||
|
this.qrCode = {
|
||||||
|
imageUrl: null,
|
||||||
|
index: null
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.mnx_backendErrorHandler(error)
|
this.mnx_backendErrorHandler(error)
|
||||||
@ -786,25 +805,25 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchMilestoneActionButtonText(project, milestone) {
|
fetchMilestoneActionButtonText(project, milestone) {
|
||||||
if (milestone.index < project.current_milestone) {
|
if (milestone.index < project.current_milestone) {
|
||||||
return 'Operation Complete'
|
return this.$t('Operation Complete')
|
||||||
} else if (milestone.index === project.current_milestone) {
|
} else if (milestone.index === project.current_milestone) {
|
||||||
if (milestone.status === milestoneStatusEnum.IMPLEMENTING) {
|
if (milestone.status === milestoneStatusEnum.IMPLEMENTING) {
|
||||||
if (project.issuers.includes(project.current_user_id)) {
|
if (project.issuers.includes(project.current_user_id)) {
|
||||||
return 'Wait for completion'
|
return this.$t('Wait for completion')
|
||||||
} else {
|
} else {
|
||||||
return 'Mission complete'
|
return this.$t('Mission complete')
|
||||||
}
|
}
|
||||||
} else if (milestone.status === milestoneStatusEnum.OUTSTANDING) {
|
} else if (milestone.status === milestoneStatusEnum.OUTSTANDING) {
|
||||||
if (project.issuers.includes(project.current_user_id)) {
|
if (project.issuers.includes(project.current_user_id)) {
|
||||||
return 'Payment'
|
return this.$t('Payment')
|
||||||
} else {
|
} else {
|
||||||
return 'Wait for payment'
|
return this.$t('Wait for payment')
|
||||||
}
|
}
|
||||||
} else if (milestone.status === milestoneStatusEnum.PAID) {
|
} else if (milestone.status === milestoneStatusEnum.PAID) {
|
||||||
if (project.issuers.includes(project.current_user_id)) {
|
if (project.issuers.includes(project.current_user_id)) {
|
||||||
return 'Wait for confirmation'
|
return this.$t('Wait for confirmation')
|
||||||
} else {
|
} else {
|
||||||
return 'Confirm receipt'
|
return this.$t('Confirm receipt')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -812,7 +831,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getGitStatus(project) {
|
getGitStatus(project) {
|
||||||
return project.project?.code?.git_url ? 'Ready' : 'Not available'
|
return project.project?.code?.git_url ? this.$t('Ready') : this.$t('Not available')
|
||||||
},
|
},
|
||||||
copyCodeGit(project) {
|
copyCodeGit(project) {
|
||||||
if (project.project.code.git_url) {
|
if (project.project.code.git_url) {
|
||||||
@ -888,7 +907,7 @@ export default {
|
|||||||
|
|
||||||
postNewIssue(product_id, project_id, issue_description) {
|
postNewIssue(product_id, project_id, issue_description) {
|
||||||
if (issue_description == null || issue_description == '') {
|
if (issue_description == null || issue_description == '') {
|
||||||
alert('Please input issue description')
|
alert(this.$t('Please input issue description'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
WorksapceApi.postIssueForProduct(product_id, project_id, issue_description)
|
WorksapceApi.postIssueForProduct(product_id, project_id, issue_description)
|
||||||
@ -911,17 +930,17 @@ export default {
|
|||||||
showIssueActionButton(project, issue, button_text) {
|
showIssueActionButton(project, issue, button_text) {
|
||||||
switch (issue.status) {
|
switch (issue.status) {
|
||||||
case projectIssueStatusEnum.OPEN:
|
case projectIssueStatusEnum.OPEN:
|
||||||
if (button_text === 'Resolve') {
|
if (button_text === this.$t('Resolve')) {
|
||||||
return project.providers.includes(project.current_user_id)
|
return project.providers.includes(project.current_user_id)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
if (button_text === 'Reopen' || button_text === 'Confirm') {
|
if (button_text === this.$t('Reopen') || button_text === this.$t('Confirm')) {
|
||||||
return project.issuers.includes(project.current_user_id)
|
return project.issuers.includes(project.current_user_id)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case projectIssueStatusEnum.CLOSED:
|
case projectIssueStatusEnum.CLOSED:
|
||||||
if (button_text === 'Reopen') {
|
if (button_text === this.$t('Reopen')) {
|
||||||
return project.issuers.includes(project.current_user_id)
|
return project.issuers.includes(project.current_user_id)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -1219,6 +1238,76 @@ export default {
|
|||||||
@extend .initiate-button;
|
@extend .initiate-button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-milestones-table {
|
||||||
|
border: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.project-milestones-table-content {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.project-milestones-table-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666666;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
.project-milestones-table-span {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #242424;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.btn-link {
|
||||||
|
padding: 0;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-milestones-qrcode-content {
|
||||||
|
padding: 32px 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 154px;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-milestones-qrcode-button {
|
||||||
|
padding: 2px 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $primary;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid $primary;
|
||||||
|
background-color: #F3F6FF;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
border-bottom: 1px solid #e1e1e1;
|
||||||
|
|
||||||
|
td:first-child {
|
||||||
|
.project-milestones-table-content {
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
td:last-child {
|
||||||
|
.project-milestones-table-content {
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.project-milestones-containter {
|
.project-milestones-containter {
|
||||||
@extend .container;
|
@extend .container;
|
||||||
@extend .border;
|
@extend .border;
|
||||||
@ -1260,12 +1349,13 @@ export default {
|
|||||||
|
|
||||||
.project-code-git-url-container {
|
.project-code-git-url-container {
|
||||||
@extend .flex-row-container;
|
@extend .flex-row-container;
|
||||||
@extend .justify-content-start;
|
@extend .justify-content-end;
|
||||||
@extend .my-3;
|
@extend .my-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-code-copy-git-url {
|
.project-code-copy-git-url {
|
||||||
@extend .initiate-button;
|
@extend .btn;
|
||||||
|
@extend .btn-link;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-code-statistics-container {
|
.project-code-statistics-container {
|
||||||
@ -1304,8 +1394,33 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.project-issue-description-container {
|
.project-issue-description-container {
|
||||||
@extend .text-start;
|
padding: 12px;
|
||||||
@extend .flex-grow-1;
|
|
||||||
|
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 {
|
.project-issue-action-container {
|
||||||
@ -1313,7 +1428,8 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.project-issue-action-button {
|
.project-issue-action-button {
|
||||||
@extend .initiate-button;
|
@extend .btn;
|
||||||
|
@extend .btn-link;
|
||||||
@extend .float-end;
|
@extend .float-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1323,15 +1439,14 @@ export default {
|
|||||||
@extend .p-3;
|
@extend .p-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-issues-containter {
|
|
||||||
@extend .container;
|
|
||||||
@extend .border;
|
|
||||||
}
|
|
||||||
|
|
||||||
.project-issue-container {
|
.project-issue-container {
|
||||||
@extend .justify-content-between;
|
@extend .justify-content-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-issue-header {
|
||||||
|
display: flex
|
||||||
|
}
|
||||||
|
|
||||||
.project-issue-title {
|
.project-issue-title {
|
||||||
@extend .text-start;
|
@extend .text-start;
|
||||||
@extend .flex-grow-1;
|
@extend .flex-grow-1;
|
||||||
@ -1357,20 +1472,54 @@ export default {
|
|||||||
width: 6vw;
|
width: 6vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline-accordion-body {padding: 0 !important}
|
||||||
|
|
||||||
.project-invite-collaborator-containter {
|
.project-invite-collaborator-containter {
|
||||||
@extend .container;
|
border-bottom: 1px solid #e1e1e1;
|
||||||
@extend .border;
|
|
||||||
|
.accordion-button {
|
||||||
|
// border: 1px solid $primary;
|
||||||
|
// color: $primary;
|
||||||
|
// background-color: #F3F6FF;
|
||||||
|
padding: 12px !important;
|
||||||
|
&::after {display: none}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-invite-collaborator {
|
.project-invite-collaborator {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@extend .initiate-button;
|
@extend .initiate-button;
|
||||||
|
color: $primary;
|
||||||
|
background-color: #F3F6FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-invite-collaborator-form-container {
|
.project-invite-collaborator-form-container {
|
||||||
@extend .container;
|
margin: 12px;
|
||||||
height: 100px;
|
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 {
|
.project-invite-collaborator-form {
|
||||||
@ -1386,4 +1535,8 @@ export default {
|
|||||||
@extend .initiate-button;
|
@extend .initiate-button;
|
||||||
@extend .float-end;
|
@extend .float-end;
|
||||||
}
|
}
|
||||||
|
.chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 357px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
>
|
>
|
||||||
<div class="execution-duration-containter" id="execution-duration-containter">
|
<div class="execution-duration-containter" id="execution-duration-containter">
|
||||||
<span class="execution-duration-span" id="execution-duration-span">
|
<span class="execution-duration-span" id="execution-duration-span">
|
||||||
{{ proposal.duration_in_day }} day(s)</span
|
{{ proposal.duration_in_day }} {{$t('day(s)')}}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -23,7 +23,7 @@ const basicStore = {
|
|||||||
() => {
|
() => {
|
||||||
// keep
|
// keep
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
state.downstream_web_socket.send(1)
|
state.downstream_web_socket.send('keep alive')
|
||||||
}, 1000 * 60)
|
}, 1000 * 60)
|
||||||
console.log('downstream_web_socket open')
|
console.log('downstream_web_socket open')
|
||||||
},
|
},
|
||||||
@ -35,7 +35,9 @@ const basicStore = {
|
|||||||
} else {
|
} else {
|
||||||
unread = 1
|
unread = 1
|
||||||
}
|
}
|
||||||
state.unreadCountMapper[data.sender_id] = unread
|
const ucm = Object.assign({}, state.unreadCountMapper)
|
||||||
|
ucm[data.sender_id] = unread
|
||||||
|
state.unreadCountMapper = ucm
|
||||||
console.log('downstream_web_socket onmessage: ', data, state.unreadCountMapper)
|
console.log('downstream_web_socket onmessage: ', data, state.unreadCountMapper)
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ class WsConnectionFactory {
|
|||||||
this.socket.onmessage = onMessage
|
this.socket.onmessage = onMessage
|
||||||
this.socket.onerror = onError
|
this.socket.onerror = onError
|
||||||
this.socket.onclose = onClose
|
this.socket.onclose = onClose
|
||||||
|
return this.socket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
export { ValueChecker } from './checker'
|
export { ValueChecker } from './checker'
|
||||||
export { DateUtils } from './dateUtils'
|
export { DateUtils } from './dateUtils'
|
||||||
export { OIDUtils } from './oidUtils'
|
export { OIDUtils } from './oidUtils'
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export { passwordValidator } from './passwordValidator'
|
export { passwordValidator } from './passwordValidator'
|
||||||
export { applicantValidator } from './applicantValidator'
|
export { applicantValidator } from './applicantValidator'
|
||||||
|
export { websiteValidator } from './websiteValidator'
|
||||||
|
|||||||
@ -22,5 +22,5 @@ class WebsiteValidator extends TextValidator {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const websiteValidator = new WebsiteValidator()
|
||||||
export { WebsiteValidator }
|
export { websiteValidator }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user