update
@ -11,13 +11,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@vueup/vue-quill": "^1.2.0",
|
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bootstrap": "^5.3.1",
|
"bootstrap": "^5.3.1",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"pdfjs-dist": "^4.2.67",
|
"pdfjs-dist": "3.5.141",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"quill": "^1.3.7",
|
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.2.4",
|
||||||
"vuex": "^4.1.0"
|
"vuex": "^4.1.0"
|
||||||
|
|||||||
@ -104,3 +104,17 @@ p {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
.btn-link {text-decoration: none; color: $primary;}
|
||||||
|
.dropdown-menu {border: none; box-shadow: 0px 0px 24px 0px #D4D3E380; padding: 0; overflow: hidden;
|
||||||
|
.btn-link {text-decoration: none; height: 33px; width: 100%; color: #0D1637; font-size: 14px; text-align: left; border-radius: 0;
|
||||||
|
&:hover {background-color: #F3F6FF;}
|
||||||
|
&.active {background-color: #1748F8; color: white;}
|
||||||
|
}
|
||||||
|
.dropdown-new {color: #1748F8;
|
||||||
|
&:hover {background-color: white;}
|
||||||
|
}
|
||||||
|
.dropdown-new-input-container {padding: 6px 12px; position: relative;
|
||||||
|
input {border: 1px solid #E7E8EB; box-shadow: none; border-radius: 3px; padding: 0 20px 0 5px; height: 22px; font-size: 14px;}
|
||||||
|
.dropdown-new-input-icon {width: 16px; height: 16px; padding: 3px; color: #3D455F; background-color: #EEEFF1; border-radius: 3px; position: absolute; top: 10px; right: 15px}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
314
frontend/src/components/FreeleapsEditor.vue
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
<template>
|
||||||
|
<div class="freeleaps-editor">
|
||||||
|
<div v-if="!disabled" class="editor-control">
|
||||||
|
<div v-for="(item, index) in iconList" :key="index" class="editor-item">
|
||||||
|
<button class="item-icon" :class="{'activity': item.choose}" :data-info="item.name" @click="iconClick($event, item.type)" :data-bs-toggle="item.drop ? 'dropdown' : ''" data-bs-auto-close="outside" aria-expanded="false">
|
||||||
|
<svg-icon :icon="item.icon" class-name="icon" />
|
||||||
|
</button>
|
||||||
|
<div class="dropmenu drop-style" v-if="item.type === 'style'">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'p', 'style')"><p>正文</p></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'pre', 'style')"><pre>code</pre></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'blockquote', 'style')"><blockquote>引用</blockquote></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'h1', 'style')"><h1>标题一</h1></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'h2', 'style')"><h2>标题二</h2></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'h3', 'style')"><h3>标题三 </h3></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'h4', 'style')"><h4>标题四 </h4></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'h5', 'style')"><h5>标题五 </h5></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'h6', 'style')"><h6>标题六</h6></a>
|
||||||
|
</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>居中</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyLeft', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-alignleft"></i>
|
||||||
|
<span>左对齐</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyRight', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-alignright"></i>
|
||||||
|
<span>右对齐</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" @click="iconClick($event, 'justifyFull', 'alignjustify')">
|
||||||
|
<i class="iconfont icon-alignjustify"></i>
|
||||||
|
<span>默认对齐</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="editor-body" :contenteditable="!disabled" spellcheck="false" ref="editor" v-html="content" @blur="updateAction" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
export default {
|
||||||
|
name: 'FreeleapsEditor',
|
||||||
|
props: {
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:content'],
|
||||||
|
components: { SvgIcon },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedRange: '',
|
||||||
|
iconList: [
|
||||||
|
// {
|
||||||
|
// name: '标签', // hover名字
|
||||||
|
// type: 'style', // 点击事件处理
|
||||||
|
// icon: 'fe-paragraph', // 图标样式
|
||||||
|
// drop: true, // 是否有下拉菜单
|
||||||
|
// canChoose: true, // 是否被选中
|
||||||
|
// choose: false
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: '粗体',
|
||||||
|
type: 'bold',
|
||||||
|
icon: 'fe-bold',
|
||||||
|
drop: false,
|
||||||
|
canChoose: true,
|
||||||
|
choose: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '斜体',
|
||||||
|
type: 'italic',
|
||||||
|
icon: 'fe-italic',
|
||||||
|
drop: false,
|
||||||
|
canChoose: true,
|
||||||
|
choose: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '下划线',
|
||||||
|
type: 'underline',
|
||||||
|
icon: 'fe-underline',
|
||||||
|
drop: false,
|
||||||
|
canChoose: true,
|
||||||
|
choose: false
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// name: '删除线',
|
||||||
|
// type: 'strike',
|
||||||
|
// icon: 'fe-strike',
|
||||||
|
// drop: false,
|
||||||
|
// canChoose: true,
|
||||||
|
// choose: false
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '清除样式',
|
||||||
|
// type: 'clear',
|
||||||
|
// icon: 'fe-clear',
|
||||||
|
// drop: false,
|
||||||
|
// canChoose: false,
|
||||||
|
// choose: false
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '字体颜色',
|
||||||
|
// type: 'fontFamily',
|
||||||
|
// icon: 'fe-char',
|
||||||
|
// drop: false,
|
||||||
|
// canChoose: true,
|
||||||
|
// choose: false
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: '无序列表',
|
||||||
|
type: 'unorderedlist',
|
||||||
|
icon: 'fe-unorderedlist',
|
||||||
|
drop: false,
|
||||||
|
canChoose: true,
|
||||||
|
choose: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '有序列表',
|
||||||
|
type: 'orderedlist',
|
||||||
|
icon: 'fe-orderedlist',
|
||||||
|
drop: false,
|
||||||
|
canChoose: true,
|
||||||
|
choose: false
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// name: '对齐方式',
|
||||||
|
// type: 'alignjustify',
|
||||||
|
// icon: 'fe-alignjustify',
|
||||||
|
// drop: true,
|
||||||
|
// canChoose: true,
|
||||||
|
// choose: false
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
iconClick (event, type, dropType) {
|
||||||
|
event.preventDefault()
|
||||||
|
this.$refs.editor.focus()
|
||||||
|
this.selectedRange = this.getSelect()
|
||||||
|
this.restoreSelection()
|
||||||
|
this.changeStyle(type)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (dropType) {
|
||||||
|
type = dropType
|
||||||
|
}
|
||||||
|
let arr = []
|
||||||
|
arr = this.iconList.map((val) => {
|
||||||
|
if (type === val.type && val.canChoose) {
|
||||||
|
val.choose = val.choose ? false : true
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
})
|
||||||
|
|
||||||
|
if (type === 'clear') {
|
||||||
|
arr = this.iconList.map((val) => {
|
||||||
|
val.choose = false
|
||||||
|
return val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.iconList = arr
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getSelect() {
|
||||||
|
if (window.getSelection) {
|
||||||
|
var sel = window.getSelection()
|
||||||
|
if (sel.rangeCount > 0) {
|
||||||
|
return sel.getRangeAt(0)
|
||||||
|
}
|
||||||
|
} else if (document.selection) {
|
||||||
|
return document.selection.createRange()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
// 改变选取的内容
|
||||||
|
changeStyle(type) {
|
||||||
|
switch (type) {
|
||||||
|
case 'bold':
|
||||||
|
document.execCommand('bold', false)
|
||||||
|
break
|
||||||
|
case 'underline':
|
||||||
|
document.execCommand('underline', false)
|
||||||
|
break
|
||||||
|
case 'strike':
|
||||||
|
document.execCommand('strikeThrough', false)
|
||||||
|
break
|
||||||
|
case 'italic':
|
||||||
|
document.execCommand('italic', false)
|
||||||
|
break
|
||||||
|
case 'clear':
|
||||||
|
document.execCommand('removeFormat', false)
|
||||||
|
break
|
||||||
|
case 'unorderedlist':
|
||||||
|
document.execCommand('insertUnorderedList', false)
|
||||||
|
break
|
||||||
|
case 'orderedlist':
|
||||||
|
document.execCommand('insertorderedList', false)
|
||||||
|
break
|
||||||
|
case 'h1':
|
||||||
|
case 'h2':
|
||||||
|
case 'h3':
|
||||||
|
case 'h4':
|
||||||
|
case 'h5':
|
||||||
|
case 'h6':
|
||||||
|
case 'p':
|
||||||
|
case 'pre':
|
||||||
|
case 'blockquote':
|
||||||
|
document.execCommand('formatBlock', false, type)
|
||||||
|
break
|
||||||
|
case 'justifyCenter':
|
||||||
|
case 'justifyFull':
|
||||||
|
case 'justifyLeft':
|
||||||
|
case 'justifyRight':
|
||||||
|
document.execCommand(type, false)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('none')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
restoreSelection() {
|
||||||
|
var selection = window.getSelection()
|
||||||
|
if (this.selectedRange) {
|
||||||
|
try {
|
||||||
|
selection.removeAllRanges()
|
||||||
|
} catch (ex) {
|
||||||
|
document.body.createTextRange().select()
|
||||||
|
document.selection.empty()
|
||||||
|
}
|
||||||
|
selection.addRange(this.selectedRange)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateAction($event) {
|
||||||
|
let html = $event.target.innerHTML || ''
|
||||||
|
this.$emit('update:content', html)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.freeleaps-editor {position: relative; background-color: #fff; border-radius: 4px; border: 1px solid #a9a9a9; box-shadow: 0 1px 1px rgba(0, 0, 0, .05); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6, p, a{ font-family: inherit; font-weight: 500; line-height: 1.1; color: inherit; margin: 0; text-decoration: none; }
|
||||||
|
code, kbd, pre, samp { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; }
|
||||||
|
.editor-control { display: flex; flex-flow: row wrap; min-height: 40px; color: #333; border-bottom: 1px solid transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; background-color: #f5f5f5; border-color: #ddd; }
|
||||||
|
.dropmenu { display: none; position: absolute; top: 32px; left: 0; min-width: 160px; padding: 5px 0; margin: 2px 0 0; font-size: 14px; text-align: left; list-style: none; background-color: #fff; background-clip: padding-box; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, .15); border-radius: 4px; box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||||
|
ul {padding: 10px; margin-bottom: 0;}
|
||||||
|
ul li { text-align: left; list-style: none;
|
||||||
|
a { display: block; padding: 5px 10px; white-space: nowrap; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.drop-align { min-width: 100px; }
|
||||||
|
.editor-body { height: 300px; padding: 10px; color: #000; background-color: #fff; overflow: auto; outline: none; text-align: left; border-radius: 4px;
|
||||||
|
p { font-size: 14px; color: #68747f; margin: 0 0 10px; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-item { position: relative; vertical-align: middle; border: 1px solid #ccc; cursor: pointer; line-height: 20px; border-radius: 3px; margin: 4px 0 4px 5px; background-color: white;
|
||||||
|
.item-icon { position: relative; display: inline-block; width: 100%; height: 100%; padding: 2px 10px; font-size: 18px; font-weight: normal; white-space: nowrap; vertical-align: middle; touch-action: manipulation; cursor: pointer; user-select: none; background-color: #fff; border: 1px solid white; outline: none; transition: all 0.1s ease-out; border-radius: 3px;
|
||||||
|
&::after { position: absolute; top: 0; content: attr(data-info); top: 40px; left: 20px; padding: 5px 8px; border-radius: 4px; white-space: nowrap; line-height: 1.5; font-size: 13px; color: #fff; background: rgba(0,0,0,.8); -webkit-transform: translateX(-50%); transform: translateX(-50%); visibility: hidden; opacity: .9; letter-spacing: 1px; z-index: 9999; }
|
||||||
|
&::before { position: absolute; content: ""; top: 35px; left: 20px; width: 0; height: 0; margin: 0 0 0 -6px; font-size: 0; color: rgba(0,0,0,.8); border-bottom: 6px solid currentColor; border-left: 6px solid transparent; border-right: 6px solid transparent; visibility: hidden; opacity: .9; z-index: 9999; }
|
||||||
|
&:hover, &.activity{ color: #333; background-color: #e6e6e6; border-color: #e6e6e6; }
|
||||||
|
&:hover:after, &:hover:before { visibility: visible; }
|
||||||
|
&.activity + .dropmenu { display: block; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.freeleaps-editor blockquote { padding: 10px 20px; font-size: 17.5px; border-left: 5px solid #f86466; background: white; }
|
||||||
|
.freeleaps-editor pre { display: block; padding: 9.5px; font-size: 13px; line-height: 1.42857143; color: #333; word-break: break-all; word-wrap: break-word; background-color: #f5f5f5; border: 1px solid #ccc; border-radius: 4px; }
|
||||||
|
.editor-body blockquote { margin-bottom: 30px; }
|
||||||
|
.editor-body pre { margin-bottom: 10px; }
|
||||||
|
.editor-body ul { padding-left: 40px; list-style-type: disc; }
|
||||||
|
.editor-body ol { padding-left: 40px; }
|
||||||
|
</style>
|
||||||
70
frontend/src/components/InputSelector.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<div class="input-selector-container">
|
||||||
|
<div class="input-selector-btn" data-bs-toggle="dropdown" aria-expanded="false" id="input-selector-btn">
|
||||||
|
<span>{{selected || ''}}</span>
|
||||||
|
<svg-icon icon="dropdown" class-name="selector-dropdown-icon" />
|
||||||
|
</div>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="input-selector-btn">
|
||||||
|
<li>
|
||||||
|
<button v-if="!inputing" class="btn btn-link dropdown-new" @click="newAction">+ NEW</button>
|
||||||
|
<div v-if="inputing" class="dropdown-new-input-container">
|
||||||
|
<input type="text" v-model="newval" @keyup.enter="newItemAction">
|
||||||
|
<svg-icon v-if="newval" icon="msg-enter" class-name="dropdown-new-input-icon" />
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li v-for="item in selectList" :key="item">
|
||||||
|
<button class="btn btn-link" @click="selectItem(item)" :class="item==selected ? 'active' : ''">{{item}}</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
export default {
|
||||||
|
name: 'InputSelector',
|
||||||
|
props: {
|
||||||
|
selectList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inputing: true,
|
||||||
|
newval: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() { },
|
||||||
|
components: {SvgIcon},
|
||||||
|
methods: {
|
||||||
|
newAction($event) {
|
||||||
|
$event.stopPropagation()
|
||||||
|
this.newval = ''
|
||||||
|
this.inputing = true
|
||||||
|
},
|
||||||
|
selectItem(item) {
|
||||||
|
this.$emit('selectedChange', {selected: item, isNew: false})
|
||||||
|
},
|
||||||
|
newItemAction() {
|
||||||
|
if (!this.newval) return
|
||||||
|
this.$emit('selectedChange', {selected: this.newval, isNew: this.selectList.indexOf(this.newval) === -1})
|
||||||
|
this.newval = ''
|
||||||
|
this.inputing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.input-selector-container {width: fit-content; height: fit-content; position: relative;
|
||||||
|
.input-selector-btn {width: 153px; height: 30px; display: flex; align-items: center; overflow: hidden; cursor: pointer; border: 1px solid #E7E8EB; border-radius: 3px; padding: 0 3px 0 5px;
|
||||||
|
>span {font-size: 18px; font-weight: 500; color: #242424; flex: 1; text-align: left;}
|
||||||
|
.selector-dropdown-icon {color: #242424; padding: 3px;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,81 +1,81 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pdf-reader">
|
<div id="pdf-container" class="pdf-container">
|
||||||
<canvas ref="canvas"></canvas>
|
<canvas id="theCanvas"></canvas>
|
||||||
|
<div class="oprate">
|
||||||
|
<button class="btn btn-link" @click="prev">prev</button>
|
||||||
|
<span> {{ currentPage }} / {{ numPages }} </span>
|
||||||
|
<button class="btn btn-link" @click="next">next</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// import { getDocument } from 'pdfjs-dist'
|
import * as PDFJS from "pdfjs-dist/build/pdf"
|
||||||
import * as PDFJS from 'pdfjs-dist'
|
import { WorksapceApi } from '@/utils/index'
|
||||||
// import pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
|
PDFJS.GlobalWorkerOptions.workerSrc = import('pdfjs-dist/build/pdf.worker.entry')
|
||||||
import { ContentApi } from '@/utils/index'
|
|
||||||
// PDFJS.GlobalWorkerOptions.workerSrc = import('pdfjs-dist/build/pdf.worker')
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PDFReader',
|
name: 'PDFReader',
|
||||||
props: {
|
props: {
|
||||||
document: { type: String, default: '' }
|
document: { type: String, default: '' }
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loadingTask: null,
|
||||||
|
currentPage: 1,
|
||||||
|
numPages: 0,
|
||||||
|
selectedPage: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.renderPDF()
|
this.renderPDF()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async renderPDF() {
|
renderPage (num) {
|
||||||
// const response = await DocumentApi.download(this.document)
|
const canvas = document.getElementById("theCanvas");
|
||||||
const response = await ContentApi.retrieve_blog_content(this.document)
|
const context = canvas.getContext("2d");
|
||||||
console.log('response', response)
|
const scale = 1.5;
|
||||||
|
this.loadingTask.promise.then((pdf) => {
|
||||||
// var fr = new FileReader();
|
pdf.getPage(num).then((page) => {
|
||||||
// fr.onload = async function(){
|
const viewport = page.getViewport({ scale });
|
||||||
// const doc = await getDocument({url: this.result}).promise
|
canvas.height = viewport.height;
|
||||||
// const page = await doc.getPage(1)
|
canvas.width = viewport.width;
|
||||||
// const canvas = this.$refs.canvas
|
const renderContext = {
|
||||||
// const context = canvas.getContext('2d')
|
canvasContext: context,
|
||||||
// const viewport = page.getViewport({ scale: 1 })
|
viewport: viewport,
|
||||||
|
};
|
||||||
// canvas.width = viewport.width
|
page.render(renderContext);
|
||||||
// canvas.height = viewport.height
|
});
|
||||||
|
});
|
||||||
// await page.render({
|
|
||||||
// canvasContext: context,
|
|
||||||
// viewport
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// fr.readAsDataURL(response.data);
|
|
||||||
|
|
||||||
const doc = await PDFJS.getDocument({ data: response.data }).promise
|
|
||||||
const page = await doc.getPage(1)
|
|
||||||
const canvas = this.$refs.canvas
|
|
||||||
const context = canvas.getContext('2d')
|
|
||||||
const viewport = page.getViewport({ scale: 1 })
|
|
||||||
|
|
||||||
canvas.width = viewport.width
|
|
||||||
canvas.height = viewport.height
|
|
||||||
|
|
||||||
await page.render({
|
|
||||||
canvasContext: context,
|
|
||||||
viewport
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
base64StringToUint8Array(base64String) {
|
async renderPDF() {
|
||||||
var padding = '='.repeat((4 - (base64String.length % 4)) % 4)
|
const response = await WorksapceApi.fetchAttachedFileAsMediaData("66673218fa83335c3b1b11ec", "6667321afa83335c3b1b11ee")
|
||||||
var base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/')
|
this.loadingTask = PDFJS.getDocument({url: response.data});
|
||||||
|
this.loadingTask.promise.then((pdf) => {
|
||||||
var rawData = atob(base64)
|
this.numPages = pdf.numPages;
|
||||||
var outputArray = new Uint8Array(rawData.length)
|
this.renderPage(1);
|
||||||
|
});
|
||||||
for (var i = 0; i < rawData.length; ++i) {
|
},
|
||||||
outputArray[i] = rawData.charCodeAt(i)
|
prev() {
|
||||||
}
|
if (this.currentPage > 1) {
|
||||||
return outputArray
|
this.currentPage--;
|
||||||
|
this.renderPage(this.currentPage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
if (this.currentPage < this.numPages) {
|
||||||
|
this.currentPage++;
|
||||||
|
this.renderPage(this.currentPage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.pdf-reader {
|
.pdf-container{position: relative;
|
||||||
width: 100%;
|
.operate{position: absolute; right: 0; top: 0; }
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="vue-quill-container">
|
|
||||||
<QuillEditor
|
|
||||||
ref="quillRef"
|
|
||||||
v-model:content="quillData"
|
|
||||||
:options="quillOptions"
|
|
||||||
content-type="html"
|
|
||||||
@text-change="quillChange()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
const toolbarOptions = [
|
|
||||||
['bold', 'italic', 'underline', 'strike'],
|
|
||||||
['blockquote', 'code-block'],
|
|
||||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
|
||||||
[{ script: 'sub' }, { script: 'super' }],
|
|
||||||
[{ indent: '-1' }, { indent: '+1' }],
|
|
||||||
[{ direction: 'rtl' }],
|
|
||||||
[{ size: ['small', false, 'large', 'huge'] }],
|
|
||||||
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
|
||||||
[{ color: [] }, { background: [] }],
|
|
||||||
[{ font: [] }],
|
|
||||||
[{ align: [] }],
|
|
||||||
['clean']
|
|
||||||
]
|
|
||||||
import { QuillEditor } from '@vueup/vue-quill'
|
|
||||||
import 'quill/dist/quill.core.css'
|
|
||||||
import 'quill/dist/quill.snow.css'
|
|
||||||
import 'quill/dist/quill.bubble.css'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'VueQuill',
|
|
||||||
props: {
|
|
||||||
content: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['update:content'],
|
|
||||||
components: { QuillEditor },
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
quillData: this.content,
|
|
||||||
quillOptions: {
|
|
||||||
theme: 'snow',
|
|
||||||
placeholder: '请输入',
|
|
||||||
modules: {
|
|
||||||
toolbar: {
|
|
||||||
container: toolbarOptions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
quillChange() {
|
|
||||||
this.$emit('update:content', this.quillData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.vue-quill-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 100px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,23 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<div class="information-bar" @click="gotoMessages">
|
<div class="information-bar" @click="gotoMessages" :class="activePath == 'message'?'active':''">
|
||||||
<img alt="freeleaps logo" src="@/assets/message.png" />
|
<img alt="freeleaps logo" src="@/assets/message.png" />
|
||||||
</div>
|
</div>
|
||||||
<div class="navigation-container" role="navigation">
|
<div class="navigation-container" role="navigation">
|
||||||
<button class="navigation-item active" @click="gotoWorkspace">
|
<button class="navigation-item" @click="gotoWorkspace" :class="activePath == 'Workspace'?'active':''">
|
||||||
<svg-icon icon="workspace" class-name="icon" />
|
<svg-icon icon="workspace" class-name="icon" />
|
||||||
Workspace
|
Workspace
|
||||||
</button>
|
</button>
|
||||||
<button class="navigation-item" @click="gotoRequests">
|
<button class="navigation-item" @click="gotoRequests" :class="activePath == 'Requests'?'active':''">
|
||||||
<svg-icon icon="requests" class-name="icon" />
|
<svg-icon icon="requests" class-name="icon" />
|
||||||
Requests
|
Requests
|
||||||
</button>
|
</button>
|
||||||
<button class="navigation-item" @click="gotoProviders">
|
<button class="navigation-item" @click="gotoProviders" :class="activePath == 'Providers'?'active':''">
|
||||||
<svg-icon icon="providers" class-name="icon" />
|
<svg-icon icon="providers" class-name="icon" />
|
||||||
Providers
|
Providers
|
||||||
</button>
|
</button>
|
||||||
<button class="navigation-item" @click="gotoIssueRequest">
|
<button class="navigation-item" @click="gotoIssueRequest" :class="activePath == 'Post'?'active':''">
|
||||||
<svg-icon icon="post" class-name="icon" />
|
<svg-icon icon="post" class-name="icon" />
|
||||||
Post
|
Post
|
||||||
</button>
|
</button>
|
||||||
@ -61,10 +61,17 @@ export default {
|
|||||||
if (this.userIdentityNote.length > 8) {
|
if (this.userIdentityNote.length > 8) {
|
||||||
this.userIdentityNote = this.userIdentityNote.slice(0, 5) + '...'
|
this.userIdentityNote = this.userIdentityNote.slice(0, 5) + '...'
|
||||||
}
|
}
|
||||||
|
console.log('watch', this.$route.meta)
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userIdentityNote: this.mnx_getUserIdentity()
|
userIdentityNote: this.mnx_getUserIdentity(),
|
||||||
|
activePath: this.$route.meta.activePath
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route(to) {
|
||||||
|
this.activePath = to.meta.activePath
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -156,6 +163,7 @@ export default {
|
|||||||
top: 0;
|
top: 0;
|
||||||
background-color: #f44837;
|
background-color: #f44837;
|
||||||
}
|
}
|
||||||
|
&.active {border: 1px solid $primary;}
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-container {
|
.profile-container {
|
||||||
|
|||||||
1
frontend/src/icons/delete.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5138" width="64" height="64"><path d="M993.310029 179.7115H892.968039l-45.464399 813.855781c-0.938917 16.951554-14.971621 30.209501-31.940191 30.209501H209.743828c-16.970573 0-30.998272-13.247937-31.936188-30.17747l-46.19311-813.887812H32.346588c-17.689275 0-32.002252-14.322987-32.002252-31.996247 0-17.666252 14.312978-31.989239 32.002252-31.989239h120.931097c1.457423 0 2.888821 0.106104 4.294194 0.294287a32.138385 32.138385 0 0 1 4.266166-0.294287h167.931996V31.99024c0-17.666252 14.312978-31.989239 31.998248-31.989239h301.08603c17.685271 0 31.995245 14.322987 31.995245 31.989239v83.735774H862.722502c1.656618 0 3.301224 0.129126 4.919805 0.382373a32.19444 32.19444 0 0 1 4.953838-0.382373H993.310029c17.685271 0 31.999249 14.322987 31.99925 31.989239 0 17.673259-14.313978 31.996246-31.99925 31.996247zM630.852066 63.986487H393.767539v51.739527h237.084527V63.986487zM195.710123 179.7115l44.280243 780.079796H785.316911l43.558538-780.079796H195.710123zM701.535093 869.624242c-0.964942 17.024626-15.060708 30.178471-31.903156 30.178472-0.625611 0-1.21819-0.014014-1.840797-0.046045-17.659245-1.000978-31.126397-16.119742-30.12542-33.757967l33.652865-592.997099c1.00398-17.666252 16.37399-30.883159 33.750959-30.132426 17.655241 0.997975 31.122393 16.120743 30.124419 33.758968L701.535093 869.624242z m-189.207773 30.178472c-17.692278 0-31.998248-14.319984-31.998249-31.993244V274.816375c0-17.673259 14.305971-31.992242 31.998249-31.992242 17.683269 0 31.996246 14.318983 31.996246 31.992242v592.993095c0 17.673259-14.312978 31.993243-31.996246 31.993244z m-156.621951-0.046045a35.334506 35.334506 0 0 1-1.843801 0.046045c-16.843449 0-30.93521-13.153846-31.904156-30.178472L288.301544 276.628145c-1.000978-17.638225 12.469177-32.760993 30.122417-33.758968 17.220817-0.79878 32.749982 12.466174 33.753963 30.132426l33.64886 592.997099c1.001978 17.638225-12.465173 32.756989-30.121415 33.757967z" p-id="5139"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
1
frontend/src/icons/dropdown.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1331 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4137" width="64" height="64"><path d="M552.5504 896.512L45.1584 244.1216A102.4 102.4 0 0 1 125.952 78.848h1014.784a102.4 102.4 0 0 1 80.896 165.2736l-507.4944 652.288a102.4 102.4 0 0 1-161.6896 0z" p-id="4138"></path></svg>
|
||||||
|
After Width: | Height: | Size: 307 B |
1
frontend/src/icons/fe-alignjustify.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1066 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3055" width="64" height="64"><path d="M170.666667 298.666667h768a42.666667 42.666667 0 1 0 0-85.333334H170.666667a42.666667 42.666667 0 1 0 0 85.333334z m768 426.666666H170.666667a42.666667 42.666667 0 0 0 0 85.333334h768a42.666667 42.666667 0 1 0 0-85.333334z m0-170.666666H170.666667a42.666667 42.666667 0 0 0 0 85.333333h768a42.666667 42.666667 0 1 0 0-85.333333z m0-170.666667H170.666667a42.666667 42.666667 0 1 0 0 85.333333h768a42.666667 42.666667 0 0 0 0-85.333333z" p-id="3056"></path></svg>
|
||||||
|
After Width: | Height: | Size: 583 B |
1
frontend/src/icons/fe-bold.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1304" width="64" height="64"><path d="M697.8 481.4c33.6-35 54.2-82.3 54.2-134.3v-10.2C752 229.3 663.9 142 555.3 142H259.4c-15.1 0-27.4 12.3-27.4 27.4v679.1c0 16.3 13.2 29.5 29.5 29.5h318.7c117 0 211.8-94.2 211.8-210.5v-11c0-73-37.4-137.3-94.2-175.1zM328 238h224.7c57.1 0 103.3 44.4 103.3 99.3v9.5c0 54.8-46.3 99.3-103.3 99.3H328V238z m366.6 429.4c0 62.9-51.7 113.9-115.5 113.9H328V542.7h251.1c63.8 0 115.5 51 115.5 113.9v10.8z" p-id="1305"></path></svg>
|
||||||
|
After Width: | Height: | Size: 537 B |
1
frontend/src/icons/fe-char.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2418" width="64" height="64"><path d="M792.864 922.112l103.584-2.176L572.576 110.24h-89.184L161.696 919.936H264l66.944-167.936h394.112l67.808 170.112zM369.216 656L528 257.632 686.784 656h-317.568z" p-id="2419"></path></svg>
|
||||||
|
After Width: | Height: | Size: 307 B |
1
frontend/src/icons/fe-clear.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2256" width="64" height="64"><path d="M311.769043 997.487304h653.668174v-66.782608H311.769043z" p-id="2257"></path><path d="M638.447304 760.186435l-152.665043-153.355131-152.665044-153.35513L650.245565 134.92313 955.575652 441.633391 638.425043 760.186435z m-173.723826 174.458435h-165.487304L70.77287 717.000348l215.129043-216.086261 18.031304 18.120348L591.187478 807.602087l-126.441739 127.042783z m540.91687-537.6L694.633739 84.658087c-23.752348-23.863652-65.113043-23.774609-88.776348 0L262.28313 429.768348 13.94087 679.201391c-21.147826 21.25913-17.986783 57.677913 7.791304 83.500522L262.906435 992.52313a33.391304 33.391304 0 0 0 22.995478 9.216h192.645565c8.859826 0 17.341217-3.539478 23.596522-9.839304l159.877565-160.567652 343.574261-345.110261A62.73113 62.73113 0 0 0 1024.005565 441.633391c0-16.851478-6.522435-32.678957-18.365217-44.588521z" p-id="2258"></path></svg>
|
||||||
|
After Width: | Height: | Size: 968 B |
1
frontend/src/icons/fe-italic.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1619" width="64" height="64"><path d="M798 160H366c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h181.2l-156 544H229c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h432c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8H474.4l156-544H798c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z" p-id="1620"></path></svg>
|
||||||
|
After Width: | Height: | Size: 347 B |
1
frontend/src/icons/fe-orderedlist.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2894" width="64" height="64"><path d="M920 760H336c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z m0-568H336c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z m0 284H336c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM216 712H100c-2.2 0-4 1.8-4 4v34c0 2.2 1.8 4 4 4h72.4v20.5h-35.7c-2.2 0-4 1.8-4 4v34c0 2.2 1.8 4 4 4h35.7V838H100c-2.2 0-4 1.8-4 4v34c0 2.2 1.8 4 4 4h116c2.2 0 4-1.8 4-4V716c0-2.2-1.8-4-4-4zM100 188h38v120c0 2.2 1.8 4 4 4h40c2.2 0 4-1.8 4-4V152c0-4.4-3.6-8-8-8h-78c-2.2 0-4 1.8-4 4v36c0 2.2 1.8 4 4 4z m116 240H100c-2.2 0-4 1.8-4 4v36c0 2.2 1.8 4 4 4h68.4l-70.3 77.7c-1.3 1.5-2.1 3.4-2.1 5.4V592c0 2.2 1.8 4 4 4h116c2.2 0 4-1.8 4-4v-36c0-2.2-1.8-4-4-4h-68.4l70.3-77.7c1.3-1.5 2.1-3.4 2.1-5.4V432c0-2.2-1.8-4-4-4z" p-id="2895"></path></svg>
|
||||||
|
After Width: | Height: | Size: 926 B |
1
frontend/src/icons/fe-paragraph.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1147" width="64" height="64"><path d="M149.333333 149.333333h448a42.666667 42.666667 0 1 1 0 85.333334H149.333333a42.666667 42.666667 0 1 1 0-85.333334z m0 640h448a42.666667 42.666667 0 1 1 0 85.333334H149.333333a42.666667 42.666667 0 1 1 0-85.333334z m0-320h725.333334a42.666667 42.666667 0 1 1 0 85.333334H149.333333a42.666667 42.666667 0 1 1 0-85.333334z" p-id="1148"></path></svg>
|
||||||
|
After Width: | Height: | Size: 468 B |
1
frontend/src/icons/fe-strike.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2095" width="64" height="64"><path d="M952 474H569.9c-10-2-20.5-4-31.6-6-15.9-2.9-22.2-4.1-30.8-5.8-51.3-10-82.2-20-106.8-34.2-35.1-20.5-52.2-48.3-52.2-85.1 0-37 15.2-67.7 44-89 28.4-21 68.8-32.1 116.8-32.1 54.8 0 97.1 14.4 125.8 42.8 14.6 14.4 25.3 32.1 31.8 52.6 1.3 4.1 2.8 10 4.3 17.8 0.9 4.8 5.2 8.2 9.9 8.2h72.8c5.6 0 10.1-4.6 10.1-10.1v-1c-0.7-6.8-1.3-12.1-2-16-7.3-43.5-28-81.7-59.7-110.3-44.4-40.5-109.7-61.8-188.7-61.8-72.3 0-137.4 18.1-183.3 50.9-25.6 18.4-45.4 41.2-58.6 67.7-13.5 27.1-20.3 58.4-20.3 92.9 0 29.5 5.7 54.5 17.3 76.5 8.3 15.7 19.6 29.5 34.1 42H72c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h433.2c2.1 0.4 3.9 0.8 5.9 1.2 30.9 6.2 49.5 10.4 66.6 15.2 23 6.5 40.6 13.3 55.2 21.5 35.8 20.2 53.3 49.2 53.3 89 0 35.3-15.5 66.8-43.6 88.8-30.5 23.9-75.6 36.4-130.5 36.4-43.7 0-80.7-8.5-110.2-25-29.1-16.3-49.1-39.8-59.7-69.5-0.8-2.2-1.7-5.2-2.7-9-1.2-4.4-5.3-7.5-9.7-7.5h-79.7c-5.6 0-10.1 4.6-10.1 10.1v1c0.2 2.3 0.4 4.2 0.6 5.7 6.5 48.8 30.3 88.8 70.7 118.8 47.1 34.8 113.4 53.2 191.8 53.2 84.2 0 154.8-19.8 204.2-57.3 25-18.9 44.2-42.2 57.1-69 13-27.1 19.7-57.9 19.7-91.5 0-31.8-5.8-58.4-17.8-81.4-5.8-11.2-13.1-21.5-21.8-30.8H952c4.4 0 8-3.6 8-8v-60c0-4.3-3.6-7.9-8-7.9z" p-id="2096"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontend/src/icons/fe-underline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1934" width="64" height="64"><path d="M824 804H200c-4.4 0-8 3.4-8 7.6v60.8c0 4.2 3.6 7.6 8 7.6h624c4.4 0 8-3.4 8-7.6v-60.8c0-4.2-3.6-7.6-8-7.6zM512 728c69.4 0 134.6-27.1 183.8-76.2C745 602.7 772 537.4 772 468V156c0-6.6-5.4-12-12-12h-60c-6.6 0-12 5.4-12 12v312c0 97-79 176-176 176s-176-79-176-176V156c0-6.6-5.4-12-12-12h-60c-6.6 0-12 5.4-12 12v312c0 69.4 27.1 134.6 76.2 183.8C377.3 701 442.6 728 512 728z" p-id="1935"></path></svg>
|
||||||
|
After Width: | Height: | Size: 515 B |
1
frontend/src/icons/fe-unorderedlist.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2733" width="64" height="64"><path d="M192 277.333333H106.666667V192h85.333333v85.333333z m725.333333 0H277.333333V192h640v85.333333zM192 554.666667H106.666667v-85.333334h85.333333v85.333334z m725.333333 0H277.333333v-85.333334h640v85.333334zM192 832H106.666667v-85.333333h85.333333v85.333333z m725.333333 0H277.333333v-85.333333h640v85.333333z" p-id="2734"></path></svg>
|
||||||
|
After Width: | Height: | Size: 455 B |
1
frontend/src/icons/msg-enter.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3264" width="64" height="64"><path d="M789.333333 128a192 192 0 0 1 191.786667 182.954667L981.333333 320v213.333333a192 192 0 0 1-182.954666 191.786667L789.333333 725.333333H110.976l118.314667 135.253334a21.333333 21.333333 0 0 1 0.682666 27.349333l-2.688 2.773333a21.333333 21.333333 0 0 1-27.306666 0.682667l-2.773334-2.688-149.248-170.624a21.333333 21.333333 0 0 1-3.84-21.76l1.536-3.2 2.304-3.114667 149.333334-170.709333a21.333333 21.333333 0 0 1 34.346666 24.96l-2.261333 3.114667L111.018667 682.666667H789.333333a149.333333 149.333333 0 0 0 149.12-141.141334L938.666667 533.333333v-213.333333a149.333333 149.333333 0 0 0-141.141334-149.12L789.333333 170.666667H512a21.333333 21.333333 0 0 1-3.84-42.325334L512 128h277.333333z" p-id="3265"></path></svg>
|
||||||
|
After Width: | Height: | Size: 843 B |
@ -33,7 +33,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
UserAuthApi
|
UserAuthApi,
|
||||||
|
applicantValidator
|
||||||
// userProfileValidator,
|
// userProfileValidator,
|
||||||
} from '../../utils/index'
|
} from '../../utils/index'
|
||||||
import { signinActionEnum } from '../../types/index'
|
import { signinActionEnum } from '../../types/index'
|
||||||
@ -55,9 +56,9 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.message = userProfileValidator.emailValidator.validate(
|
this.message = applicantValidator.emailValidator.validate(
|
||||||
// this.email
|
this.email
|
||||||
// );
|
);
|
||||||
|
|
||||||
if (this.message != null) return
|
if (this.message != null) return
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { UserAuthApi, passwordValidator } from '../../utils/index'
|
import { UserAuthApi, applicantValidator } from '../../utils/index'
|
||||||
export default {
|
export default {
|
||||||
name: 'NewUserSetPassword',
|
name: 'NewUserSetPassword',
|
||||||
props: {},
|
props: {},
|
||||||
@ -67,7 +67,8 @@ export default {
|
|||||||
this.message = 'The two passwords are not matched'
|
this.message = 'The two passwords are not matched'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.message = passwordValidator.validate(this.password)
|
this.message = applicantValidator.emailValidator.validate(this.password)
|
||||||
|
// console.log('EmailValidator', EmailValidator)
|
||||||
if (this.message != null) return
|
if (this.message != null) return
|
||||||
|
|
||||||
UserAuthApi.updatePassword(this.password, this.password2)
|
UserAuthApi.updatePassword(this.password, this.password2)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 100vw; height: 100vh">
|
<div class="pdf-viewer">
|
||||||
<PDFReader document="6662431ee312d5389c612020" />
|
<PDFReader />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@ -50,3 +50,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// .pdf-viewer {height: $body-height;}
|
||||||
|
</style>
|
||||||
@ -1,81 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="message-hub-conainter">
|
<div class="message-container">
|
||||||
<div class="conversation-list-container">
|
<div class="message-hub-conainter">
|
||||||
<div
|
<div v-if="conversations && conversations.length>0" class="conversation-list-container">
|
||||||
v-for="(conversation, index) in conversations"
|
<div v-for="(conversation, index) in conversations" :key="index" class="conversation-container" @click="selectConversation(conversation)">
|
||||||
:key="index"
|
<img class="participant-portrait" alt="user portrait" src="@/assets/profile.png" />
|
||||||
class="conversation-container"
|
<div class="conversation-summary-container">
|
||||||
@click="selectConversation(conversation)"
|
<div class="conversation-summary-header-container">
|
||||||
>
|
<span class="participant-fullname">
|
||||||
<div class="participant-portrait-container">
|
{{ conversation.summary.contact.first_name }}
|
||||||
<img
|
{{ conversation.summary.contact.last_name }}
|
||||||
class="participant-portrait"
|
</span>
|
||||||
alt="user portrait"
|
<span class="conversation-last-update-date">{{ getDateFromFulltimeString(conversation.summary.last_message.create_time) }}</span>
|
||||||
src="@/assets/images/default-user-portrait.png"
|
</div>
|
||||||
/>
|
<div class="conversation-summary-highlight-container">{{ conversation.summary.last_message.message_body }}</div>
|
||||||
</div>
|
|
||||||
<div class="conversation-summary-container">
|
|
||||||
<div class="conversation-summary-header-container">
|
|
||||||
<span class="participant-fullname">
|
|
||||||
{{ conversation.summary.contact.first_name }}
|
|
||||||
{{ conversation.summary.contact.last_name }}
|
|
||||||
</span>
|
|
||||||
<span class="conversation-last-update-date">
|
|
||||||
{{ getDateFromFulltimeString(conversation.summary.last_message.create_time) }}</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="conversation-summary-highlight-container">
|
|
||||||
<span class="conversation-last-message-summary">{{
|
|
||||||
conversation.summary.last_message.message_body
|
|
||||||
}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-if="!conversations || conversations.length==0" class="conversation-list-empty-container">
|
||||||
<div class="message-panel-container">
|
Empty conversation
|
||||||
<div v-if="current_thread" class="message-thread-container">
|
</div>
|
||||||
<div
|
<div class="message-panel-container">
|
||||||
v-for="(item, index) in current_thread.conversation.messages"
|
<div v-if="current_thread" class="message-thread-container">
|
||||||
:key="index"
|
<div v-for="(item, index) in current_thread.conversation.messages" :key="index" class="message-item-container" :class="item.sender_profile.me ? 'me': ''">
|
||||||
class="message-item-container"
|
<div class="message-item-header-container">
|
||||||
>
|
<img class="message-item-sender-portrait" alt="user portrait" src="@/assets/profile.png" />
|
||||||
<div class="message-item-header-container">
|
|
||||||
<div class="message-item-sender-info">
|
|
||||||
<img
|
|
||||||
class="message-item-sender-portrait"
|
|
||||||
alt="user portrait"
|
|
||||||
src="@/assets/images/default-user-portrait.png"
|
|
||||||
/>
|
|
||||||
<span class="message-item-sender-fullname">
|
<span class="message-item-sender-fullname">
|
||||||
{{ item.sender_profile.first_name }}
|
{{ item.sender_profile.first_name }}
|
||||||
{{ item.sender_profile.last_name }}
|
{{ item.sender_profile.last_name }}
|
||||||
</span>
|
</span>
|
||||||
|
<span class="message-item-create-time"> {{ getDateFromFulltimeString(item.raw_data.create_time) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-item-additional-info-container">
|
<div class="message-item-message-body">{{ item.raw_data.message_body }}</div>
|
||||||
<span class="message-item-create-time">
|
|
||||||
{{ getDateFromFulltimeString(item.raw_data.create_time) }}</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message-item-message-body-container">
|
|
||||||
<p class="message-item-message-body-span">{{ item.raw_data.message_body }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-if="!current_thread" class="message-thread-empty-container">Please choose conversation</div>
|
||||||
<div class="message-writing-panel-container">
|
<div class="message-writing-panel-container">
|
||||||
<input
|
<svg-icon icon="msg-enter" class-name="writing-message-enter" />
|
||||||
class="writing-message-input"
|
<input class="writing-message-input" type="text" v-model="writtenMessage" @keypress.enter="sendMessage(current_thread.conversation.information.conversation_id)" />
|
||||||
type="text"
|
</div>
|
||||||
v-model="writtenMessage"
|
|
||||||
@keypress.enter="sendMessage(current_thread.conversation.information.conversation_id)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import SvgIcon from '../../../components/SvgIcon.vue'
|
||||||
import { MessageHubApi, DateUtils } from '../../../utils/index'
|
import { MessageHubApi, DateUtils } from '../../../utils/index'
|
||||||
export default {
|
export default {
|
||||||
|
components: { SvgIcon },
|
||||||
name: 'MessageHub',
|
name: 'MessageHub',
|
||||||
props: {},
|
props: {},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -130,139 +101,45 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.message-hub-conainter {
|
.message-container { display: flex; align-items: center; width: 100%; height: $body-height; padding: 24px 24px 0 24px; justify-content: center;
|
||||||
@extend .flex-row-container;
|
.message-hub-conainter { display: flex; box-shadow: 0px 0px 24px 0px #D4D3E380; border-radius: 12px; width: 100%; max-width: $body-width; height: 100%; overflow: hidden;
|
||||||
@extend .justify-content-between;
|
.conversation-list-container {height: 100%; overflow: auto; width: 300px;
|
||||||
@extend .border;
|
.conversation-container {background-color: #F3F3F5; display: flex; cursor: pointer; height: 98px; padding: 18px;
|
||||||
@extend .w-100;
|
.participant-portrait {width: 36px; height: 36px; border-radius: 18px; margin-right: 16px;}
|
||||||
}
|
.conversation-summary-container {display: flex; flex-direction: column; flex: 1; overflow: hidden;
|
||||||
|
.conversation-summary-header-container {display: flex; align-items: center; height: 22px; color: #0D1637;
|
||||||
|
.participant-fullname {font-weight: 500; flex: 1; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
|
||||||
|
.conversation-last-update-date {white-space: nowrap; flex-shrink: 0;}
|
||||||
|
}
|
||||||
|
.conversation-summary-highlight-container {font-size: 14px; color: #6E7387; white-space: normal; overflow: hidden; flex: 1; text-align: left; word-break: break-word}
|
||||||
|
}
|
||||||
|
&:hover {opacity: .78;}
|
||||||
|
&.selected {background-color: transparent;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.conversation-list-empty-container {height: 100%; overflow: auto; width: 300px; background-color: #F3F3F5; display: flex; align-items: center; justify-content: center;}
|
||||||
|
.message-panel-container {height: 100%; overflow: auto; flex: 1; padding-bottom: 98px; position: relative;
|
||||||
|
.message-thread-container {height: 100%; overflow: auto; padding: 20px 32px; display: flex; flex-direction: column;
|
||||||
|
.message-item-container {max-width: 70%; margin-bottom: 15px; width: fit-content; display: flex; flex-direction: column;
|
||||||
|
.message-item-header-container {display: flex; align-items: center; margin-bottom: 6px; width: 100%; overflow: hidden; font-size: 18px; width: fit-content; max-width: 100%;
|
||||||
|
.message-item-sender-portrait {width: 36px; height: 36px; border-radius: 18px; }
|
||||||
|
.message-item-sender-fullname {overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: #16181E; font-weight: 500; margin: 0 7px; }
|
||||||
|
.message-item-create-time {color: #737478; white-space: nowrap; flex-shrink: 0; font-size: 16px; }
|
||||||
|
}
|
||||||
|
.message-item-message-body {font-size: 14px; line-height: 17px; color: #0D1637; background-color: #F3F3F5; padding: 12px; border-radius: 12px; overflow: hidden; width: fit-content; max-width: 100%; text-align: left; word-break: break-word}
|
||||||
|
|
||||||
.conversation-list-container {
|
&.me {align-self: flex-end;
|
||||||
@extend .flex-colum-container;
|
.message-item-header-container {flex-direction: row-reverse; align-self: flex-end;}
|
||||||
@extend .justify-content-start;
|
.message-item-message-body {background-color: $primary; color: white; align-self: flex-end;}
|
||||||
@extend .w-40;
|
}
|
||||||
@extend .m-1;
|
}
|
||||||
@extend .border;
|
}
|
||||||
min-height: 80vh;
|
.message-thread-empty-container {height: 100%; overflow: auto; padding: 20px 32px; display: flex; align-items: center; justify-content: center;}
|
||||||
}
|
.message-writing-panel-container {height: 98px; padding: 24px; background-color: white; position: absolute; bottom: 0; left: 0; width: 100%;
|
||||||
|
.writing-message-enter {position: absolute; height: 24px; width: 24px; background-color: #F3F3F5; padding: 7px; color: #9EA2AF; top: 37px; right: 37px; border-radius: 7px;}
|
||||||
.conversation-container {
|
.writing-message-input {height: 50px; border: 1px solid #E1E1E1; box-shadow: none; width: 100%; padding: 0 48px 0 12px; border-radius: 12px;}
|
||||||
@extend .flex-row-container;
|
}
|
||||||
@extend .justify-content-between;
|
}
|
||||||
@extend .border;
|
}
|
||||||
@extend .w-100;
|
|
||||||
@extend .my-3;
|
|
||||||
@extend .focus-ring;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.participant-portrait-container {
|
|
||||||
@extend .float-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.participant-portrait {
|
|
||||||
@extend .img-fluid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-summary-container {
|
|
||||||
@extend .flex-colum-container;
|
|
||||||
@extend .w-90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-summary-header-container {
|
|
||||||
@extend .flex-row-container;
|
|
||||||
@extend .justify-content-between;
|
|
||||||
@extend .w-100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.participant-fullname {
|
|
||||||
@extend .text-start;
|
|
||||||
@extend .label-text-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-last-update-date {
|
|
||||||
@extend .text-start;
|
|
||||||
@extend .label-text-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-summary-highlight-container {
|
|
||||||
@extend .container;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-last-message-summary {
|
|
||||||
@extend .d-inline-block;
|
|
||||||
@extend .text-truncate;
|
|
||||||
@extend .w-100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-panel-container {
|
|
||||||
@extend .flex-colum-container;
|
|
||||||
@extend .w-60;
|
|
||||||
@extend .m-1;
|
|
||||||
@extend .border;
|
|
||||||
@extend .justify-content-between;
|
|
||||||
min-height: 80vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-thread-container {
|
|
||||||
@extend .flex-colum-container;
|
|
||||||
@extend .m-1;
|
|
||||||
@extend .border;
|
|
||||||
@extend .align-items-start;
|
|
||||||
@extend .flex-grow-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-container {
|
|
||||||
@extend .flex-colum-container;
|
|
||||||
@extend .m-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-header-container {
|
|
||||||
@extend .flex-row-container;
|
|
||||||
@extend .justify-content-between;
|
|
||||||
@extend .w-100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-sender-info {
|
|
||||||
@extend .m-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-additional-info-container {
|
|
||||||
@extend .m-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-sender-portrait {
|
|
||||||
@extend .img-fluid;
|
|
||||||
height: 2vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-sender-fullname {
|
|
||||||
@extend .label-text;
|
|
||||||
@extend .mx-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-create-time {
|
|
||||||
@extend .label-text;
|
|
||||||
@extend .mx-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-message-body-container {
|
|
||||||
@extend .container;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item-message-body-span {
|
|
||||||
@extend .text-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-writing-panel-container {
|
|
||||||
@extend .flex-colum-container;
|
|
||||||
@extend .border;
|
|
||||||
min-height: 10vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.writing-message-input {
|
|
||||||
@extend .text-start;
|
|
||||||
@extend .w-100;
|
|
||||||
@extend .flex-grow-1;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="workspace-container">
|
<div class="workspace-container">
|
||||||
<div class="workspace-header"></div>
|
<!-- <div class="workspace-header"></div> -->
|
||||||
<div class="workspace-body">
|
<div class="workspace-body">
|
||||||
<div
|
<div
|
||||||
class="accordion"
|
class="accordion"
|
||||||
@ -911,34 +911,36 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.workspace-container {
|
.workspace-container {width: 100%; display: flex; align-items: center; justify-content: center}
|
||||||
@extend .flex-colum-container;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workspace-header {
|
.workspace-header {
|
||||||
@extend .flex-row-container;
|
@extend .flex-row-container;
|
||||||
@extend .justify-content-end;
|
@extend .justify-content-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-body {
|
.workspace-body {width: 100%; max-width: $body-width; padding: 24px 0;
|
||||||
@extend .container;
|
.accordion {box-shadow: 0px 0px 24px 0px #D4D3E380; border: none; border-radius: 12px; margin-bottom: 16px;
|
||||||
|
.accordion-item {border: none;
|
||||||
|
.accordion-header {border: none;
|
||||||
|
.accordion-button {box-shadow: none; padding: 12px}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-item-bar {
|
.workspace-item-bar {display: flex; align-items: center; margin: 0 24px 0 0; border: 1px dashed #AEBFFD; border-radius: 3px; flex: 1}
|
||||||
@extend .flex-row-container;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workspace-item-bar-left {
|
.workspace-item-bar-left {
|
||||||
@extend .flex-row-container;
|
@extend .flex-row-container;
|
||||||
@extend .flex-grow-1;
|
@extend .flex-grow-1;
|
||||||
@extend .border;
|
// @extend .border;
|
||||||
@extend .me-3;
|
@extend .me-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-item-bar-right {
|
.workspace-item-bar-right {
|
||||||
@extend .flex-row-container;
|
@extend .flex-row-container;
|
||||||
@extend .w-20;
|
@extend .w-20;
|
||||||
@extend .border;
|
// @extend .border;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-item-title-container {
|
.project-item-title-container {
|
||||||
|
|||||||
@ -105,22 +105,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-bar">
|
<div class="action-bar">
|
||||||
<div class="product-dropdown-container">
|
<input-selector :select-list="products" :selected="selectedProduct" @selectedChange="selectedChange" />
|
||||||
<label>Product Name:</label>
|
<div class="upload-contianer">
|
||||||
<select class="product-dropdown" v-model="selectedProduct">
|
<label class="btn btn-link">
|
||||||
<option value="new">New ...</option>
|
<span v-if="!uploadFile">Upload file</span>
|
||||||
<option v-for="product in products" :value="product.name" :key="product">
|
<span v-if="uploadFile">{{uploadFile.name}}</span>
|
||||||
{{ product.name }}
|
<input type="file" hidden @change="handleFileUpload"/>
|
||||||
</option>
|
</label>
|
||||||
</select>
|
<svg-icon v-if="uploadFile" icon="delete" class-name="delete-icon" @click.stop="clearFile" />
|
||||||
<input
|
|
||||||
v-if="selectedProduct === 'new'"
|
|
||||||
type="text"
|
|
||||||
class="product-input-box"
|
|
||||||
v-model="newProduct"
|
|
||||||
placeholder="Enter new product name"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex-1" />
|
||||||
<button
|
<button
|
||||||
class="action-button"
|
class="action-button"
|
||||||
type="button"
|
type="button"
|
||||||
@ -150,12 +144,12 @@
|
|||||||
@blur="descriptionDone($event)"
|
@blur="descriptionDone($event)"
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
/> -->
|
/> -->
|
||||||
<VueQuill v-model:content="content" />
|
<freeleaps-editor v-model:content="content" />
|
||||||
</div>
|
</div>
|
||||||
<div class="file-upload-container">
|
<!-- <div class="file-upload-container">
|
||||||
<label for="file-upload" class="file-upload-label">Upload File:</label>
|
<label for="file-upload" class="file-upload-label">Upload File:</label>
|
||||||
<input type="file" id="file-upload" class="file-upload-input" @change="handleFileUpload" />
|
<input type="file" id="file-upload" class="file-upload-input" @change="handleFileUpload" />
|
||||||
</div>
|
</div> -->
|
||||||
<div class="action-footer">
|
<div class="action-footer">
|
||||||
<button class="cancel-button" @click="back">Back</button>
|
<button class="cancel-button" @click="back">Back</button>
|
||||||
<button class="submit-button" @click="submit">Submit</button>
|
<button class="submit-button" @click="submit">Submit</button>
|
||||||
@ -166,7 +160,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import { WorksapceApi, textAreaAujuster, requestIssueUtils } from '../../../../utils/index'
|
import { WorksapceApi, textAreaAujuster, requestIssueUtils } from '../../../../utils/index'
|
||||||
import { requestIssuingModelEnum } from '../../../../types/index'
|
import { requestIssuingModelEnum } from '../../../../types/index'
|
||||||
import VueQuill from '@/components/VueQuill.vue'
|
import FreeleapsEditor from '@/components/FreeleapsEditor.vue'
|
||||||
|
import InputSelector from '@/components/InputSelector.vue'
|
||||||
|
import SvgIcon from '@/components/SvgIcon.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'IssueRequest',
|
name: 'IssueRequest',
|
||||||
@ -180,7 +176,7 @@ export default {
|
|||||||
type: String
|
type: String
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: { VueQuill },
|
components: {FreeleapsEditor, InputSelector, SvgIcon },
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initProducts()
|
this.initProducts()
|
||||||
this.initiateFromInput()
|
this.initiateFromInput()
|
||||||
@ -194,26 +190,36 @@ export default {
|
|||||||
request_id: null,
|
request_id: null,
|
||||||
availableTemplates: null,
|
availableTemplates: null,
|
||||||
existingRequests: null,
|
existingRequests: null,
|
||||||
products: null,
|
products: [],
|
||||||
selectedProduct: null,
|
selectedProduct: null,
|
||||||
newProduct: null,
|
|
||||||
uploadFile: null
|
uploadFile: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleFileUpload(event) {
|
handleFileUpload(event) {
|
||||||
this.uploadFile = event.target.files[0]
|
if (event.target.files[0]) {
|
||||||
|
this.uploadFile = event.target.files[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearFile() {
|
||||||
|
this.uploadFile = null
|
||||||
},
|
},
|
||||||
initProducts() {
|
initProducts() {
|
||||||
WorksapceApi.fetchProducts()
|
WorksapceApi.fetchProducts()
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.products = response.data
|
this.products = (response.data || []).map(p => p.name)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.mnx_backendErrorHandler(error)
|
this.mnx_backendErrorHandler(error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
selectedChange(item) {
|
||||||
|
this.selectedProduct = item.selected
|
||||||
|
if (item.isNew) {
|
||||||
|
this.products.push(item.selected)
|
||||||
|
}
|
||||||
|
},
|
||||||
fetchExisting() {
|
fetchExisting() {
|
||||||
WorksapceApi.fetchMyExistingRequests('')
|
WorksapceApi.fetchMyExistingRequests('')
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -290,9 +296,6 @@ export default {
|
|||||||
},
|
},
|
||||||
submit() {
|
submit() {
|
||||||
var product = this.selectedProduct
|
var product = this.selectedProduct
|
||||||
if (this.selectedProduct === 'new') {
|
|
||||||
product = this.newProduct.trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
alert('Please input a product name or select a product')
|
alert('Please input a product name or select a product')
|
||||||
@ -322,6 +325,10 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.upload-contianer {display: flex; align-items: center;}
|
||||||
|
.delete-icon {color: $primary; cursor: pointer;
|
||||||
|
&:hover {opacity: .78;}
|
||||||
|
}
|
||||||
.request-issue-container {
|
.request-issue-container {
|
||||||
@extend .flex-colum-container;
|
@extend .flex-colum-container;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
export { store } from './store/index'
|
export { store } from './store/index'
|
||||||
export { router } from './router/index'
|
export { router } from './router/index'
|
||||||
export { pdfjsLib } from './pdfjs/index'
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export { pdfjsLib } from './pdfjs.js'
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import * as pdfjsLib from 'pdfjs-dist'
|
|
||||||
//need to set worker before the pdfjs can be used.
|
|
||||||
// pdfjsLib.GlobalWorkerOptions.workerPort = new Worker(
|
|
||||||
// new URL('pdfjs-dist/build/pdf.worker.mjs', import.meta.url)
|
|
||||||
// )
|
|
||||||
|
|
||||||
export { pdfjsLib }
|
|
||||||
@ -235,7 +235,7 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
name: 'request-issue',
|
name: 'request-issue',
|
||||||
path: '/request-issue/:loadFrom',
|
path: '/request-issue/:loadFrom',
|
||||||
meta: { requiredRoles: [userRoleEnum.PERSONAL] },
|
meta: { requiredRoles: [userRoleEnum.PERSONAL], activePath: 'Post' },
|
||||||
components: { default: IssueRequest, footer: FooterGuest, header: HeaderUser },
|
components: { default: IssueRequest, footer: FooterGuest, header: HeaderUser },
|
||||||
props: (route) => {
|
props: (route) => {
|
||||||
/**
|
/**
|
||||||
@ -298,21 +298,21 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
name: 'message-hub',
|
name: 'message-hub',
|
||||||
path: '/message-hub',
|
path: '/message-hub',
|
||||||
meta: { requiredRoles: [userRoleEnum.PERSONAL] },
|
meta: { requiredRoles: [userRoleEnum.PERSONAL], activePath: 'message' },
|
||||||
components: { default: MessageHub, footer: FooterGuest, header: HeaderUser }
|
components: { default: MessageHub, footer: FooterGuest, header: HeaderUser }
|
||||||
},
|
},
|
||||||
// provider hub
|
// provider hub
|
||||||
{
|
{
|
||||||
name: 'provider-hub',
|
name: 'provider-hub',
|
||||||
path: '/provider-hub',
|
path: '/provider-hub',
|
||||||
meta: { requiredRoles: [userRoleEnum.PERSONAL] },
|
meta: { requiredRoles: [userRoleEnum.PERSONAL], activePath: 'Providers' },
|
||||||
components: { default: ProviderHub, footer: FooterGuest, header: HeaderUser }
|
components: { default: ProviderHub, footer: FooterGuest, header: HeaderUser }
|
||||||
},
|
},
|
||||||
//request hub
|
//request hub
|
||||||
{
|
{
|
||||||
name: 'request-hub',
|
name: 'request-hub',
|
||||||
path: '/request-hub',
|
path: '/request-hub',
|
||||||
meta: { requiredRoles: [userRoleEnum.PERSONAL] },
|
meta: { requiredRoles: [userRoleEnum.PERSONAL], activePath: 'Requests' },
|
||||||
components: { default: RequestHub, footer: FooterGuest, header: HeaderUser }
|
components: { default: RequestHub, footer: FooterGuest, header: HeaderUser }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -370,7 +370,7 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
name: 'work-space',
|
name: 'work-space',
|
||||||
path: '/work-space',
|
path: '/work-space',
|
||||||
meta: { requiredRoles: [userRoleEnum.PERSONAL], active: 'workspace' },
|
meta: { requiredRoles: [userRoleEnum.PERSONAL], activePath: 'Workspace' },
|
||||||
components: { default: Workspace, footer: FooterGuest, header: HeaderUser }
|
components: { default: Workspace, footer: FooterGuest, header: HeaderUser }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -13,6 +13,6 @@ export { userUtils, userProfileUtils, requestIssueUtils, requestHubUtils } from
|
|||||||
|
|
||||||
export { ValueChecker, DateUtils, OIDUtils } from './common/index'
|
export { ValueChecker, DateUtils, OIDUtils } from './common/index'
|
||||||
|
|
||||||
export { passwordValidator } from './validator/index'
|
export { passwordValidator, applicantValidator } from './validator/index'
|
||||||
|
|
||||||
export { textAreaAujuster, tooltip, elementHandler, mediaDataHandler } from './html/index'
|
export { textAreaAujuster, tooltip, elementHandler, mediaDataHandler } from './html/index'
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
export { passwordValidator } from './passwordValidator'
|
export { passwordValidator } from './passwordValidator'
|
||||||
|
export { applicantValidator } from './applicantValidator'
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export default defineConfig({
|
|||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
'^/api/': {
|
'^/api/': {
|
||||||
target: 'http://localhost:8001/',
|
target: 'https://freeleaps-alpha.com',
|
||||||
ws: true,
|
ws: true,
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
}
|
}
|
||||||
|
|||||||