mirror of
https://github.com/Teamlinker/Teamlinker.git
synced 2025-06-03 03:00:17 +00:00
add
This commit is contained in:
parent
d4874f0472
commit
3bd5997cb7
@ -9,17 +9,20 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.3",
|
||||
"@logicflow/core": "^1.1.31",
|
||||
"blueimp-md5": "^2.19.0",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"mediasoup-client": "^3.6.84",
|
||||
"moment": "^2.29.4",
|
||||
"moment-timezone": "^0.5.42",
|
||||
"pinia": "^2.0.28",
|
||||
"pinia": "^2.1.4",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"uuid": "^9.0.0",
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.1.6"
|
||||
"vue-router": "^4.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arco-design/web-vue": "^2.47.1",
|
||||
@ -27,14 +30,14 @@
|
||||
"@types/blueimp-md5": "^2.18.0",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@vitejs/plugin-vue": "^4.2.0",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"tslib": "^2.4.1",
|
||||
"ttypescript": "^1.5.15",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^4.3.2",
|
||||
"vite": "^4.3.9",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-typescript": "^1.0.4",
|
||||
"vue-tsc": "^1.4.4"
|
||||
"vue-tsc": "^1.8.2"
|
||||
}
|
||||
}
|
||||
|
@ -23,15 +23,15 @@
|
||||
<script setup lang="ts">
|
||||
import {apiIssue, apiOrganization, apiRelease, apiUser, DCSType} from "../../request/request";
|
||||
import {
|
||||
ICommon_Route_Req_ProjectIssue_Field,
|
||||
ICommon_Route_Res_Project_filter_Item,
|
||||
ICommon_Route_Res_Release_Item,
|
||||
ICommon_Route_Res_Workflow_Node_Field
|
||||
ICommon_Route_Req_ProjectIssue_Field,
|
||||
ICommon_Route_Res_Project_Issue_filter_Item,
|
||||
ICommon_Route_Res_Release_Item,
|
||||
ICommon_Route_Res_Workflow_Node_Field
|
||||
} from "../../../../../../common/routes/response";
|
||||
import {ECommon_Field_Type} from "../../../../../../common/field/type";
|
||||
import {ref} from "vue";
|
||||
import {
|
||||
ECommon_Model_Workflow_Node_Field_Type_Label_Type
|
||||
ECommon_Model_Workflow_Node_Field_Type_Label_Type
|
||||
} from "../../../../../../common/model/workflow_node_field_type";
|
||||
import {SessionStorage} from "../../storage/session";
|
||||
|
||||
@ -89,12 +89,12 @@ switch (props.item.fieldType.type) {
|
||||
default:
|
||||
break
|
||||
}
|
||||
const multiLabelList=ref<DCSType<ICommon_Route_Res_Project_filter_Item[] | ICommon_Route_Res_Release_Item[] | {
|
||||
const multiLabelList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item[] | ICommon_Route_Res_Release_Item[] | {
|
||||
name:string,
|
||||
id:string,
|
||||
photo:string
|
||||
}[]>>([])
|
||||
const labelList=ref<DCSType<ICommon_Route_Res_Project_filter_Item[] | ICommon_Route_Res_Release_Item[] | {
|
||||
const labelList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item[] | ICommon_Route_Res_Release_Item[] | {
|
||||
name:string,
|
||||
id:string,
|
||||
photo:string
|
||||
|
@ -1,14 +1,21 @@
|
||||
import {nextTick, reactive, Ref} from "vue";
|
||||
import {ELineConfigType, Line, LineConfig, LineStyle} from "./type";
|
||||
import {AppContext, nextTick, reactive, Ref} from "vue";
|
||||
import {RichEditorHandle} from "./handle";
|
||||
import {RichEditorFunc} from "./func";
|
||||
import {
|
||||
ECommon_Wiki_Content_Line_Config_Type,
|
||||
ICommon_Wiki_Content_Line,
|
||||
ICommon_Wiki_Content_Line_Config,
|
||||
ICommon_Wiki_Content_Line_Style
|
||||
} from "../../../../../../common/model/wiki_item_content";
|
||||
import {renderComponent} from "../../../../teamOS/common/util/component";
|
||||
import PopMenu from "./popMenu.vue";
|
||||
|
||||
export class RichEditorEvent {
|
||||
private selectElementList:HTMLElement[]=[]
|
||||
private isMouseDown=false
|
||||
private root:Ref<HTMLElement>
|
||||
private elementList:Ref<HTMLElement[]>
|
||||
private lineList=reactive<Line[]>([])
|
||||
private lineList=reactive<ICommon_Wiki_Content_Line[]>([])
|
||||
private imageHelperElement:HTMLElement
|
||||
private resizeImage:HTMLElement
|
||||
private resizeObserver:ResizeObserver
|
||||
@ -17,10 +24,33 @@ export class RichEditorEvent {
|
||||
private selectionLinkElement:HTMLElement
|
||||
private selectionColorElement:HTMLElement
|
||||
private linkEditElement:HTMLElement
|
||||
private popMenuElement:HTMLElement
|
||||
private appContext:AppContext
|
||||
private destroyFunc:()=>void
|
||||
private popMenuList:{
|
||||
type: any,
|
||||
title: string
|
||||
}[]=[]
|
||||
onUploadFileFunc:(file:File,handleFunc:(fileId:string,path:string)=>void)=>void
|
||||
onPopMenuClickFunc:(type:any,handleFunc:(item:ICommon_Wiki_Content_Line_Config)=>void)=>void
|
||||
clear() {
|
||||
this.destroyFunc?.()
|
||||
this.imageHelperElement?.remove()
|
||||
this.resizeObserver?.disconnect()
|
||||
this.selectionMenuElement?.remove()
|
||||
this.linkEditElement?.remove()
|
||||
this.popMenuElement?.parentElement.removeChild(this.popMenuElement)
|
||||
}
|
||||
setPopMenuList(popMenuList:{
|
||||
type: any,
|
||||
title: string
|
||||
}[]) {
|
||||
this.popMenuList=popMenuList
|
||||
}
|
||||
getLineList(){
|
||||
return this.lineList
|
||||
}
|
||||
setLineList(data:Line[]) {
|
||||
setLineList(data:ICommon_Wiki_Content_Line[]) {
|
||||
this.lineList.splice(0,this.lineList.length,...data)
|
||||
}
|
||||
getSelectElementList() {
|
||||
@ -29,13 +59,13 @@ export class RichEditorEvent {
|
||||
getRoot() {
|
||||
return this.root
|
||||
}
|
||||
addLine(value:string,style?:LineStyle){
|
||||
let line:Line={
|
||||
addLine(value:string,style?:ICommon_Wiki_Content_Line_Style){
|
||||
let line:ICommon_Wiki_Content_Line={
|
||||
arr:[
|
||||
{
|
||||
value:value,
|
||||
...style,
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
],
|
||||
selectEndIndexPath:[],
|
||||
@ -43,7 +73,7 @@ export class RichEditorEvent {
|
||||
}
|
||||
this.lineList.push(line)
|
||||
}
|
||||
onFocus(item:Line,event:MouseEvent){
|
||||
onFocus(item:ICommon_Wiki_Content_Line, event:MouseEvent){
|
||||
if(this.selectElementList.length==0) {
|
||||
this.selectElementList=[event.currentTarget as HTMLElement]
|
||||
}
|
||||
@ -52,7 +82,7 @@ export class RichEditorEvent {
|
||||
this.selectElementList=[event.currentTarget as HTMLElement]
|
||||
}
|
||||
|
||||
onBlur(item:Line,event:FocusEvent){
|
||||
onBlur(item:ICommon_Wiki_Content_Line, event:FocusEvent){
|
||||
RichEditorHandle.handleInnerHtml(item,event.currentTarget as HTMLElement,true)
|
||||
if(this.selectionMenuElement) {
|
||||
if(!this.selectionMenuElement.contains(event.relatedTarget as HTMLElement) && !this.selectionLinkElement.contains(event.relatedTarget as HTMLElement)) {
|
||||
@ -66,17 +96,17 @@ export class RichEditorEvent {
|
||||
}
|
||||
}
|
||||
|
||||
onEnter(line:Line,index:number,event:MouseEvent){
|
||||
onEnter(line:ICommon_Wiki_Content_Line, index:number, event:MouseEvent){
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
RichEditorHandle.handleInnerHtml(line,event.currentTarget as HTMLElement)
|
||||
let obj=line.arr[line.selectStartIndexPath[0]]
|
||||
let newLine:Line={
|
||||
let newLine:ICommon_Wiki_Content_Line={
|
||||
arr:line.arr.slice(line.selectStartIndexPath[0]+1),
|
||||
selectStartIndexPath:[],
|
||||
selectEndIndexPath:[]
|
||||
}
|
||||
if(!obj || obj.type!=ELineConfigType.IMAGE) {
|
||||
if(!obj || obj.type!=ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
let value=obj?.value.substring(line.selectStartIndexPath[1])
|
||||
if(value) {
|
||||
newLine.arr.unshift({
|
||||
@ -84,14 +114,14 @@ export class RichEditorEvent {
|
||||
style:{
|
||||
...obj.style
|
||||
},
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
})
|
||||
obj.value=obj.value.substring(0,line.selectStartIndexPath[1])
|
||||
} else {
|
||||
newLine.arr.unshift({
|
||||
value:"",
|
||||
style:{},
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -108,7 +138,7 @@ export class RichEditorEvent {
|
||||
selection.addRange(range)
|
||||
})
|
||||
}
|
||||
onDelete(index,item:Line,event:MouseEvent){
|
||||
onDelete(index, item:ICommon_Wiki_Content_Line, event:MouseEvent){
|
||||
let ele=event.currentTarget as HTMLElement
|
||||
let selection=window.getSelection()
|
||||
let range=selection.getRangeAt(0)
|
||||
@ -123,7 +153,7 @@ export class RichEditorEvent {
|
||||
RichEditorHandle.handleInnerHtml(item,ele)
|
||||
let preLine=this.lineList[index-1]
|
||||
item.arr=item.arr.filter(obj=>{
|
||||
return obj.value.length>0 || obj.type==ELineConfigType.IMAGE
|
||||
return obj.value.length>0 || obj.type==ECommon_Wiki_Content_Line_Config_Type.IMAGE
|
||||
})
|
||||
let path=[preLine.arr.length-1>=0?preLine.arr.length-1:0,preLine.arr.length>0?preLine.arr[preLine.arr.length-1].value.length:0]
|
||||
preLine.arr=preLine.arr.concat(item.arr)
|
||||
@ -157,6 +187,9 @@ export class RichEditorEvent {
|
||||
}
|
||||
|
||||
onMouseDown(event:MouseEvent){
|
||||
if(this.popMenuElement) {
|
||||
this.popMenuElement.style.display="none"
|
||||
}
|
||||
if(event.detail==1) {
|
||||
this.selectElementList=[event.currentTarget as HTMLElement]
|
||||
this.isMouseDown=true
|
||||
@ -183,7 +216,9 @@ export class RichEditorEvent {
|
||||
if(this.selectElementList.length>0) {
|
||||
range=range.cloneRange()
|
||||
for(let ele of this.selectElementList) {
|
||||
ele.contentEditable="true"
|
||||
nextTick(()=>{
|
||||
ele.contentEditable="true"
|
||||
})
|
||||
}
|
||||
let startContainer=range.startContainer as HTMLElement
|
||||
while (startContainer.tagName!=="DIV") {
|
||||
@ -632,7 +667,7 @@ export class RichEditorEvent {
|
||||
let remove=this.linkEditElement.querySelector("[name='remove']") as HTMLElement
|
||||
remove.onclick=()=>{
|
||||
let item=this.lineList[lineIndex].arr[index]
|
||||
item.type=ELineConfigType.TEXT
|
||||
item.type=ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
delete item.link
|
||||
RichEditorHandle.fixLine(this.lineList[lineIndex])
|
||||
this.linkEditElement.style.display="none"
|
||||
@ -641,34 +676,74 @@ export class RichEditorEvent {
|
||||
}
|
||||
}
|
||||
|
||||
onCopy(event:ClipboardEvent) {
|
||||
const range=window.getSelection().getRangeAt(0)
|
||||
const content=range.cloneContents()
|
||||
const ele=document.createElement("div")
|
||||
ele.setAttribute("copy","teamlinker")
|
||||
ele.appendChild(content)
|
||||
event.clipboardData.setData("text/html",ele.outerHTML)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
onPaste(event:ClipboardEvent) {
|
||||
let types=event.clipboardData.types
|
||||
let elementList=this.getSelectElementList()
|
||||
if(types?.includes("text/html")) {
|
||||
if(types.includes("Files")) {
|
||||
let file=event.clipboardData.files[0]
|
||||
if(file) {
|
||||
let selection=window.getSelection()
|
||||
let range=selection.getRangeAt(0)
|
||||
let container=range.startContainer as HTMLElement
|
||||
while (container.tagName!="DIV") {
|
||||
container=container.parentElement
|
||||
}
|
||||
let startIndex=Array.from(this.root.value.children).indexOf(container)
|
||||
let selectLine=this.lineList[startIndex]
|
||||
RichEditorHandle.handleInnerHtml(selectLine,container,true)
|
||||
this.onUploadFileFunc?.(file,(fileId, path) => {
|
||||
let originItem=selectLine.arr[selectLine.selectStartIndexPath[0]]
|
||||
let objItem:ICommon_Wiki_Content_Line_Config={
|
||||
value:fileId,
|
||||
link:path,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.IMAGE
|
||||
}
|
||||
let index:number
|
||||
if(originItem) {
|
||||
let objTemp:ICommon_Wiki_Content_Line_Config=JSON.parse(JSON.stringify(originItem))
|
||||
objTemp.value=objTemp.value.substring(selectLine.selectStartIndexPath[1])
|
||||
let appendItemList=[...selectLine.arr.slice(selectLine.selectStartIndexPath[0]+1)]
|
||||
if(objTemp.type!=ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
appendItemList.unshift(objTemp)
|
||||
}
|
||||
originItem.value=originItem.value.substring(0,selectLine.selectStartIndexPath[1])
|
||||
selectLine.arr.splice(selectLine.selectStartIndexPath[0]+1,0,objItem)
|
||||
index=selectLine.arr.length-1
|
||||
selectLine.arr=selectLine.arr.concat(appendItemList)
|
||||
} else {
|
||||
selectLine.arr=[objItem]
|
||||
index=0
|
||||
}
|
||||
RichEditorHandle.fixLine(selectLine)
|
||||
nextTick(()=>{
|
||||
let range=document.createRange()
|
||||
range.selectNode(container.childNodes[index])
|
||||
range.collapse(false)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
})
|
||||
})
|
||||
}
|
||||
} else if(types?.includes("text/html")) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault();
|
||||
let ele=document.createElement("div")
|
||||
ele.innerHTML=event.clipboardData.getData("text/html")
|
||||
let divList=ele.getElementsByTagName("div")
|
||||
let isEdit=true
|
||||
Array.from(divList).forEach(item=>{
|
||||
if(item.contentEditable!="true") {
|
||||
isEdit=false
|
||||
}
|
||||
})
|
||||
let isPlain=false
|
||||
if(divList.length==0) {
|
||||
let spanList=ele.getElementsByTagName("span")
|
||||
let linkList=ele.getElementsByTagName("a")
|
||||
let imgList=ele.getElementsByTagName("img")
|
||||
if(spanList.length+linkList.length+imgList.length==ele.children.length-1) {
|
||||
isPlain=true
|
||||
let div=ele.cloneNode(true) as HTMLDivElement
|
||||
div.removeChild(div.firstChild)
|
||||
let wrapper=document.createElement("div")
|
||||
wrapper.appendChild(div)
|
||||
divList=wrapper.getElementsByTagName("div")
|
||||
}
|
||||
let isFromTeamLinker=false
|
||||
if(divList.length==1 && divList[0].getAttribute("copy")==="teamlinker") {
|
||||
isFromTeamLinker=true
|
||||
}
|
||||
let selection=window.getSelection()
|
||||
let range=selection.getRangeAt(0)
|
||||
@ -679,10 +754,10 @@ export class RichEditorEvent {
|
||||
let startIndex=Array.from(this.root.value.children).indexOf(container)
|
||||
let selectLine=this.lineList[Array.from(this.root.value.children).indexOf(container)]
|
||||
RichEditorHandle.handleInnerHtml(selectLine,container,true)
|
||||
if((isEdit && divList.length==ele.children.length-1) || isPlain) {
|
||||
let appendItemList:LineConfig[],indexPath:number[]=[];
|
||||
if(isFromTeamLinker) {
|
||||
let appendItemList:ICommon_Wiki_Content_Line_Config[],indexPath:number[]=[];
|
||||
for(let i=0;i<divList.length;i++) {
|
||||
let line:Line={
|
||||
let line:ICommon_Wiki_Content_Line={
|
||||
arr:[],
|
||||
selectEndIndexPath:[],
|
||||
selectStartIndexPath:[]
|
||||
@ -693,7 +768,7 @@ export class RichEditorEvent {
|
||||
let text="",isImg=false
|
||||
selectLine.arr.forEach(item=>{
|
||||
text+=item.value
|
||||
if(item.type==ELineConfigType.IMAGE) {
|
||||
if(item.type==ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
isImg=true
|
||||
}
|
||||
})
|
||||
@ -701,10 +776,10 @@ export class RichEditorEvent {
|
||||
this.lineList.splice(this.lineList.indexOf(selectLine),1,line)
|
||||
} else {
|
||||
let originItem=selectLine.arr[selectLine.selectStartIndexPath[0]]
|
||||
let objTemp:LineConfig=JSON.parse(JSON.stringify(originItem))
|
||||
let objTemp:ICommon_Wiki_Content_Line_Config=JSON.parse(JSON.stringify(originItem))
|
||||
objTemp.value=objTemp.value.substring(selectLine.selectStartIndexPath[1])
|
||||
appendItemList=[...selectLine.arr.slice(selectLine.selectStartIndexPath[0]+1)]
|
||||
if(objTemp.type!=ELineConfigType.IMAGE) {
|
||||
if(objTemp.type!=ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
appendItemList.unshift(objTemp)
|
||||
}
|
||||
originItem.value=originItem.value.substring(0,selectLine.selectStartIndexPath[1])
|
||||
@ -772,7 +847,7 @@ export class RichEditorEvent {
|
||||
} else {
|
||||
selectLine.arr.push({
|
||||
value:ele.innerText,
|
||||
type:ELineConfigType.TEXT,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT,
|
||||
style:{}
|
||||
})
|
||||
nextTick(()=>{
|
||||
@ -793,8 +868,10 @@ export class RichEditorEvent {
|
||||
let ele=event.target as HTMLElement
|
||||
if(ele.tagName=="IMG") {
|
||||
let parent=ele.offsetParent;
|
||||
let left=ele.offsetLeft
|
||||
let top=ele.offsetTop
|
||||
let parentRect=parent.getBoundingClientRect()
|
||||
let rect=ele.getBoundingClientRect();
|
||||
let left=rect.left-parentRect.left
|
||||
let top=rect.top-parentRect.top
|
||||
let width=ele.offsetWidth
|
||||
let height=ele.offsetHeight
|
||||
if(!this.imageHelperElement) {
|
||||
@ -831,29 +908,121 @@ export class RichEditorEvent {
|
||||
}
|
||||
|
||||
onKeyDown(event:KeyboardEvent) {
|
||||
if((event.metaKey || event.ctrlKey) && event.key=="a") {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
if(event.metaKey || event.ctrlKey) {
|
||||
if(event.key=="a") {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
let selection=window.getSelection()
|
||||
let range=selection.getRangeAt(0)
|
||||
let element=range.startContainer as HTMLElement
|
||||
while (element.tagName!="DIV") {
|
||||
element=element.parentElement
|
||||
}
|
||||
let index=Array.from(this.root.value.children).indexOf(element)
|
||||
let line=this.lineList[index]
|
||||
RichEditorHandle.handleInnerHtml(line,element)
|
||||
this.selectElementList=Array.from(this.root.value.children) as HTMLElement[]
|
||||
nextTick(()=>{
|
||||
let range=document.createRange()
|
||||
let startNode:Node,endNode:Node
|
||||
for(let i=0;i<this.root.value.childNodes.length;i++) {
|
||||
let node=this.root.value.childNodes[i]
|
||||
for(let j=0;j<node.childNodes.length;j++) {
|
||||
let node1=node.childNodes[j]
|
||||
if(node1) {
|
||||
startNode=node1
|
||||
break
|
||||
}
|
||||
}
|
||||
if(startNode) {
|
||||
break
|
||||
}
|
||||
}
|
||||
for(let i=this.root.value.childNodes.length-1;i>=0;i--) {
|
||||
let node=this.root.value.childNodes[i]
|
||||
for(let j=node.childNodes.length-1;j>=0;j--) {
|
||||
let node1=node.childNodes[j]
|
||||
if(node1) {
|
||||
endNode=node1
|
||||
break
|
||||
}
|
||||
}
|
||||
if(endNode) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if(startNode && endNode) {
|
||||
range.setStartBefore(startNode)
|
||||
range.setEndAfter(endNode)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
if(event.key==="/") {
|
||||
if(!this.popMenuList || this.popMenuList.length==0) {
|
||||
return;
|
||||
}
|
||||
if(!this.popMenuElement) {
|
||||
this.popMenuElement=document.createElement("div")
|
||||
this.popMenuElement.style.position="absolute"
|
||||
this.popMenuElement.style.display="none"
|
||||
this.popMenuElement.style.boxShadow="0px 0px 2px 2px rgba(169, 169, 169, 0.2)"
|
||||
this.popMenuElement.style.backgroundColor="white"
|
||||
this.popMenuElement.style.border="1px solid rgba(169, 169, 169, 0.2)"
|
||||
this.popMenuElement.style.width="150px"
|
||||
this.popMenuElement.style.height="200px"
|
||||
this.popMenuElement.style.overflow="auto"
|
||||
this.popMenuElement.style.backgroundColor="white";
|
||||
this.popMenuElement.style.outlineWidth="0"
|
||||
this.popMenuElement.tabIndex=-1;
|
||||
(event.target as HTMLElement).offsetParent.appendChild(this.popMenuElement)
|
||||
this.popMenuElement.onclick=()=>{
|
||||
this.popMenuElement.style.display="none"
|
||||
}
|
||||
this.destroyFunc=renderComponent(this.popMenuElement,PopMenu,this.appContext,{
|
||||
objEditor:this,
|
||||
popMenuList:this.popMenuList
|
||||
});
|
||||
}
|
||||
let selection=window.getSelection()
|
||||
let range=selection.getRangeAt(0)
|
||||
let element=range.startContainer as HTMLElement
|
||||
while (element.tagName!="DIV") {
|
||||
element=element.parentElement
|
||||
let rect=range.getBoundingClientRect()
|
||||
if(rect.left==0 && rect.top==0 && rect.width==0 && rect.height==0) {
|
||||
let ele=range.startContainer as HTMLElement
|
||||
if(ele.tagName=="DIV" && range.startOffset!==0) {
|
||||
return
|
||||
}
|
||||
rect=(range.startContainer as HTMLElement).getBoundingClientRect()
|
||||
}
|
||||
let parent=(event.target as HTMLElement).offsetParent
|
||||
let rectParent=parent.getBoundingClientRect()
|
||||
let right=rectParent.right-rect.right+rect.width
|
||||
let bottom=rectParent.bottom-rect.bottom
|
||||
let left:number,top:number
|
||||
if(right>160) {
|
||||
left=rect.left-rectParent.left
|
||||
} else {
|
||||
left=rect.left-rectParent.left-150
|
||||
}
|
||||
if(bottom>210) {
|
||||
top=rect.top-rectParent.top+rect.height
|
||||
} else {
|
||||
top=rect.top-rectParent.top-200
|
||||
}
|
||||
this.popMenuElement.style.left=left+"px"
|
||||
this.popMenuElement.style.top=top+"px"
|
||||
this.popMenuElement.style.display="block"
|
||||
} else {
|
||||
if(this.popMenuElement) {
|
||||
this.popMenuElement.style.display="none"
|
||||
}
|
||||
let index=Array.from(this.root.value.children).indexOf(element)
|
||||
let line=this.lineList[index]
|
||||
RichEditorHandle.handleInnerHtml(line,element)
|
||||
nextTick(()=>{
|
||||
let range=document.createRange()
|
||||
range.setStartBefore(this.root.value.children[0].firstChild)
|
||||
range.setEndAfter(this.root.value.children[this.root.value.children.length-1].lastChild)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
constructor(root:Ref<HTMLElement>,elementList:Ref<HTMLElement[]>){
|
||||
constructor(root:Ref<HTMLElement>,elementList:Ref<HTMLElement[]>,appContext:AppContext){
|
||||
this.appContext=appContext
|
||||
this.root=root;
|
||||
this.elementList=elementList
|
||||
document.addEventListener("keydown",(event:KeyboardEvent)=>{
|
||||
@ -861,113 +1030,109 @@ export class RichEditorEvent {
|
||||
if(this.selectElementList.length>0 && !window.getSelection().getRangeAt(0)?.collapsed) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
let selection=window.getSelection()
|
||||
let range=selection.getRangeAt(0)
|
||||
let startOffset=range.startOffset
|
||||
let endOffset=range.endOffset
|
||||
let startContainer=range.startContainer as HTMLElement
|
||||
let endContainer=range.endContainer as HTMLElement
|
||||
let selectStartIndexPath=[],selectEndIndexPath=[]
|
||||
selectStartIndexPath.unshift(startOffset)
|
||||
if(startContainer.tagName=="DIV") {
|
||||
selectStartIndexPath.unshift(0)
|
||||
} else {
|
||||
let parentElement=startContainer.parentElement
|
||||
if(parentElement.tagName=="DIV") {
|
||||
startOffset=Array.from(parentElement.childNodes).indexOf(startContainer as Element)
|
||||
selectStartIndexPath.unshift(startOffset)
|
||||
startContainer=parentElement
|
||||
} else {
|
||||
startOffset=Array.from(parentElement.parentElement.childNodes).indexOf(parentElement as Element)
|
||||
selectStartIndexPath.unshift(startOffset)
|
||||
startContainer=parentElement.parentElement
|
||||
}
|
||||
let list=this.getSelectionItemList()
|
||||
let objStartInfo={
|
||||
startItem:null,
|
||||
startIndex:0
|
||||
}
|
||||
selectEndIndexPath.unshift(endOffset)
|
||||
if(endContainer.tagName=="DIV") {
|
||||
selectEndIndexPath.unshift(0)
|
||||
} else {
|
||||
let parentElement=endContainer.parentElement
|
||||
if(parentElement.tagName=="DIV") {
|
||||
endOffset=Array.from(parentElement.childNodes).indexOf(endContainer as Element)
|
||||
selectEndIndexPath.unshift(endOffset)
|
||||
endContainer=parentElement
|
||||
if(list.length==1) {
|
||||
let line=list[0].line
|
||||
let startItem=line.arr[line.selectStartIndexPath[0]]
|
||||
let endItem=line.arr[line.selectEndIndexPath[0]]
|
||||
if(startItem===endItem) {
|
||||
if(startItem.type===ECommon_Wiki_Content_Line_Config_Type.TEXT || startItem.type===ECommon_Wiki_Content_Line_Config_Type.LINK) {
|
||||
let start=startItem.value.substring(0,line.selectStartIndexPath[1])
|
||||
let end=startItem.value.substring(line.selectEndIndexPath[1])
|
||||
startItem.value=start+end
|
||||
} else {
|
||||
line.arr.splice(line.selectStartIndexPath[0],1)
|
||||
}
|
||||
objStartInfo.startItem=startItem
|
||||
objStartInfo.startIndex=line.selectStartIndexPath[1]
|
||||
} else {
|
||||
endOffset=Array.from(parentElement.parentElement.childNodes).indexOf(parentElement as Element)
|
||||
selectEndIndexPath.unshift(endOffset)
|
||||
endContainer=parentElement.parentElement
|
||||
}
|
||||
}
|
||||
if(startContainer==endContainer) {
|
||||
let index=Array.from(root.value.children).indexOf(startContainer as HTMLElement)
|
||||
let line=this.lineList[index];
|
||||
RichEditorHandle.handleInnerHtml(line,startContainer as HTMLElement)
|
||||
if(line.selectEndIndexPath[0]>line.selectStartIndexPath[0]) {
|
||||
let startItem=line.arr[line.selectStartIndexPath[0]]
|
||||
let endItem=line.arr[line.selectEndIndexPath[0]]
|
||||
for(let i=line.selectStartIndexPath[0]; i<=line.selectEndIndexPath[0]; i++) {
|
||||
let item=line.arr[i]
|
||||
if(item==startItem) {
|
||||
if(item.type==ELineConfigType.IMAGE) {
|
||||
line.arr.splice(i,1)
|
||||
i--;
|
||||
line.selectEndIndexPath[0]--
|
||||
for(let obj of list[0].data) {
|
||||
if(obj===startItem) {
|
||||
if(startItem.type===ECommon_Wiki_Content_Line_Config_Type.TEXT || startItem.type===ECommon_Wiki_Content_Line_Config_Type.LINK) {
|
||||
startItem.value=startItem.value.substring(0,line.selectStartIndexPath[1])
|
||||
} else {
|
||||
item.value=item.value.substring(0,line.selectStartIndexPath[1])
|
||||
line.arr.splice(line.arr.indexOf(startItem),1)
|
||||
}
|
||||
} else if(item==endItem) {
|
||||
if(item.type==ELineConfigType.IMAGE) {
|
||||
line.arr.splice(i,1)
|
||||
i--;
|
||||
line.selectEndIndexPath[0]--
|
||||
objStartInfo.startItem=startItem
|
||||
objStartInfo.startIndex=line.selectStartIndexPath[1]
|
||||
} else if(obj===endItem) {
|
||||
if(endItem.type===ECommon_Wiki_Content_Line_Config_Type.TEXT || endItem.type===ECommon_Wiki_Content_Line_Config_Type.LINK) {
|
||||
endItem.value=endItem.value.substring(line.selectEndIndexPath[1])
|
||||
} else {
|
||||
item.value=item.value.substring(line.selectEndIndexPath[1])
|
||||
line.arr.splice(line.arr.indexOf(endItem),1)
|
||||
}
|
||||
} else {
|
||||
line.arr.splice(i,1)
|
||||
i--;
|
||||
line.selectEndIndexPath[0]--
|
||||
line.arr.splice(line.arr.indexOf(obj),1)
|
||||
}
|
||||
}
|
||||
RichEditorHandle.fixLine(line)
|
||||
} else {
|
||||
let item=line.arr[line.selectStartIndexPath[0]]
|
||||
item.value=item.value.substring(0,line.selectStartIndexPath[1])+item.value.substring(line.selectEndIndexPath[1])
|
||||
RichEditorHandle.fixLine(line)
|
||||
}
|
||||
RichEditorHandle.fixLine(line,objStartInfo)
|
||||
} else {
|
||||
let indexStart=Array.from(root.value.children).indexOf(startContainer as HTMLElement)
|
||||
let indexEnd=Array.from(root.value.children).indexOf(endContainer as HTMLElement)
|
||||
let lineStart=this.lineList[indexStart];
|
||||
let lineEnd=this.lineList[indexEnd]
|
||||
let startItem=lineStart.arr[selectStartIndexPath[0]]
|
||||
let endItem=lineEnd.arr[selectEndIndexPath[0]]
|
||||
lineStart.arr.splice(selectStartIndexPath[0]+1)
|
||||
lineEnd.arr.splice(0,selectEndIndexPath[0])
|
||||
this.lineList.splice(indexStart+1,indexEnd-indexStart)
|
||||
startItem.value=startItem.value.substring(0,selectStartIndexPath[1])
|
||||
endItem.value=endItem.value.substring(selectEndIndexPath[1])
|
||||
lineStart.arr=lineStart.arr.concat(lineEnd.arr)
|
||||
RichEditorHandle.fixLine(lineStart)
|
||||
let startLine:ICommon_Wiki_Content_Line
|
||||
for(let i=0;i<list.length;i++) {
|
||||
let obj=list[i]
|
||||
let line=obj.line
|
||||
if(i==0 || i==list.length-1) {
|
||||
if(i==0) {
|
||||
startLine=line
|
||||
for(let i=0;i<obj.data.length;i++) {
|
||||
let startItem=obj.data[i]
|
||||
if(i==0) {
|
||||
if(startItem.type===ECommon_Wiki_Content_Line_Config_Type.TEXT || startItem.type===ECommon_Wiki_Content_Line_Config_Type.LINK) {
|
||||
startItem.value=startItem.value.substring(0,line.selectStartIndexPath[1])
|
||||
} else {
|
||||
line.arr.splice(line.arr.indexOf(startItem),1)
|
||||
}
|
||||
} else {
|
||||
line.arr.splice(line.arr.indexOf(startItem),1)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(let i=0;i<obj.data.length;i++) {
|
||||
let endItem=obj.data[i]
|
||||
if(i==obj.data.length-1) {
|
||||
if(endItem.type===ECommon_Wiki_Content_Line_Config_Type.TEXT || endItem.type===ECommon_Wiki_Content_Line_Config_Type.LINK) {
|
||||
endItem.value=endItem.value.substring(line.selectEndIndexPath[1])
|
||||
} else {
|
||||
line.arr.splice(line.arr.indexOf(endItem),1)
|
||||
}
|
||||
} else {
|
||||
line.arr.splice(line.arr.indexOf(endItem),1)
|
||||
}
|
||||
}
|
||||
startLine.arr=startLine.arr.concat(line.arr)
|
||||
this.lineList.splice(this.lineList.indexOf(line),1)
|
||||
RichEditorHandle.fixLine(startLine)
|
||||
}
|
||||
} else {
|
||||
this.lineList.splice(this.lineList.indexOf(line),1)
|
||||
}
|
||||
}
|
||||
}
|
||||
nextTick(()=>{
|
||||
let selection=window.getSelection()
|
||||
let range=document.createRange()
|
||||
let ele=startContainer.childNodes[selectStartIndexPath[0]] as HTMLElement
|
||||
let index=this.lineList.indexOf(list[0].line)
|
||||
let ele=this.root.value.children[index].childNodes[list[0].line.selectStartIndexPath[0]] as HTMLElement
|
||||
if(!ele) {
|
||||
return
|
||||
}
|
||||
if(ele.nodeType==Node.TEXT_NODE) {
|
||||
range.setStart(ele,selectStartIndexPath[1])
|
||||
range.setEnd(ele,selectStartIndexPath[1])
|
||||
} else if(ele.nodeType==Node.ELEMENT_NODE) {
|
||||
if(ele.tagName=="IMG") {
|
||||
range.selectNode(ele)
|
||||
range.collapse(false)
|
||||
if(ele.nodeType===Node.TEXT_NODE || ele.tagName==="SPAN") {
|
||||
let text=ele.tagName==="SPAN"?ele.innerText:ele.textContent
|
||||
if(list[0].line.selectStartIndexPath[1]>=text.length) {
|
||||
range.setStartAfter(ele)
|
||||
range.setEndAfter(ele)
|
||||
} else {
|
||||
range.setStart(ele.firstChild,selectStartIndexPath[1])
|
||||
range.setEnd(ele.firstChild,selectStartIndexPath[1])
|
||||
range.setStart(ele,list[0].line.selectStartIndexPath[1])
|
||||
range.setEnd(ele,list[0].line.selectStartIndexPath[1])
|
||||
}
|
||||
} else {
|
||||
range.setStartAfter(ele)
|
||||
range.setEndAfter(ele)
|
||||
}
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
@ -1046,8 +1211,11 @@ export class RichEditorEvent {
|
||||
}
|
||||
})
|
||||
}
|
||||
getSelectionItemList():LineConfig[] {
|
||||
let selectLineList:Line[]=[]
|
||||
getSelectionItemList():{
|
||||
line:ICommon_Wiki_Content_Line,
|
||||
data:ICommon_Wiki_Content_Line_Config[]
|
||||
}[] {
|
||||
let selectLineList:ICommon_Wiki_Content_Line[]=[]
|
||||
this.selectElementList.forEach((ele)=>{
|
||||
selectLineList.push(this.lineList[Array.from(this.root.value.children).indexOf(ele)])
|
||||
})
|
||||
@ -1066,9 +1234,11 @@ export class RichEditorEvent {
|
||||
if(parentElement.tagName=="DIV") {
|
||||
startOffset=Array.from(parentElement.childNodes).indexOf(startContainer as Element)
|
||||
selectStartIndexPath.unshift(startOffset)
|
||||
startContainer=parentElement
|
||||
} else {
|
||||
startOffset=Array.from(parentElement.parentElement.childNodes).indexOf(parentElement as Element)
|
||||
selectStartIndexPath.unshift(startOffset)
|
||||
startContainer=parentElement.parentElement
|
||||
}
|
||||
}
|
||||
if(endContainer.tagName=="DIV") {
|
||||
@ -1079,31 +1249,57 @@ export class RichEditorEvent {
|
||||
if(parentElement.tagName=="DIV") {
|
||||
endOffset=Array.from(parentElement.childNodes).indexOf(endContainer as Element)
|
||||
selectEndIndexPath.unshift(endOffset)
|
||||
endContainer=parentElement
|
||||
} else {
|
||||
endOffset=Array.from(parentElement.parentElement.childNodes).indexOf(parentElement as Element)
|
||||
selectEndIndexPath.unshift(endOffset)
|
||||
endContainer=parentElement.parentElement
|
||||
}
|
||||
}
|
||||
let startLine=selectLineList[0]
|
||||
startLine.selectStartIndexPath=selectStartIndexPath
|
||||
let endLine=selectLineList[selectLineList.length-1]
|
||||
let itemList:LineConfig[]=[]
|
||||
endLine.selectEndIndexPath=selectEndIndexPath
|
||||
let itemList:{
|
||||
line:ICommon_Wiki_Content_Line,
|
||||
data:ICommon_Wiki_Content_Line_Config[]
|
||||
}[]=[]
|
||||
if(selectLineList.length==1) {
|
||||
itemList=[...selectLineList[0].arr.slice(selectStartIndexPath[0],selectEndIndexPath[0]+1)]
|
||||
RichEditorHandle.handleInnerHtml(selectLineList[0],startContainer)
|
||||
itemList=[{
|
||||
line:selectLineList[0],
|
||||
data:[...selectLineList[0].arr.slice(selectStartIndexPath[0],selectEndIndexPath[0]+1)]
|
||||
}]
|
||||
} else {
|
||||
for(let line of selectLineList) {
|
||||
let obj=itemList.find(value => {
|
||||
return value.line===line
|
||||
})
|
||||
if(!obj) {
|
||||
obj={
|
||||
line:line,
|
||||
data:[]
|
||||
}
|
||||
itemList.push(obj)
|
||||
}
|
||||
if(line==startLine) {
|
||||
RichEditorHandle.handleInnerHtml(line,startContainer)
|
||||
for (let i = selectStartIndexPath[0]; i < startLine.arr.length; i++) {
|
||||
let item=startLine.arr[i]
|
||||
itemList.push(item)
|
||||
obj.data.push(item)
|
||||
}
|
||||
} else if(line==endLine) {
|
||||
RichEditorHandle.handleInnerHtml(line,endContainer)
|
||||
for (let i = 0; i <= selectEndIndexPath[0]; i++) {
|
||||
let item=endLine.arr[i]
|
||||
itemList.push(item)
|
||||
if(item) {
|
||||
obj.data.push(item)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RichEditorHandle.handleInnerHtml(line,this.root.value.children[this.lineList.indexOf(line)] as HTMLElement)
|
||||
line.arr.forEach(item=>{
|
||||
itemList.push(item)
|
||||
obj.data.push(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1112,9 +1308,9 @@ export class RichEditorEvent {
|
||||
}
|
||||
getCurrentInfo():{
|
||||
element:HTMLElement,
|
||||
line:Line,
|
||||
line:ICommon_Wiki_Content_Line,
|
||||
lineIndex:number,
|
||||
item:LineConfig,
|
||||
item:ICommon_Wiki_Content_Line_Config,
|
||||
itemIndex
|
||||
}{
|
||||
let selection=window.getSelection()
|
||||
@ -1126,7 +1322,7 @@ export class RichEditorEvent {
|
||||
}
|
||||
let lineIndex=Array.from(this.root.value.children).indexOf(element)
|
||||
let line=this.lineList[lineIndex]
|
||||
let item:LineConfig,itemIndex:number
|
||||
let item:ICommon_Wiki_Content_Line_Config,itemIndex:number
|
||||
if(container!=element) {
|
||||
itemIndex=Array.from(element.childNodes).indexOf(container as HTMLElement)
|
||||
item=line.arr[itemIndex]
|
||||
|
2337
code/client/src/business/common/component/richEditor/font/css/font-awesome.css
vendored
Normal file
2337
code/client/src/business/common/component/richEditor/font/css/font-awesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
code/client/src/business/common/component/richEditor/font/css/font-awesome.min.css
vendored
Normal file
4
code/client/src/business/common/component/richEditor/font/css/font-awesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,7 +1,11 @@
|
||||
import {ELineConfigType, Line, LineConfig} from "./type";
|
||||
import {nextTick} from "vue";
|
||||
import {RichEditorEvent} from "./event";
|
||||
import {RichEditorHandle} from "./handle";
|
||||
import {
|
||||
ECommon_Wiki_Content_Line_Config_Type,
|
||||
ICommon_Wiki_Content_Line,
|
||||
ICommon_Wiki_Content_Line_Config
|
||||
} from "../../../../../../common/model/wiki_item_content";
|
||||
|
||||
function handleLink(obj:RichEditorEvent,link:string) {
|
||||
let lineList=obj.getLineList()
|
||||
@ -10,11 +14,11 @@ function handleLink(obj:RichEditorEvent,link:string) {
|
||||
if(selectElementList.length==1) {
|
||||
let selectLine=lineList[Array.from(root.value.children).indexOf(selectElementList[0])]
|
||||
if(selectLine.selectStartIndexPath.length>0 && selectLine.selectEndIndexPath.length>0) {
|
||||
let newItem:LineConfig,newItemValueLength:number
|
||||
let newItem:ICommon_Wiki_Content_Line_Config,newItemValueLength:number
|
||||
if(selectLine.selectEndIndexPath[0]>selectLine.selectStartIndexPath[0]) {
|
||||
let startItem=selectLine.arr[selectLine.selectStartIndexPath[0]]
|
||||
let endItem=selectLine.arr[selectLine.selectEndIndexPath[0]]
|
||||
let newItem:LineConfig
|
||||
let newItem:ICommon_Wiki_Content_Line_Config
|
||||
for(let i=selectLine.selectStartIndexPath[0]; i<=selectLine.selectEndIndexPath[0]; i++) {
|
||||
let item=selectLine.arr[i]
|
||||
if(item==startItem) {
|
||||
@ -24,7 +28,7 @@ function handleLink(obj:RichEditorEvent,link:string) {
|
||||
...item.style
|
||||
},
|
||||
value: item.value.substring(selectLine.selectStartIndexPath[1]),
|
||||
type:ELineConfigType.LINK,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.LINK,
|
||||
link:link
|
||||
}
|
||||
item.value=item.value.substring(0,selectLine.selectStartIndexPath[1])
|
||||
@ -34,7 +38,7 @@ function handleLink(obj:RichEditorEvent,link:string) {
|
||||
startItem=newItem
|
||||
} else {
|
||||
item.link=link
|
||||
item.type=ELineConfigType.LINK
|
||||
item.type=ECommon_Wiki_Content_Line_Config_Type.LINK
|
||||
startItem=item
|
||||
}
|
||||
} else if(item==endItem) {
|
||||
@ -64,7 +68,7 @@ function handleLink(obj:RichEditorEvent,link:string) {
|
||||
if(!item) {
|
||||
return;
|
||||
}
|
||||
let startIndex:number,endIndex:number,selectItem:LineConfig
|
||||
let startIndex:number,endIndex:number,selectItem:ICommon_Wiki_Content_Line_Config
|
||||
let str=item.value.substring(selectLine.selectStartIndexPath[1],selectLine.selectEndIndexPath[1])
|
||||
let startStr=item.value.substring(0,selectLine.selectStartIndexPath[1])
|
||||
let endStr=item.value.substring(selectLine.selectEndIndexPath[1])
|
||||
@ -74,7 +78,7 @@ function handleLink(obj:RichEditorEvent,link:string) {
|
||||
style:{
|
||||
...item.style
|
||||
},
|
||||
type:ELineConfigType.LINK,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.LINK,
|
||||
link:link
|
||||
}
|
||||
selectLine.arr.splice(selectLine.selectStartIndexPath[0]+1,0,newItem,{
|
||||
@ -113,8 +117,8 @@ function handleImage(obj:RichEditorEvent,link:string,width:number) {
|
||||
let selectLine=lineList[Array.from(root.value.children).indexOf(selectElementList[0])]
|
||||
RichEditorHandle.handleInnerHtml(selectLine,root.value.children[lineList.indexOf(selectLine)] as HTMLElement)
|
||||
if(selectLine.arr.length==0) {
|
||||
let imageItem:LineConfig={
|
||||
type:ELineConfigType.IMAGE,
|
||||
let imageItem:ICommon_Wiki_Content_Line_Config={
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.IMAGE,
|
||||
link,
|
||||
value:"",
|
||||
width
|
||||
@ -122,14 +126,14 @@ function handleImage(obj:RichEditorEvent,link:string,width:number) {
|
||||
selectLine.arr.push(imageItem)
|
||||
} else {
|
||||
let selectItem=selectLine.arr[selectLine.selectStartIndexPath[0]]
|
||||
let imageItem:LineConfig={
|
||||
type:ELineConfigType.IMAGE,
|
||||
let imageItem:ICommon_Wiki_Content_Line_Config={
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.IMAGE,
|
||||
value:"",
|
||||
link,
|
||||
width
|
||||
}
|
||||
let newItem:LineConfig=JSON.parse(JSON.stringify(selectItem))
|
||||
if(newItem.type==ELineConfigType.IMAGE) {
|
||||
let newItem:ICommon_Wiki_Content_Line_Config=JSON.parse(JSON.stringify(selectItem))
|
||||
if(newItem.type==ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
selectLine.arr.splice(selectLine.selectStartIndexPath[0]+1,0,imageItem)
|
||||
} else {
|
||||
newItem.value=newItem.value.substring(selectLine.selectStartIndexPath[1])
|
||||
@ -147,7 +151,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
if(selectElementList.length==1) {
|
||||
let selectLine=lineList[Array.from(root.value.children).indexOf(selectElementList[0])]
|
||||
if(selectLine.selectStartIndexPath.length>0 && selectLine.selectEndIndexPath.length>0) {
|
||||
let newItem:LineConfig,newItemValueLength:number
|
||||
let newItem:ICommon_Wiki_Content_Line_Config,newItemValueLength:number
|
||||
if(selectLine.selectEndIndexPath[0]>selectLine.selectStartIndexPath[0]) {
|
||||
let startItem=selectLine.arr[selectLine.selectStartIndexPath[0]]
|
||||
let endItem=selectLine.arr[selectLine.selectEndIndexPath[0]]
|
||||
@ -156,14 +160,14 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
let item=selectLine.arr[i]
|
||||
if(item==startItem) {
|
||||
if(selectLine.selectStartIndexPath[1]>0 && item.style[style]!=value) {
|
||||
let newItem:LineConfig
|
||||
let newItem:ICommon_Wiki_Content_Line_Config
|
||||
if(value) {
|
||||
newItem = {
|
||||
style: Object.assign({}, item.style, {
|
||||
[style]: value
|
||||
}),
|
||||
value: item.value.substring(selectLine.selectStartIndexPath[1]),
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
} else {
|
||||
let objStyle={
|
||||
@ -173,7 +177,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
newItem = {
|
||||
style: objStyle,
|
||||
value: item.value.substring(selectLine.selectStartIndexPath[1]),
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
}
|
||||
item.value=item.value.substring(0,selectLine.selectStartIndexPath[1])
|
||||
@ -195,14 +199,14 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
}
|
||||
} else if(item==endItem) {
|
||||
if(selectLine.selectEndIndexPath[1]<item.value.length && item.style[style]!=value) {
|
||||
let newItem:LineConfig
|
||||
let newItem:ICommon_Wiki_Content_Line_Config
|
||||
if(value) {
|
||||
newItem={
|
||||
style:Object.assign({},item.style,{
|
||||
[style]:value
|
||||
}),
|
||||
value:item.value.substring(0,selectLine.selectEndIndexPath[1]),
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
} else {
|
||||
let objStyle={
|
||||
@ -212,7 +216,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
newItem = {
|
||||
style: objStyle,
|
||||
value: item.value.substring(0,selectLine.selectEndIndexPath[1]),
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
}
|
||||
item.value=item.value.substring(selectLine.selectEndIndexPath[1])
|
||||
@ -280,7 +284,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
if(!item) {
|
||||
return;
|
||||
}
|
||||
let startIndex:number,endIndex:number,selectItem:LineConfig
|
||||
let startIndex:number,endIndex:number,selectItem:ICommon_Wiki_Content_Line_Config
|
||||
if(item.style[style]!=value) {
|
||||
let str=item.value.substring(selectLine.selectStartIndexPath[1],selectLine.selectEndIndexPath[1])
|
||||
let startStr=item.value.substring(0,selectLine.selectStartIndexPath[1])
|
||||
@ -306,7 +310,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
style:{
|
||||
...item.style
|
||||
},
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
})
|
||||
RichEditorHandle.fixLine(selectLine)
|
||||
startIndex=0;
|
||||
@ -341,7 +345,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
}
|
||||
}
|
||||
} else if(selectElementList.length>1) {
|
||||
let selectLineList:Line[]=[]
|
||||
let selectLineList:ICommon_Wiki_Content_Line[]=[]
|
||||
selectElementList.forEach((ele)=>{
|
||||
selectLineList.push(lineList[Array.from(root.value.children).indexOf(ele)])
|
||||
})
|
||||
@ -382,7 +386,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
let endLine=selectLineList[selectLineList.length-1]
|
||||
let startItem=startLine.arr[selectStartIndexPath[0]]
|
||||
let endItem=endLine.arr[selectEndIndexPath[0]]
|
||||
let startSelectItem:LineConfig=startItem,endSelectItem:LineConfig=endItem
|
||||
let startSelectItem:ICommon_Wiki_Content_Line_Config=startItem,endSelectItem:ICommon_Wiki_Content_Line_Config=endItem
|
||||
let startIndex,endIndex
|
||||
for(let line of selectLineList) {
|
||||
if(line==startLine) {
|
||||
@ -390,7 +394,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
let item=startLine.arr[i]
|
||||
if(item.style[style]!=value) {
|
||||
if(item==startItem) {
|
||||
let newItem:LineConfig
|
||||
let newItem:ICommon_Wiki_Content_Line_Config
|
||||
if(value) {
|
||||
newItem={
|
||||
value:item.value.substring(selectStartIndexPath[1]),
|
||||
@ -398,7 +402,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
...item.style,
|
||||
[style]:value
|
||||
},
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
} else {
|
||||
let objStyle={
|
||||
@ -408,7 +412,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
newItem={
|
||||
value:item.value.substring(selectStartIndexPath[1]),
|
||||
style:objStyle,
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
}
|
||||
item.value=item.value.substring(0,selectStartIndexPath[1])
|
||||
@ -434,7 +438,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
let item=endLine.arr[i]
|
||||
if(item.style[style]!=value) {
|
||||
if(item==endItem) {
|
||||
let newItem:LineConfig
|
||||
let newItem:ICommon_Wiki_Content_Line_Config
|
||||
if(value) {
|
||||
newItem={
|
||||
value:item.value.substring(0,selectEndIndexPath[1]),
|
||||
@ -442,7 +446,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
...item.style,
|
||||
[style]:value
|
||||
},
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
} else {
|
||||
let objStyle={
|
||||
@ -452,7 +456,7 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
newItem={
|
||||
value:item.value.substring(0,selectEndIndexPath[1]),
|
||||
style:objStyle,
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
}
|
||||
item.value=item.value.substring(selectEndIndexPath[1])
|
||||
@ -528,7 +532,12 @@ function handle(obj:RichEditorEvent,style:string,value:string) {
|
||||
}
|
||||
|
||||
function check(obj:RichEditorEvent,style:string,value:string):boolean {
|
||||
let itemList=obj.getSelectionItemList()
|
||||
let itemList=[]
|
||||
obj.getSelectionItemList().forEach(item=>{
|
||||
itemList.push(...item.data.filter(item=>{
|
||||
return item.type===ECommon_Wiki_Content_Line_Config_Type.TEXT || item.type===ECommon_Wiki_Content_Line_Config_Type.LINK
|
||||
}))
|
||||
})
|
||||
for(let item of itemList) {
|
||||
if(!item.style || item.style[style]!=value) {
|
||||
return false
|
||||
|
@ -1,71 +1,105 @@
|
||||
import {nextTick, toRaw} from "vue";
|
||||
import {ELineConfigType, Line, LineConfig} from "./type";
|
||||
|
||||
import {
|
||||
ECommon_Wiki_Content_Line_Config_Type,
|
||||
ICommon_Wiki_Content_Line,
|
||||
ICommon_Wiki_Content_Line_Config
|
||||
} from "../../../../../../common/model/wiki_item_content";
|
||||
|
||||
export class RichEditorHandle {
|
||||
static handle(line:Line){
|
||||
static handle(line:ICommon_Wiki_Content_Line){
|
||||
let str=""
|
||||
for(let obj of line.arr) {
|
||||
let ele:HTMLElement
|
||||
if(obj.type==ELineConfigType.TEXT) {
|
||||
if(obj.type==ECommon_Wiki_Content_Line_Config_Type.TEXT) {
|
||||
if(obj.style && Object.keys(obj.style).length>0) {
|
||||
ele=document.createElement("span")
|
||||
ele.innerText=obj.value
|
||||
if(obj.style) {
|
||||
for(let key in obj.style) {
|
||||
ele.style[key]=obj.style[key]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
str+=obj.value
|
||||
continue;
|
||||
}
|
||||
} else if(obj.type==ELineConfigType.LINK) {
|
||||
} else if(obj.type==ECommon_Wiki_Content_Line_Config_Type.LINK) {
|
||||
ele=document.createElement("a")
|
||||
ele.setAttribute("href",obj.link)
|
||||
ele.setAttribute("target","_blank")
|
||||
ele.style.cursor="pointer"
|
||||
} else if(obj.type==ELineConfigType.IMAGE) {
|
||||
ele.innerText=obj.value
|
||||
if(obj.style) {
|
||||
for(let key in obj.style) {
|
||||
ele.style[key]=obj.style[key]
|
||||
}
|
||||
}
|
||||
} else if(obj.type==ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
ele=document.createElement("img")
|
||||
ele.setAttribute("src",obj.link)
|
||||
ele.setAttribute("width",String(obj.width))
|
||||
ele.setAttribute("height","auto")
|
||||
}
|
||||
if(obj.style) {
|
||||
for(let key in obj.style) {
|
||||
ele.style[key]=obj.style[key]
|
||||
}
|
||||
ele.setAttribute("fileId",obj.value)
|
||||
} else if(obj.type===ECommon_Wiki_Content_Line_Config_Type.FILE) {
|
||||
ele=document.createElement("a")
|
||||
ele.setAttribute("href",obj.link)
|
||||
ele.setAttribute("download",obj.label)
|
||||
ele.setAttribute("fileId",obj.value)
|
||||
ele.style.margin="0 2px 0 2px"
|
||||
ele.style.cursor="pointer"
|
||||
ele.contentEditable="false"
|
||||
ele.innerText=obj.label
|
||||
ele.style.color="black"
|
||||
let icon=document.createElement("i")
|
||||
icon.className="fa fa-file"
|
||||
icon.style.marginRight="5px"
|
||||
icon.style.color="gray"
|
||||
ele.prepend(icon)
|
||||
}
|
||||
if(ele) {
|
||||
ele.innerText=obj.value
|
||||
str+=ele.outerHTML
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
static handleInnerHtml(item:Line,root:HTMLElement,relocate:boolean=false){
|
||||
static handleInnerHtml(item:ICommon_Wiki_Content_Line, root:HTMLElement, relocate:boolean=false){
|
||||
item.selectEndIndexPath=[]
|
||||
item.selectStartIndexPath=[]
|
||||
item.arr=[]
|
||||
root.childNodes.forEach(node=>{
|
||||
if(node.nodeType==Node.TEXT_NODE) {
|
||||
let objTemp:LineConfig={
|
||||
let objTemp:ICommon_Wiki_Content_Line_Config={
|
||||
value:node.nodeValue,
|
||||
style:{},
|
||||
type:ELineConfigType.TEXT
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
}
|
||||
item.arr.push(objTemp)
|
||||
} else if(node.nodeType==Node.ELEMENT_NODE) {
|
||||
let obj=<LineConfig>{
|
||||
let obj=<ICommon_Wiki_Content_Line_Config>{
|
||||
value:"",
|
||||
style:{}
|
||||
}
|
||||
let ele=node as HTMLElement
|
||||
if(ele.tagName=="SPAN") {
|
||||
obj.type=ELineConfigType.TEXT
|
||||
obj.type=ECommon_Wiki_Content_Line_Config_Type.TEXT
|
||||
obj.value=ele.innerText??""
|
||||
} else if(ele.tagName=="A") {
|
||||
obj.type=ELineConfigType.LINK
|
||||
obj.link=ele.getAttribute("href")
|
||||
obj.value=ele.innerText??""
|
||||
let fileId=ele.getAttribute("fileId")
|
||||
if(fileId) {
|
||||
obj.type=ECommon_Wiki_Content_Line_Config_Type.FILE
|
||||
obj.link=ele.getAttribute("href")
|
||||
obj.value=fileId
|
||||
obj.label=ele.innerText??""
|
||||
} else {
|
||||
obj.type=ECommon_Wiki_Content_Line_Config_Type.LINK
|
||||
obj.link=ele.getAttribute("href")
|
||||
obj.value=ele.innerText??""
|
||||
}
|
||||
} else if(ele.tagName=="IMG") {
|
||||
obj.type=ELineConfigType.IMAGE
|
||||
obj.type=ECommon_Wiki_Content_Line_Config_Type.IMAGE
|
||||
obj.link=ele.getAttribute("src")
|
||||
obj.width=parseInt(ele.getAttribute("width"))
|
||||
obj.value=ele.getAttribute("fileId")
|
||||
}
|
||||
if(ele.style?.color) {
|
||||
obj.style.color=ele.style?.color
|
||||
@ -99,7 +133,7 @@ export class RichEditorHandle {
|
||||
if(startContainer.childNodes.length==0 || startOffset>=startContainer.childNodes.length) {
|
||||
item.selectStartIndexPath=[startOffset>0?(startOffset-1):0,startContainer.childNodes.length==0?0:(startContainer.lastChild.textContent?startContainer.lastChild.textContent.length:0)]
|
||||
} else {
|
||||
item.selectStartIndexPath=[startOffset,startContainer.lastChild.textContent.length]
|
||||
item.selectStartIndexPath=[startOffset,0]
|
||||
}
|
||||
} else {
|
||||
item.selectStartIndexPath.unshift(startOffset)
|
||||
@ -180,11 +214,11 @@ export class RichEditorHandle {
|
||||
})
|
||||
}
|
||||
}
|
||||
static fixLine(line:Line,objItem?:{startItem?:LineConfig,endItem?:LineConfig,startIndex?:number,endIndex?:number}){
|
||||
static fixLine(line:ICommon_Wiki_Content_Line, objItem?:{startItem?:ICommon_Wiki_Content_Line_Config,endItem?:ICommon_Wiki_Content_Line_Config,startIndex?:number,endIndex?:number}){
|
||||
for(let i=1;i<line.arr.length;i++) {
|
||||
let obj=line.arr[i]
|
||||
let preObj=line.arr[i-1]
|
||||
if((obj.style && preObj.style && JSON.stringify(obj.style)===JSON.stringify(preObj.style) && obj.type==preObj.type && obj.type==ELineConfigType.TEXT) || (!obj.value && obj.type!=ELineConfigType.IMAGE)) {
|
||||
if((obj.style && preObj.style && JSON.stringify(obj.style)===JSON.stringify(preObj.style) && obj.type==preObj.type && obj.type==ECommon_Wiki_Content_Line_Config_Type.TEXT) || (!obj.value && obj.type!=ECommon_Wiki_Content_Line_Config_Type.IMAGE)) {
|
||||
let len=preObj.value.length
|
||||
preObj.value+=obj.value
|
||||
line.arr.splice(i,1)
|
||||
@ -203,7 +237,7 @@ export class RichEditorHandle {
|
||||
}
|
||||
for(let i=0;i<line.arr.length;i++) {
|
||||
let obj=line.arr[i]
|
||||
if(!obj.value && obj.type!=ELineConfigType.IMAGE) {
|
||||
if(!obj.value && obj.type!=ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
line.arr.splice(i,1)
|
||||
i--
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div class="item" v-for="(item,index) in list" style="height: 35px;display:flex;align-items: center;justify-content: center;cursor: pointer" :key="item.type" :style="{borderBottom:index!==list.length-1?'rgb(241,241,241) 1px solid':''}" @mousedown="onClick(item)">
|
||||
{{item.title}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
import {ICommon_Wiki_Content_Line_Config} from "../../../../../../common/model/wiki_item_content";
|
||||
import {RichEditorEvent} from "./event";
|
||||
import {RichEditorHandle} from "./handle";
|
||||
|
||||
const props=defineProps<{
|
||||
objEditor:RichEditorEvent,
|
||||
popMenuList?:{
|
||||
type: any,
|
||||
title: string
|
||||
}[]
|
||||
}>()
|
||||
const list = ref(props.popMenuList??[])
|
||||
|
||||
const onClick=async (item:{
|
||||
type:any,
|
||||
title:string
|
||||
})=>{
|
||||
let itemList=props.objEditor.getSelectionItemList()
|
||||
let selectStartIndexPath=JSON.parse(JSON.stringify(itemList[0].line.selectStartIndexPath))
|
||||
props.objEditor.onPopMenuClickFunc?.(item.type,item1 => {
|
||||
let line=itemList[0].line
|
||||
let originItem=line.arr[selectStartIndexPath[0]]
|
||||
let objTemp:ICommon_Wiki_Content_Line_Config=JSON.parse(JSON.stringify(originItem))
|
||||
objTemp.value=originItem.value.substring(selectStartIndexPath[1])
|
||||
originItem.value=originItem.value.substring(0,selectStartIndexPath[1]-1)
|
||||
line.arr.splice(selectStartIndexPath[0]+1,0,item1,objTemp)
|
||||
RichEditorHandle.fixLine(line)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
</style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="root" @mouseover="onMouseOver" @keydown="onKeyDown" style="padding: 10px" :style="{border:border?'border: 1px solid lightgray;':'0px'}">
|
||||
<div ref="root" @mouseover="onMouseOver" @keydown="onKeyDown" style="padding: 10px" :style="{border:border?'border: 1px solid lightgray;':'0px'}" @copy="onCopy">
|
||||
<div v-for="(item,index) in lineList" :key="index" contenteditable="true" @blur="onBlur(item,$event)" ref="elementList" v-html="RichEditorHandle.handle(item)" @keydown.enter="onEnter(item,index,$event)" @keydown.delete="onDelete(index,item,$event)" style="line-height: 1.5" @focus="onFocus(item,$event)" @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove" @dblclick="onDbClick" @paste="onPaste" placeholder="type your content" v-if="!readonly">
|
||||
</div>
|
||||
<div v-for="(item,index) in lineList" :key="index+1" v-html="RichEditorHandle.handle(item)" style="line-height: 1.5;min-height: 21px" v-else>
|
||||
@ -10,53 +10,96 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, watch} from "vue";
|
||||
import {getCurrentInstance, onBeforeUnmount, ref, watch} from "vue";
|
||||
import {RichEditorEvent} from "./event";
|
||||
import {Line} from "./type";
|
||||
import {RichEditorHandle} from "./handle";
|
||||
import {
|
||||
ICommon_Wiki_Content_Line,
|
||||
ICommon_Wiki_Content_Line_Config
|
||||
} from "../../../../../../common/model/wiki_item_content";
|
||||
import "./font/css/font-awesome.min.css"
|
||||
|
||||
const emit=defineEmits<{
|
||||
(e:"update:modelValue",value:Line[]):void
|
||||
(e:"update:modelValue",value:ICommon_Wiki_Content_Line[]):void
|
||||
(e:"uploadFile", file:File, handleFunc:(fileId:string, path:string)=>void):void
|
||||
(e:"popMenuClick",type:any,handleFunc:(item:ICommon_Wiki_Content_Line_Config)=>void):void
|
||||
}>()
|
||||
const props=defineProps<{
|
||||
readonly?:boolean,
|
||||
modelValue:Line[],
|
||||
border?:boolean
|
||||
modelValue:ICommon_Wiki_Content_Line[],
|
||||
border?:boolean,
|
||||
popMenuList?:{
|
||||
type: any,
|
||||
title: string
|
||||
}[]
|
||||
}>()
|
||||
|
||||
const root=ref<HTMLElement>()
|
||||
const elementList=ref<HTMLElement[]>([])
|
||||
const objEditor=new RichEditorEvent(root,elementList)
|
||||
const objEditor=new RichEditorEvent(root,elementList,getCurrentInstance().appContext)
|
||||
if(props.popMenuList) {
|
||||
objEditor.setPopMenuList(props.popMenuList)
|
||||
}
|
||||
objEditor.onUploadFileFunc=(file, handleFunc) => {
|
||||
emit("uploadFile",file,handleFunc)
|
||||
}
|
||||
objEditor.onPopMenuClickFunc=(type, handleFunc) => {
|
||||
emit("popMenuClick",type,handleFunc)
|
||||
}
|
||||
const lineList=objEditor.getLineList()
|
||||
let historyList:ICommon_Wiki_Content_Line[][]=[]
|
||||
let recall=false
|
||||
watch(lineList,()=>{
|
||||
emit("update:modelValue",lineList)
|
||||
},{
|
||||
deep:true
|
||||
})
|
||||
watch(()=>props.modelValue,()=>{
|
||||
|
||||
watch(()=>props.modelValue,(value, oldValue, onCleanup)=>{
|
||||
objEditor.setLineList(props.modelValue)
|
||||
if(lineList.length==0) {
|
||||
objEditor.addLine("")
|
||||
}
|
||||
if(oldValue && oldValue.length>0 && !recall) {
|
||||
let obj=JSON.parse(JSON.stringify(oldValue))
|
||||
obj.forEach(obj=>{
|
||||
delete obj.selectStartIndexPath
|
||||
delete obj.selectEndIndexPath
|
||||
})
|
||||
let str=JSON.stringify(obj)
|
||||
if(historyList.length==0) {
|
||||
historyList.unshift(obj)
|
||||
} else {
|
||||
let objFirst=historyList[0]
|
||||
if(JSON.stringify(objFirst)!==str) {
|
||||
historyList.unshift(obj)
|
||||
}
|
||||
}
|
||||
if(historyList.length>10) {
|
||||
historyList.pop()
|
||||
}
|
||||
} else if(recall===true) {
|
||||
recall=false
|
||||
}
|
||||
},{
|
||||
deep:true,
|
||||
immediate:true
|
||||
})
|
||||
const onFocus=(item:Line,event:MouseEvent)=>{
|
||||
const onFocus=(item:ICommon_Wiki_Content_Line, event:MouseEvent)=>{
|
||||
objEditor.onFocus(item,event)
|
||||
}
|
||||
const onDbClick=(event:MouseEvent)=>{
|
||||
objEditor.onDbClick(event)
|
||||
}
|
||||
|
||||
const onBlur=(item:Line,event:FocusEvent)=>{
|
||||
const onBlur=(item:ICommon_Wiki_Content_Line, event:FocusEvent)=>{
|
||||
objEditor.onBlur(item,event)
|
||||
}
|
||||
|
||||
const onEnter=(line:Line,index:number,event:MouseEvent)=>{
|
||||
const onEnter=(line:ICommon_Wiki_Content_Line, index:number, event:MouseEvent)=>{
|
||||
objEditor.onEnter(line,index,event)
|
||||
}
|
||||
const onDelete=(index,item:Line,event:MouseEvent)=>{
|
||||
const onDelete=(index, item:ICommon_Wiki_Content_Line, event:MouseEvent)=>{
|
||||
objEditor.onDelete(index,item,event)
|
||||
}
|
||||
|
||||
@ -80,12 +123,28 @@ const onMouseOver=(event:MouseEvent)=>{
|
||||
}
|
||||
}
|
||||
|
||||
const onCopy=(event:ClipboardEvent)=>{
|
||||
objEditor.onCopy(event)
|
||||
}
|
||||
|
||||
const onKeyDown=(event:KeyboardEvent)=>{
|
||||
if(!props.readonly) {
|
||||
objEditor.onKeyDown(event)
|
||||
if(event.key=="z" && (event.metaKey || event.ctrlKey)) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
if(historyList.length>0) {
|
||||
let list=historyList.shift()
|
||||
objEditor.setLineList(list)
|
||||
}
|
||||
recall=true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(()=>{
|
||||
objEditor.clear()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -102,4 +161,7 @@ div {
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
}
|
||||
:deep a[fileId]:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
</style>
|
@ -1,26 +0,0 @@
|
||||
export enum ELineConfigType {
|
||||
TEXT,
|
||||
LINK,
|
||||
IMAGE
|
||||
}
|
||||
export type LineStyle={
|
||||
fontStyle?:string
|
||||
fontWeight?:string,
|
||||
color?:string,
|
||||
backgroundColor?:string,
|
||||
textDecoration?:string,
|
||||
fontSize?:string
|
||||
}
|
||||
|
||||
export type LineConfig={
|
||||
style?:LineStyle,
|
||||
value:string
|
||||
link?:string,
|
||||
type:ELineConfigType,
|
||||
width?:number
|
||||
}
|
||||
export type Line={
|
||||
arr:LineConfig[],
|
||||
selectStartIndexPath?:number[],
|
||||
selectEndIndexPath?:number[]
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div style="width: 100%;height: 100%;display: grid;grid-template-rows:repeat(auto-fill,120px);grid-template-columns: repeat(auto-fill,100px);align-items: center;justify-items: center" v-drop.file.shortcut.folder.disk="objFinderHandle.onDrop.bind(objFinderHandle,props.folderId)" v-select v-menu.self="objFinderHandle.contextMenuFunc.bind(objFinderHandle)" :key="folderId" @click="$event.currentTarget===$event.target && selectItem()">
|
||||
<div style="width: 100%;height: 100%;display: grid;grid-template-rows:repeat(auto-fill,120px);grid-template-columns: repeat(auto-fill,100px);align-items: center;justify-items: center;" v-drop.file.shortcut.folder.disk="objFinderHandle.onDrop.bind(objFinderHandle,props.folderId)" v-select v-menu.self="objFinderHandle.contextMenuFunc.bind(objFinderHandle)" :key="folderId" @click="$event.currentTarget===$event.target && selectItem()" onselectstart="return false">
|
||||
<template v-for="(item,index) in itemList" :key="item.meta.id">
|
||||
<IconItem :item="item" :index="index" v-if="item.meta.type===ECommon_Model_Finder_Item_Type.FILE" v-selectable.file="item.meta.id" @click="selectItem(item.meta)">
|
||||
</IconItem>
|
||||
@ -37,7 +37,6 @@ const emit=defineEmits<{
|
||||
selectItem:[item:DCSType<ICommon_Model_Finder_Item>]
|
||||
}>()
|
||||
|
||||
|
||||
const appContext=getCurrentInstance().appContext
|
||||
const root=getRootNavigatorRef()
|
||||
const objFinderHandle=new FinderHandle(root,appContext,props.folderId)
|
||||
|
@ -14,7 +14,6 @@ import {
|
||||
DCSType
|
||||
} from "../../../common/request/request";
|
||||
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../common/event/event";
|
||||
import {Message} from "@arco-design/web-vue";
|
||||
import {useDesktopStore} from "../../desktop/store/desktop";
|
||||
import {
|
||||
ECommon_Model_Finder_Item_Type,
|
||||
@ -26,6 +25,7 @@ import {selectedSelectableItems} from "../../../../teamOS/common/directive/selec
|
||||
import {IClient_Drag_Element} from "../../../../teamOS/common/directive/drag";
|
||||
import {DropParam} from "../../../../teamOS/common/directive/drop";
|
||||
import {SessionStorage} from "../../../common/storage/session";
|
||||
import {Message} from "@arco-design/web-vue";
|
||||
|
||||
export class FinderHandle {
|
||||
private itemList=ref<Icon[]>([])
|
||||
|
@ -14,7 +14,7 @@
|
||||
import {onDialogOk} from "../../../../common/component/dialog/dialog";
|
||||
import {reactive, ref} from "vue";
|
||||
import {apiIssue, DCSType} from "../../../../common/request/request";
|
||||
import {ICommon_Route_Res_Project_filter_Item} from "../../../../../../../common/routes/response";
|
||||
import {ICommon_Route_Res_Project_Issue_filter_Item} from "../../../../../../../common/routes/response";
|
||||
import {dialogFuncGenerator} from "../../../../common/util/helper";
|
||||
|
||||
const props=defineProps<{
|
||||
@ -25,7 +25,7 @@ const eleForm=ref(null)
|
||||
const form=reactive({
|
||||
issueId:""
|
||||
})
|
||||
const issueList=ref<DCSType<ICommon_Route_Res_Project_filter_Item[]>>([])
|
||||
const issueList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item[]>>([])
|
||||
const onSearch=async (keyword:string)=>{
|
||||
let res=await apiIssue.filter({
|
||||
name:keyword,
|
||||
|
@ -87,19 +87,19 @@ import {ECommon_Model_Workflow_Node_Status} from "../../../../../../../common/mo
|
||||
import {getCurrentInstance, inject, markRaw, onBeforeMount, reactive, ref} from "vue";
|
||||
import {apiIssue, apiOrganization, apiProject, DCSType} from "../../../../common/request/request";
|
||||
import {
|
||||
ICommon_Route_Res_Organization_User_Item,
|
||||
ICommon_Route_Res_Project_CreateModule_Data,
|
||||
ICommon_Route_Res_Project_filter_Item
|
||||
ICommon_Route_Res_Organization_User_Item,
|
||||
ICommon_Route_Res_Project_CreateModule_Data,
|
||||
ICommon_Route_Res_Project_Issue_filter_Item
|
||||
} from "../../../../../../../common/routes/response";
|
||||
import {injectProjectInfo} from "../../../../common/util/symbol";
|
||||
import {checkPermission} from "../../../../common/util/helper";
|
||||
import {Permission_Types} from "../../../../../../../common/permission/permission";
|
||||
import {Dialog} from "../../../../common/component/dialog/dialog";
|
||||
import {
|
||||
ETeamOS_Navigator_Action,
|
||||
getCurrentNavigator,
|
||||
getRootNavigatorRef,
|
||||
onNavigatorShow
|
||||
ETeamOS_Navigator_Action,
|
||||
getCurrentNavigator,
|
||||
getRootNavigatorRef,
|
||||
onNavigatorShow
|
||||
} from "../../../../../teamOS/common/component/navigator/navigator";
|
||||
import ProjectIssueCreate from "./projectIssueCreate.vue";
|
||||
import UserAvatar from "../../../../common/component/userAvatar.vue";
|
||||
@ -169,7 +169,7 @@ const assignerId=ref("all")
|
||||
const assignerList=ref<DCSType<ICommon_Route_Res_Organization_User_Item[]>>([])
|
||||
const reporterId=ref("all")
|
||||
const reporterList=ref<DCSType<ICommon_Route_Res_Organization_User_Item[]>>([])
|
||||
const issueList=ref<DCSType<ICommon_Route_Res_Project_filter_Item[]>>([])
|
||||
const issueList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item[]>>([])
|
||||
const root=getRootNavigatorRef();
|
||||
const appContext=getCurrentInstance().appContext
|
||||
const navigator=getCurrentNavigator();
|
||||
|
@ -7,7 +7,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {defineProps, onBeforeMount, reactive, ref} from "vue"
|
||||
import {onBeforeMount, reactive, ref} from "vue"
|
||||
import {ICommon_Route_Res_Workflow_Node_List_Item} from "../../../../../../../common/routes/response";
|
||||
import {apiField, apiWorkflow} from "../../../../common/request/request";
|
||||
import {onDialogOk} from "../../../../common/component/dialog/dialog";
|
||||
|
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div style="width: 100%;height: 100%">
|
||||
<a-row>
|
||||
<a-input-search></a-input-search>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -33,7 +33,7 @@
|
||||
<a-input style="width: 80%;margin-top: 10px;border: 0px;background-color: transparent" autofocus placeholder="type you title" :input-attrs="{style:{fontSize:'20px'}}" v-model="title" :readonly="!isWrite"></a-input>
|
||||
</a-row>
|
||||
<a-row style="width: 100%;height: calc(100% - 60px);margin-top: 10px;justify-content: center;overflow-y: auto">
|
||||
<RichEditor v-model="content" :readonly="!isWrite" style="width: 80%"></RichEditor>
|
||||
<RichEditor v-model="content" :readonly="!isWrite" style="width: 80%" @upload-file="onUploadFile" :pop-menu-list="popMenuList" @pop-menu-click="onPopMenuClick"></RichEditor>
|
||||
</a-row>
|
||||
</a-row>
|
||||
</div>
|
||||
@ -41,12 +41,16 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {onBeforeMount, ref, watch} from "vue";
|
||||
import {apiWiki, DCSType} from "../../../common/request/request";
|
||||
import {apiFile, apiWiki, DCSType} from "../../../common/request/request";
|
||||
import moment from "moment";
|
||||
import {ICommon_Model_Wiki_Item_Content} from "../../../../../../common/model/wiki_item_content";
|
||||
import {
|
||||
ECommon_Wiki_Content_Line_Config_Type,
|
||||
ICommon_Model_Wiki_Item_Content,
|
||||
ICommon_Wiki_Content_Line,
|
||||
ICommon_Wiki_Content_Line_Config
|
||||
} from "../../../../../../common/model/wiki_item_content";
|
||||
import UserAvatar from "../../../common/component/userAvatar.vue";
|
||||
import RichEditor from "../../../common/component/richEditor/richEditor.vue";
|
||||
import {Line} from "../../../common/component/richEditor/type";
|
||||
import {checkPermission} from "../../../common/util/helper";
|
||||
import {Permission_Types} from "../../../../../../common/permission/permission";
|
||||
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../common/model/finder_item";
|
||||
@ -70,7 +74,46 @@ const title=ref(props.name)
|
||||
const path=ref(props.path)
|
||||
const isWrite=ref(false)
|
||||
const info=ref<DCSType<ICommon_Model_Wiki_Item_Content>>()
|
||||
const content=ref<Line[]>([])
|
||||
const content=ref<ICommon_Wiki_Content_Line[]>([])
|
||||
const popMenuList=ref([
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.IMAGE,
|
||||
title: "Image"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.FILE,
|
||||
title: "File"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.PROJECT,
|
||||
title: "Project"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.PROJECT_ISSUE,
|
||||
title: "Project Issue"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.PROJECT_RELEASE,
|
||||
title: "Project Release"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.WIKI,
|
||||
title: "Wiki Space"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.WIKI_ITEM,
|
||||
title: "Wiki Item"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.CALENDAR_EVENT,
|
||||
title: "Calendar Event"
|
||||
},
|
||||
{
|
||||
type: ECommon_Wiki_Content_Line_Config_Type.MEETING_ROOM,
|
||||
title: "Meeting Room"
|
||||
},
|
||||
])
|
||||
let loadDate:number
|
||||
watch(()=>props.name,()=>{
|
||||
title.value=props.name
|
||||
})
|
||||
@ -95,8 +138,11 @@ watch(title,()=>{
|
||||
titleTimer=null;
|
||||
},500)
|
||||
})
|
||||
watch(content,()=>{
|
||||
watch(content,(value, oldValue, onCleanup)=>{
|
||||
let now=Date.now()
|
||||
if(!loadDate || now-loadDate<300) {
|
||||
return
|
||||
}
|
||||
if(contentTimerStamps==0 || now-contentTimerStamps<500) {
|
||||
if(contentTimer) {
|
||||
clearInterval(contentTimer)
|
||||
@ -125,8 +171,56 @@ const getContent=async ()=>{
|
||||
if(res?.code==0) {
|
||||
info.value=res.data
|
||||
content.value=info.value.content?JSON.parse(info.value.content):[]
|
||||
loadDate=Date.now()
|
||||
}
|
||||
}
|
||||
|
||||
const onUploadFile=async (file, handleFunc) => {
|
||||
let res=await apiFile.upload({
|
||||
file:file
|
||||
})
|
||||
if(res?.code==0) {
|
||||
handleFunc(res.data.id,res.data.path)
|
||||
}
|
||||
}
|
||||
|
||||
const onPopMenuClick=async (type:ECommon_Wiki_Content_Line_Config_Type,handleFunc:(item:ICommon_Wiki_Content_Line_Config)=>void)=>{
|
||||
if(type===ECommon_Wiki_Content_Line_Config_Type.IMAGE || type===ECommon_Wiki_Content_Line_Config_Type.FILE) {
|
||||
let input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
if(type===ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
input.accept=".png,.jpg,.gif,.jpeg,.bmp,.webp"
|
||||
}
|
||||
input.onchange=async (ev:InputEvent) => {
|
||||
let files=Array.from((ev.target as HTMLInputElement).files)
|
||||
if(files.length>0) {
|
||||
let res=await apiFile.upload({
|
||||
file:files[0] as any
|
||||
})
|
||||
if(res?.code==0) {
|
||||
let fileId=res.data.id
|
||||
let path=res.data.path
|
||||
let objImageItem:ICommon_Wiki_Content_Line_Config=type===ECommon_Wiki_Content_Line_Config_Type.IMAGE?{
|
||||
value:fileId,
|
||||
link:path,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.IMAGE,
|
||||
width:200
|
||||
}:{
|
||||
value:fileId,
|
||||
link:path,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type.FILE,
|
||||
label:files[0].name
|
||||
}
|
||||
handleFunc(objImageItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
input.click();
|
||||
} else if(type===ECommon_Wiki_Content_Line_Config_Type.PROJECT) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(()=>{
|
||||
getContent()
|
||||
})
|
||||
|
@ -16,6 +16,8 @@ import RegisterCode from "./business/controller/login/registerCode.vue";
|
||||
import Reset from "./business/controller/login/reset.vue";
|
||||
import ResetCode from "./business/controller/login/resetCode.vue";
|
||||
import {ECommon_Application_Mode} from "../../common/types";
|
||||
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
|
||||
|
||||
|
||||
const Desktop =()=>import("./business/controller/desktop/desktop.vue")
|
||||
const routes=[
|
||||
@ -69,6 +71,7 @@ app.use(ArcoVueIcon)
|
||||
app.use(createPinia())
|
||||
app.use(router);
|
||||
app.component("sicon",sicon)
|
||||
app.component("icon",FontAwesomeIcon)
|
||||
app.mount('#app')
|
||||
|
||||
apiGateway.deployInfo().then(async value => {
|
||||
|
@ -1,5 +1,41 @@
|
||||
import {BaseModel} from "./base"
|
||||
|
||||
export enum ECommon_Wiki_Content_Line_Config_Type {
|
||||
TEXT,
|
||||
LINK,
|
||||
IMAGE,
|
||||
FILE,
|
||||
PROJECT,
|
||||
PROJECT_ISSUE,
|
||||
PROJECT_RELEASE,
|
||||
WIKI,
|
||||
WIKI_ITEM,
|
||||
CALENDAR_EVENT,
|
||||
MEETING_ROOM
|
||||
}
|
||||
|
||||
export type ICommon_Wiki_Content_Line_Style ={
|
||||
fontStyle?:string
|
||||
fontWeight?:string,
|
||||
color?:string,
|
||||
backgroundColor?:string,
|
||||
textDecoration?:string,
|
||||
fontSize?:string
|
||||
}
|
||||
|
||||
export type ICommon_Wiki_Content_Line_Config ={
|
||||
style?:ICommon_Wiki_Content_Line_Style,
|
||||
value:string
|
||||
link?:string,
|
||||
type:ECommon_Wiki_Content_Line_Config_Type,
|
||||
width?:number,
|
||||
label?:string
|
||||
}
|
||||
export type ICommon_Wiki_Content_Line ={
|
||||
arr:ICommon_Wiki_Content_Line_Config[],
|
||||
selectStartIndexPath?:number[],
|
||||
selectEndIndexPath?:number[]
|
||||
}
|
||||
export interface ICommon_Model_Wiki_Item_Content {
|
||||
id :string ,
|
||||
wiki_item_id:string,
|
||||
|
@ -1,7 +1,11 @@
|
||||
import {ECommon_Services} from "../types"
|
||||
import {ECommon_HttpApi_Method} from "./types"
|
||||
import {ECommon_Calendar_Color, ICommon_Model_Calendar} from "../model/calendar";
|
||||
import {ICommon_Route_Res_Calendar_Event_Info, ICommon_Route_Res_Calendar_ListEvent_Item} from "./response";
|
||||
import {
|
||||
ICommon_Route_Res_Calendar_Event_Filter,
|
||||
ICommon_Route_Res_Calendar_Event_Info,
|
||||
ICommon_Route_Res_Calendar_ListEvent_Item
|
||||
} from "./response";
|
||||
import {ECommon_Calendar_Recurring_Type} from "../model/calendar_event";
|
||||
import {ECommon_Calendar_WeekDay, ICommon_Model_Calendar_Setting} from "../model/calendar_setting";
|
||||
import {Permission_Types} from "../permission/permission";
|
||||
@ -140,6 +144,18 @@ const api= {
|
||||
res: <ICommon_Model_Calendar>{},
|
||||
permission: [Permission_Types.Organization.READ]
|
||||
},
|
||||
filterEvent:{
|
||||
method: ECommon_HttpApi_Method.GET,
|
||||
path: "/calendar/event/filter",
|
||||
req: <{
|
||||
calendarId?:string,
|
||||
name?:string,
|
||||
page:number,
|
||||
size:number
|
||||
}>{},
|
||||
res: <ICommon_Route_Res_Calendar_Event_Filter>{},
|
||||
permission: [Permission_Types.Organization.READ]
|
||||
}
|
||||
}
|
||||
}
|
||||
export default api
|
@ -14,6 +14,7 @@ const api={
|
||||
}>{},
|
||||
res:<{
|
||||
id:string,
|
||||
path:string,
|
||||
meta?:string
|
||||
}>{}
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ import {ICommon_Model_Project_Module} from './../model/project_module';
|
||||
import {
|
||||
ICommon_Route_Req_ProjectIssue_Field,
|
||||
ICommon_Route_Req_ProjectIssue_Field_Value,
|
||||
ICommon_Route_Res_Project_filter,
|
||||
ICommon_Route_Res_Project_Issue_filter,
|
||||
ICommon_Route_Res_ProjectIssue_BasicInfo,
|
||||
ICommon_Route_Res_ProjectIssue_fieldsInfo,
|
||||
ICommon_Route_Res_Workflow_Node_Field
|
||||
@ -292,7 +292,7 @@ const api={
|
||||
method:ECommon_HttpApi_Method.GET,
|
||||
path:"/filter",
|
||||
req:<{
|
||||
projectId :string,
|
||||
projectId? :string,
|
||||
createdBy?:string,
|
||||
issueTypeId?:string,
|
||||
name?:string,
|
||||
@ -305,7 +305,7 @@ const api={
|
||||
page:number,
|
||||
size:number
|
||||
}>{},
|
||||
res:<ICommon_Route_Res_Project_filter>{},
|
||||
res:<ICommon_Route_Res_Project_Issue_filter>{},
|
||||
permission:[Permission_Types.Project.READ]
|
||||
},
|
||||
releaseList:{
|
||||
|
@ -17,7 +17,7 @@ const api={
|
||||
method:ECommon_HttpApi_Method.GET,
|
||||
path:"/list",
|
||||
req:<{
|
||||
projectId:string,
|
||||
projectId?:string,
|
||||
name?:string,
|
||||
status?:ECommon_Model_Project_Release_Status,
|
||||
page:number,
|
||||
|
@ -19,7 +19,7 @@ import {ICommon_Model_Member_Tag} from "../model/member_tag";
|
||||
import {ICommon_Field_Type} from "../field/type";
|
||||
import {ICommon_Model_Wiki} from "../model/wiki";
|
||||
import {ICommon_Model_Calendar_Event} from "../model/calendar_event";
|
||||
import {ECommon_Calendar_Color} from "../model/calendar";
|
||||
import {ECommon_Calendar_Color, ICommon_Model_Calendar} from "../model/calendar";
|
||||
import {ICommon_Model_Finder_Item} from "../model/finder_item";
|
||||
import {ICommon_Model_File} from "../model/file";
|
||||
import {ICommon_Model_Wiki_Item} from "../model/wiki_item";
|
||||
@ -67,6 +67,13 @@ export type ICommon_Route_Res_Wiki_Item_Info=ICommon_Model_Wiki_Item & {
|
||||
wiki:ICommon_Model_Wiki
|
||||
}
|
||||
|
||||
export type ICommon_Route_Res_Wiki_Item_Filter={
|
||||
data:ICommon_Route_Res_Wiki_Item_Info[],
|
||||
count:number,
|
||||
totalPage:number,
|
||||
page:number
|
||||
}
|
||||
|
||||
export type ICommon_Route_Res_User_List = {
|
||||
count:number,
|
||||
totalPage:number,
|
||||
@ -189,7 +196,7 @@ export interface ICommon_Route_Res_userWikiList {
|
||||
data:ICommon_Model_Wiki[]
|
||||
}
|
||||
|
||||
export interface ICommon_Route_Res_Project_filter_Item {
|
||||
export interface ICommon_Route_Res_Project_Issue_filter_Item {
|
||||
id:string,
|
||||
name:string,
|
||||
unique_id:number,
|
||||
@ -203,11 +210,12 @@ export interface ICommon_Route_Res_Project_filter_Item {
|
||||
reporter_id:string,
|
||||
created_time:Date,
|
||||
created_by:string,
|
||||
priority:ECommon_Model_Project_Issue_Priority
|
||||
priority:ECommon_Model_Project_Issue_Priority,
|
||||
project:ICommon_Model_Project
|
||||
}
|
||||
|
||||
export interface ICommon_Route_Res_Project_filter {
|
||||
data:ICommon_Route_Res_Project_filter_Item[],
|
||||
export interface ICommon_Route_Res_Project_Issue_filter {
|
||||
data:ICommon_Route_Res_Project_Issue_filter_Item[],
|
||||
count:number,
|
||||
totalPage:number,
|
||||
page:number,
|
||||
@ -223,7 +231,8 @@ export interface ICommon_Route_Res_Release_List {
|
||||
export interface ICommon_Route_Res_Release_Item extends ICommon_Model_Project_Release {
|
||||
notstart:number,
|
||||
inprogress:number,
|
||||
done:number
|
||||
done:number,
|
||||
project:ICommon_Model_Project
|
||||
}
|
||||
|
||||
export type ICommon_Route_Res_Release_Info_Issue_Item = Omit<ICommon_Model_Project_Issue,"issue_type_id"|"workflow_node_id"> & {
|
||||
@ -332,6 +341,15 @@ export type ICommon_Route_Res_Calendar_Event_Info = ICommon_Model_Calendar_Event
|
||||
}[]
|
||||
}
|
||||
|
||||
export type ICommon_Route_Res_Calendar_Event_Filter={
|
||||
count:number,
|
||||
totalPage:number,
|
||||
page:number,
|
||||
data:(ICommon_Model_Calendar_Event & {
|
||||
calendar:ICommon_Model_Calendar
|
||||
})[]
|
||||
}
|
||||
|
||||
export type ICommon_Route_Res_Organization_FilterUserAndTeam = {
|
||||
users:{
|
||||
id:string,
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
ICommon_Route_Res_Role_List,
|
||||
ICommon_Route_Res_Role_ListMember,
|
||||
ICommon_Route_Res_userWikiList,
|
||||
ICommon_Route_Res_Wiki_Info,
|
||||
ICommon_Route_Res_Wiki_Info, ICommon_Route_Res_Wiki_Item_Filter,
|
||||
ICommon_Route_Res_Wiki_Item_Info
|
||||
} from "./response";
|
||||
import {ICommon_Model_Wiki_Item} from "../model/wiki_item";
|
||||
@ -26,7 +26,7 @@ const api= {
|
||||
|
||||
}>{},
|
||||
res: <ICommon_Model_Wiki[]>{},
|
||||
permission: [Permission_Types.Wiki.READ]
|
||||
permission: [Permission_Types.Organization.READ]
|
||||
},
|
||||
userWikiList: {
|
||||
method: ECommon_HttpApi_Method.GET,
|
||||
@ -38,7 +38,7 @@ const api= {
|
||||
type:"all"|"created"|"joined"
|
||||
}>{},
|
||||
res: <ICommon_Route_Res_userWikiList>{},
|
||||
permission: [Permission_Types.Wiki.READ]
|
||||
permission: [Permission_Types.Organization.READ]
|
||||
},
|
||||
list: {
|
||||
method: ECommon_HttpApi_Method.GET,
|
||||
@ -50,7 +50,7 @@ const api= {
|
||||
organizationUserId?:string
|
||||
}>{},
|
||||
res: <ICommon_Route_Res_userWikiList>{},
|
||||
permission: [Permission_Types.Wiki.READ]
|
||||
permission: [Permission_Types.Organization.READ]
|
||||
},
|
||||
addWiki: {
|
||||
method: ECommon_HttpApi_Method.POST,
|
||||
@ -265,6 +265,18 @@ const api= {
|
||||
res: <ICommon_Route_Res_Wiki_Item_Info>{},
|
||||
permission: [Permission_Types.Wiki.READ]
|
||||
},
|
||||
filterWikiItem:{
|
||||
method: ECommon_HttpApi_Method.GET,
|
||||
path: "/item/filter",
|
||||
req: <{
|
||||
wikiId?:string,
|
||||
name?:string,
|
||||
size:number,
|
||||
page:number
|
||||
}>{},
|
||||
res: <ICommon_Route_Res_Wiki_Item_Filter>{},
|
||||
permission: [Permission_Types.Wiki.READ]
|
||||
}
|
||||
}
|
||||
}
|
||||
export default api
|
@ -118,6 +118,10 @@ export namespace Err {
|
||||
code:3004,
|
||||
msg:"project id not match"
|
||||
},
|
||||
projectKeywordDuplicate:{
|
||||
code:3004,
|
||||
msg:"project keyword duplicate"
|
||||
},
|
||||
Label:{
|
||||
labelSizeEmpty:{
|
||||
code:3100,
|
||||
|
@ -98,4 +98,10 @@ class PermissionClear {
|
||||
await obj.del()
|
||||
}
|
||||
|
||||
@DEventListener("roleChange")
|
||||
async roleChange(roleId:string) {
|
||||
let obj=new REDIS_AUTH.Permission.Role.RoleInfo(roleId)
|
||||
await obj.del()
|
||||
}
|
||||
|
||||
}
|
@ -205,4 +205,10 @@ class CalendarController {
|
||||
}
|
||||
return obj.getItem()
|
||||
}
|
||||
|
||||
@DHttpApi(calendarApi.routes.filterEvent)
|
||||
async filterEvent(@DHttpReqParam("calendarId") calendarId:string,@DHttpReqParam("name") name:string,@DHttpReqParamRequired("size") size:number,@DHttpReqParamRequired("page") page:number,@DHttpUser user:IUserSession):Promise<typeof calendarApi.routes.filterEvent.res> {
|
||||
let ret=await CalendarEventService.filterEvent(user.organizationInfo.organizationUserId,calendarId,name,page,size)
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import {calendarSettingModel, ECommon_Calendar_WeekDay} from "../../../common/mo
|
||||
import {Err} from "../../../common/status/error";
|
||||
import {getMysqlInstance} from "../../common/db/mysql";
|
||||
import {
|
||||
convertCountSql,
|
||||
generateBatchCreateSql,
|
||||
generateDeleteInnerJoin2Sql,
|
||||
generateDeleteInnerJoinSql,
|
||||
@ -17,6 +18,8 @@ import {calendarEventModel, ECommon_Calendar_Recurring_Type} from "../../../comm
|
||||
import {calendarEventGuestModel, ICommon_Model_Calendar_Event_Guest} from "../../../common/model/calendar_event_guest";
|
||||
import {ICommon_Route_Res_Calendar_ListEvent_Item} from "../../../common/routes/response";
|
||||
import * as moment from "moment";
|
||||
import {keys} from "../../../common/transform";
|
||||
import CommonUtil from "../../common/util/common";
|
||||
|
||||
|
||||
class CalendarMapper extends Mapper<typeof calendarModel> {
|
||||
@ -663,6 +666,61 @@ class CalendarEventMapper extends Mapper<typeof calendarEventModel> {
|
||||
}
|
||||
return isMatch
|
||||
}
|
||||
|
||||
async filterEvent(organizationUserId:string,calendarId:string,name:string,page:number,size:number) {
|
||||
if(page===undefined || page<0 || size===undefined || size<=0) {
|
||||
throw Err.Common.paramError
|
||||
}
|
||||
let mysql=getMysqlInstance()
|
||||
let sql=generateLeftJoinSql({
|
||||
model:calendarEventModel,
|
||||
columns:keys<typeof calendarEventModel["model"]>().map(item=>item.name)
|
||||
},{
|
||||
model:calendarModel,
|
||||
columns:keys<typeof calendarModel["model"]>().map(item=>item.name),
|
||||
aggregation:"calendar",
|
||||
expression:{
|
||||
id:{
|
||||
model:calendarEventModel,
|
||||
field:"calendar_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
organization_user_id:{
|
||||
model:calendarModel,
|
||||
value:organizationUserId
|
||||
},
|
||||
...(calendarId && {
|
||||
calendar_id:{
|
||||
model:calendarEventModel,
|
||||
value:calendarId
|
||||
}
|
||||
}),
|
||||
...(name && {
|
||||
name:{
|
||||
model:calendarEventModel,
|
||||
value:{
|
||||
exp:"%like%",
|
||||
value:name
|
||||
}
|
||||
}
|
||||
}),
|
||||
},"and",{
|
||||
model:calendarEventModel,
|
||||
field:"name",
|
||||
type:"asc"
|
||||
},page*size,size)
|
||||
let countSql=convertCountSql(sql);
|
||||
let count=Number(Object.values(await mysql.executeOne(countSql))[0])
|
||||
let totalPage=CommonUtil.pageTotal(count,size)
|
||||
let ret=await mysql.execute(sql)
|
||||
return {
|
||||
count:count,
|
||||
totalPage:totalPage,
|
||||
page:page,
|
||||
data:ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const calendarEventMapper=new CalendarEventMapper
|
||||
|
@ -136,6 +136,11 @@ export class CalendarEventService extends Entity<typeof calendarEventModel,typeo
|
||||
let arr=calendarEventMapper.getMemberList(this.getId(),this.getItem().calendar_id)
|
||||
return arr;
|
||||
}
|
||||
|
||||
static async filterEvent(organizationUserId:string,calendarId:string,name:string,page:number,size:number) {
|
||||
let ret=await calendarEventMapper.filterEvent(organizationUserId,calendarId,name,page,size)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
export class CalendarSettingService extends Entity<typeof calendarSettingModel,typeof calendarSettingMapper> {
|
||||
|
@ -4,8 +4,8 @@ export interface IServer_Common_Event_Types {
|
||||
userDelete:(userId:string)=>void
|
||||
projectDelete:(projectId:string)=>void
|
||||
teamDelete:(teamId:string)=>void
|
||||
fileRef:(fileId:string)=>void
|
||||
fileUnref:(fileId:string)=>void
|
||||
fileRef:(fileId:string,count?:number)=>void
|
||||
fileUnref:(fileId:string,count?:number)=>void
|
||||
fileUpload:(meta:string,fileId:string)=>void
|
||||
issueTypeDelete:(issueTypeId:string)=>void
|
||||
organizationUserAdd:(organizationId:string,organizationUserId:string)=>void
|
||||
@ -18,4 +18,5 @@ export interface IServer_Common_Event_Types {
|
||||
teamUserAdd:(teamId:string,organizationUserId:string)=>void
|
||||
teamUserEdit:(teamId:string,organizationUserId:string)=>void
|
||||
teamUserDelete:(teamId:string,organizationUserId:string)=>void
|
||||
roleChange:(roleId:string)=>void
|
||||
}
|
@ -298,7 +298,7 @@ class IssueController {
|
||||
}
|
||||
|
||||
@DHttpApi(projectIssueApi.routes.filter)
|
||||
async filter(@DHttpReqParamRequired("projectId") projectId :string,
|
||||
async filter(@DHttpReqParam("projectId") projectId :string,
|
||||
@DHttpReqParam("createdBy") createdBy :string,
|
||||
@DHttpReqParam("issueTypeId") issueTypeId :string,
|
||||
@DHttpReqParam("name") name :string,
|
||||
@ -309,8 +309,8 @@ class IssueController {
|
||||
@DHttpReqParam("moduleId") moduleId :string,
|
||||
@DHttpReqParam("labelId") labelId :string,
|
||||
@DHttpReqParamRequired("page") page :number,
|
||||
@DHttpReqParamRequired("size") size :number):Promise<typeof projectIssueApi.routes.filter.res> {
|
||||
let ret=await ProjectIssueService.filter(projectId ,page ,size ,createdBy ,issueTypeId,name,priority,assignerId,reporterId,status,moduleId,labelId)
|
||||
@DHttpReqParamRequired("size") size :number,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.filter.res> {
|
||||
let ret=await ProjectIssueService.filter(user.organizationInfo.organizationId,projectId ,page ,size ,createdBy ,issueTypeId,name,priority,assignerId,reporterId,status,moduleId,labelId)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,13 @@ class ProjectController {
|
||||
|
||||
@DHttpApi(projectApi.routes.create)
|
||||
async createProject(@DHttpReqParamRequired("name") name:string,@DHttpReqParamRequired("keyword") keyword:string,@DHttpReqParam("photo") photo:string,@DHttpReqParam("description") description:string,@DHttpUser user:IUserSession):Promise<typeof projectApi.routes.create.res>{
|
||||
let objProject=await ProjectService.getItemByExp({
|
||||
organization_id:user.organizationInfo.organizationId,
|
||||
keyword
|
||||
})
|
||||
if(objProject) {
|
||||
throw Err.Project.projectKeywordDuplicate
|
||||
}
|
||||
let obj=new ProjectService()
|
||||
obj.assignItem({
|
||||
keyword:keyword,
|
||||
|
@ -10,8 +10,8 @@ import {IUserSession} from "../../user/types/config";
|
||||
@DHttpController(releaseApi)
|
||||
class ReleaseController {
|
||||
@DHttpApi(releaseApi.routes.list)
|
||||
async list(@DHttpReqParamRequired("projectId") projectId:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("name") name:string,@DHttpReqParam("status") status:ECommon_Model_Project_Release_Status):Promise<typeof releaseApi.routes.list.res> {
|
||||
let list=await ProjectReleaseService.list(projectId,page,size,name,status)
|
||||
async list(@DHttpReqParam("projectId") projectId:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("name") name:string,@DHttpReqParam("status") status:ECommon_Model_Project_Release_Status,@DHttpUser user:IUserSession):Promise<typeof releaseApi.routes.list.res> {
|
||||
let list=await ProjectReleaseService.list(user.organizationInfo.organizationId,projectId,page,size,name,status)
|
||||
return list;
|
||||
}
|
||||
@DHttpApi(releaseApi.routes.info)
|
||||
|
@ -3,7 +3,7 @@ import {ICommon_Model_Project_Issue, projectIssueModel} from "../../../common/mo
|
||||
import {ICommon_Model_Project_Label, projectLabelModel} from "../../../common/model/project_label";
|
||||
import {ICommon_Model_Project_Module, projectModuleModel} from "../../../common/model/project_module";
|
||||
import {workflowNodeModel} from "../../../common/model/workflow_node";
|
||||
import {ICommon_Route_Res_Project_filter} from "../../../common/routes/response";
|
||||
import {ICommon_Route_Res_Project_Issue_filter} from "../../../common/routes/response";
|
||||
import {Err} from "../../../common/status/error";
|
||||
import {keys} from "../../../common/transform";
|
||||
import {getMysqlInstance} from '../../common/db/mysql';
|
||||
@ -14,7 +14,6 @@ import {
|
||||
generateBatchCreateSql,
|
||||
generateCreateSql,
|
||||
generateDeleteSql,
|
||||
generateLeftJoin2Sql,
|
||||
generateLeftJoin3Sql,
|
||||
generateLeftJoinSql,
|
||||
generateQuerySql,
|
||||
@ -607,11 +606,21 @@ class ProjectIssueMapper extends Mapper<typeof projectIssueModel> {
|
||||
}
|
||||
}
|
||||
|
||||
async filter(projectId :string,page :number,size :number,createdBy? :string,issueTypeId? :string,name? :string,priority? :number,assignerId? :string,reporterId? :string,status? :number,moduleId? :string,labelId? :string):Promise<ICommon_Route_Res_Project_filter> {
|
||||
if(!projectId) {
|
||||
throw Err.Project.projectNotFound
|
||||
}
|
||||
async filter(organizationId:string,projectId :string,page :number,size :number,createdBy? :string,issueTypeId? :string,name? :string,priority? :number,assignerId? :string,reporterId? :string,status? :number,moduleId? :string,labelId? :string):Promise<ICommon_Route_Res_Project_Issue_filter> {
|
||||
let mysql=getMysqlInstance()
|
||||
if(!projectId && name && name.includes("-")) {
|
||||
let arr=name.split("-")
|
||||
let projectUniqueId=arr[0]
|
||||
name=arr[1]
|
||||
let obj=await mysql.executeOne(generateQuerySql(projectModel,["id"],{
|
||||
keyword:projectUniqueId,
|
||||
organization_id:organizationId
|
||||
}))
|
||||
if(!obj) {
|
||||
throw Err.Project.projectNotFound
|
||||
}
|
||||
projectId=obj.id
|
||||
}
|
||||
let setId:Set<string>=new Set;
|
||||
if(moduleId) {
|
||||
let arrModuleIssueId=(await mysql.execute(generateQuerySql(projectModuleIssueModel,["id"],{
|
||||
@ -629,7 +638,7 @@ class ProjectIssueMapper extends Mapper<typeof projectIssueModel> {
|
||||
setId.add(obj)
|
||||
}
|
||||
}
|
||||
let sql=generateLeftJoin2Sql({
|
||||
let sql=generateLeftJoin3Sql({
|
||||
model:projectIssueModel,
|
||||
columns:["id","assigner_id","reporter_id","unique_id","name","unique_id","created_time","created_by","priority"]
|
||||
},{
|
||||
@ -652,10 +661,26 @@ class ProjectIssueMapper extends Mapper<typeof projectIssueModel> {
|
||||
}
|
||||
}
|
||||
},{
|
||||
project_id:{
|
||||
model:projectIssueModel,
|
||||
value:projectId
|
||||
model:projectModel,
|
||||
columns:keys<typeof projectModel["model"]>().map(item=>item.name),
|
||||
aggregation:"project",
|
||||
expression:{
|
||||
id:{
|
||||
model:projectIssueModel,
|
||||
field:"project_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
organization_id:{
|
||||
model:projectModel,
|
||||
value:organizationId
|
||||
},
|
||||
...(projectId && {
|
||||
project_id:{
|
||||
model:projectIssueModel,
|
||||
value:projectId
|
||||
}
|
||||
}),
|
||||
...(createdBy && {
|
||||
created_by:{
|
||||
model:projectIssueModel,
|
||||
|
@ -5,10 +5,11 @@ import {getMysqlInstance} from "../../common/db/mysql";
|
||||
import {Mapper} from "../../common/entity/mapper";
|
||||
import CommonUtil from "../../common/util/common";
|
||||
import {
|
||||
generateCountSql,
|
||||
convertCountSql,
|
||||
generateCreateSql,
|
||||
generateDeleteSql,
|
||||
generateGroupLeftJoin2Sql,
|
||||
generateGroupLeftJoin3Sql,
|
||||
generateLeftJoin3Sql,
|
||||
generateLeftJoinSql,
|
||||
generateQuerySql,
|
||||
@ -27,47 +28,69 @@ import {
|
||||
ICommon_Route_Res_Release_Item,
|
||||
ICommon_Route_Res_Release_List
|
||||
} from './../../../common/routes/response';
|
||||
import {projectModel} from "../../../common/model/project";
|
||||
|
||||
class ReleaseMapper extends Mapper<typeof projectReleaseModel> {
|
||||
constructor() {
|
||||
super(projectReleaseModel)
|
||||
}
|
||||
async list(projectId:string,page:number,size:number,name?:string,status?:ECommon_Model_Project_Release_Status):Promise<ICommon_Route_Res_Release_List> {
|
||||
if(!projectId || page===undefined || page<0 || size===undefined || size<=0) {
|
||||
async list(organizationId:string,projectId:string,page:number,size:number,name?:string,status?:ECommon_Model_Project_Release_Status):Promise<ICommon_Route_Res_Release_List> {
|
||||
if(page===undefined || page<0 || size===undefined || size<=0) {
|
||||
throw Err.Common.paramError
|
||||
}
|
||||
let mysql=getMysqlInstance()
|
||||
let ret:ICommon_Route_Res_Release_Item[]=[]
|
||||
let count=Number(Object.values(await mysql.executeOne(generateCountSql(projectReleaseModel,{
|
||||
...(name && {
|
||||
name:{
|
||||
exp:"%like%",
|
||||
value:name
|
||||
let sql=generateLeftJoinSql({
|
||||
model:projectReleaseModel,
|
||||
columns:keys<typeof projectReleaseModel["model"]>().map(item=>item.name)
|
||||
},{
|
||||
model:projectModel,
|
||||
columns:keys<typeof projectModel["model"]>().map(item=>item.name),
|
||||
aggregation:"project",
|
||||
expression:{
|
||||
id:{
|
||||
model:projectReleaseModel,
|
||||
field:"project_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
organization_id:{
|
||||
model:projectModel,
|
||||
value:organizationId
|
||||
},
|
||||
...(projectId && {
|
||||
project_id:{
|
||||
model:projectReleaseModel,
|
||||
value:projectId
|
||||
}
|
||||
}),
|
||||
...(status && {
|
||||
status:status
|
||||
})
|
||||
})))[0])
|
||||
let totalPage=CommonUtil.pageTotal(count,size)
|
||||
if(count>0) {
|
||||
let arr=await mysql.execute(generateQuerySql(projectReleaseModel,null,{
|
||||
project_id:projectId,
|
||||
...(name && {
|
||||
name:{
|
||||
...(name && {
|
||||
name:{
|
||||
model:projectReleaseModel,
|
||||
value:{
|
||||
exp:"%like%",
|
||||
value:name
|
||||
}
|
||||
}),
|
||||
...(status && {
|
||||
status:status
|
||||
})
|
||||
},"and",{
|
||||
field:"name",
|
||||
type:"asc"
|
||||
},page*size,size))
|
||||
}
|
||||
}),
|
||||
...(status && {
|
||||
status:{
|
||||
model:projectReleaseModel,
|
||||
value:status
|
||||
}
|
||||
})
|
||||
},"and",{
|
||||
model:projectReleaseModel,
|
||||
field:"name",
|
||||
type:"asc"
|
||||
},page*size,size)
|
||||
let countSql=convertCountSql(sql);
|
||||
let count=Number(Object.values(await mysql.executeOne(countSql))[0])
|
||||
let totalPage=CommonUtil.pageTotal(count,size)
|
||||
if(count>0) {
|
||||
let arr=await mysql.execute(sql)
|
||||
if(arr.length>0) {
|
||||
let sql=generateGroupLeftJoin2Sql({
|
||||
let sql=generateGroupLeftJoin3Sql({
|
||||
model:projectReleaseIssueModel,
|
||||
columns:{
|
||||
columns:["project_release_id"],
|
||||
@ -81,6 +104,14 @@ class ReleaseMapper extends Mapper<typeof projectReleaseModel> {
|
||||
field:"project_issue_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
model:projectModel,
|
||||
expression:{
|
||||
id:{
|
||||
model:projectReleaseIssueModel,
|
||||
field:"project_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
model:workflowNodeModel,
|
||||
expression:{
|
||||
@ -138,7 +169,7 @@ class ReleaseMapper extends Mapper<typeof projectReleaseModel> {
|
||||
...obj,
|
||||
notstart:objTemp[obj.id]?Number(objTemp[obj.id].notstart):0,
|
||||
inprogress:objTemp[obj.id]?Number(objTemp[obj.id].inprogress):0,
|
||||
done:objTemp[obj.id]?Number(objTemp[obj.id].done):0
|
||||
done:objTemp[obj.id]?Number(objTemp[obj.id].done):0,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -156,9 +187,26 @@ class ReleaseMapper extends Mapper<typeof projectReleaseModel> {
|
||||
throw Err.Project.Release.releaseNotFound
|
||||
}
|
||||
let mysql=getMysqlInstance()
|
||||
let objRelease = await mysql.executeOne(generateQuerySql(projectReleaseModel,[],{
|
||||
id:projectReleaseId
|
||||
}))
|
||||
let sqlRelease=generateLeftJoinSql({
|
||||
model:projectReleaseModel,
|
||||
columns:keys<typeof projectReleaseModel["model"]>().map(item=>item.name)
|
||||
},{
|
||||
model:projectModel,
|
||||
columns:keys<typeof projectModel["model"]>().map(item=>item.name),
|
||||
aggregation:"project",
|
||||
expression:{
|
||||
id:{
|
||||
model:projectReleaseModel,
|
||||
field:"project_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
id:{
|
||||
model:projectReleaseModel,
|
||||
value:projectReleaseId
|
||||
}
|
||||
})
|
||||
let objRelease = await mysql.executeOne(sqlRelease)
|
||||
if(!objRelease) {
|
||||
throw Err.Project.Release.releaseNotFound
|
||||
}
|
||||
|
@ -381,12 +381,12 @@ export class ProjectIssueService extends Entity<typeof projectIssueModel,typeof
|
||||
}
|
||||
|
||||
|
||||
static async filter(projectId :string,page :number,size :number,createdBy? :string,issueTypeId? :string,name? :string,priority? :number,assignerId? :string,reporterId? :string,status? :number,moduleId? :string,labelId? :string) {
|
||||
static async filter(organizationId:string,projectId :string,page :number,size :number,createdBy? :string,issueTypeId? :string,name? :string,priority? :number,assignerId? :string,reporterId? :string,status? :number,moduleId? :string,labelId? :string) {
|
||||
let project=await ProjectService.getItemById(projectId)
|
||||
if(!project) {
|
||||
throw Err.Project.projectNotFound
|
||||
}
|
||||
let ret=await projectIssueMapper.filter(projectId ,page ,size ,createdBy ,issueTypeId,name,priority,assignerId,reporterId,status,moduleId,labelId)
|
||||
let ret=await projectIssueMapper.filter(organizationId,projectId ,page ,size ,createdBy ,issueTypeId,name,priority,assignerId,reporterId,status,moduleId,labelId)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,11 @@ export class ProjectReleaseService extends Entity<typeof projectReleaseModel,typ
|
||||
constructor(){
|
||||
super(releaseMapper)
|
||||
}
|
||||
static async list(projectId:string,page:number,size:number,name?:string,status?:ECommon_Model_Project_Release_Status){
|
||||
static async list(organizationId:string,projectId:string,page:number,size:number,name?:string,status?:ECommon_Model_Project_Release_Status){
|
||||
if(page<0 || size<=0){
|
||||
throw Err.Project.Release.releaseSizeEmpty
|
||||
}
|
||||
let ret=await releaseMapper.list(projectId,page,size,name,status)
|
||||
let ret=await releaseMapper.list(organizationId,projectId,page,size,name,status)
|
||||
return ret
|
||||
}
|
||||
|
||||
|
@ -7,24 +7,24 @@ import {fileModel} from './../../../common/model/file';
|
||||
@DComponent
|
||||
class FileEvents {
|
||||
@DEventListener("fileRef")
|
||||
async refFile(fileId:string){
|
||||
async refFile(fileId:string,count?:number){
|
||||
let mysql=getMysqlInstance()
|
||||
await mysql.execute(generateUpdateSql(fileModel,{
|
||||
ref:{
|
||||
exp:"+",
|
||||
value:1
|
||||
value:count??1
|
||||
}
|
||||
},{
|
||||
id:fileId
|
||||
}))
|
||||
}
|
||||
@DEventListener("fileUnref")
|
||||
async unrefFile(fileId:string){
|
||||
async unrefFile(fileId:string,count?:number){
|
||||
let mysql=getMysqlInstance()
|
||||
await mysql.execute(generateUpdateSql(fileModel,{
|
||||
ref:{
|
||||
exp:"-",
|
||||
value:1
|
||||
value:count??1
|
||||
}
|
||||
},{
|
||||
id:fileId
|
||||
|
@ -23,7 +23,8 @@ class AdminController {
|
||||
id:obj.getItem().id,
|
||||
...(meta && {
|
||||
meta
|
||||
})
|
||||
}),
|
||||
path:"/file"+obj.getItem().path
|
||||
}
|
||||
} else {
|
||||
let objFile=new FileService()
|
||||
@ -38,7 +39,8 @@ class AdminController {
|
||||
id:ret,
|
||||
...(meta && {
|
||||
meta
|
||||
})
|
||||
}),
|
||||
path:"/file"+objFile.getItem().path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"module": "commonjs",
|
||||
"target": "ES2017",
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule":true,
|
||||
"moduleResolution":"node",
|
||||
|
@ -150,11 +150,13 @@ export class OrganizationService extends Entity<typeof organizationModel,typeof
|
||||
description,
|
||||
value:value
|
||||
});
|
||||
emitServiceEvent("roleChange",roleId)
|
||||
return ret;
|
||||
}
|
||||
|
||||
async removeRole(roleId:string){
|
||||
let ret=await rpcAuthApi.removeRole(roleId);
|
||||
emitServiceEvent("roleChange",roleId)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -272,4 +272,10 @@ class WikiController {
|
||||
wiki:objWiki.getItem()
|
||||
}
|
||||
}
|
||||
|
||||
@DHttpApi(wikiApi.routes.filterWikiItem)
|
||||
async filterWikiItem(@DHttpReqParam("wikiId") wikiId:string,@DHttpReqParam("name") name:string,@DHttpReqParamRequired("size") size:number,@DHttpReqParamRequired("page") page:number,@DHttpUser user:IUserSession):Promise<typeof wikiApi.routes.filterWikiItem.res>{
|
||||
let ret=await WikiItemService.filterWikiItem(user.organizationInfo.organizationId,wikiId,name,page,size)
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -4,10 +4,12 @@ import {wikiItemModel} from "../../../common/model/wiki_item";
|
||||
import {Err} from "../../../common/status/error";
|
||||
import {getMysqlInstance} from "../../common/db/mysql";
|
||||
import {
|
||||
convertCountSql,
|
||||
generateBatchCreateOnUpdateSql,
|
||||
generateDeleteSql,
|
||||
generateGroupLeftJoin2Sql,
|
||||
generateLeftJoin3Sql,
|
||||
generateLeftJoinSql,
|
||||
generateQuerySql,
|
||||
generateSnowId,
|
||||
generateUpdateSql
|
||||
@ -448,6 +450,61 @@ class WikiItemMapper extends Mapper<typeof wikiItemModel> {
|
||||
}));
|
||||
return ret;
|
||||
}
|
||||
|
||||
async filterWikiItem(organizationId:string,wikiId:string,name:string,page:number,size:number) {
|
||||
if(page===undefined || page<0 || size===undefined || size<=0) {
|
||||
throw Err.Common.paramError
|
||||
}
|
||||
let mysql=getMysqlInstance()
|
||||
let sql=generateLeftJoinSql({
|
||||
model:wikiItemModel,
|
||||
columns:keys<typeof wikiItemModel["model"]>().map(item=>item.name)
|
||||
},{
|
||||
model:wikiModel,
|
||||
columns:keys<typeof wikiModel["model"]>().map(item=>item.name),
|
||||
aggregation:"wiki",
|
||||
expression:{
|
||||
id:{
|
||||
model:wikiItemModel,
|
||||
field:"wiki_id"
|
||||
}
|
||||
}
|
||||
},{
|
||||
organization_id:{
|
||||
model:wikiModel,
|
||||
value:organizationId
|
||||
},
|
||||
...(wikiId && {
|
||||
wiki_id:{
|
||||
model:wikiItemModel,
|
||||
value:wikiId
|
||||
}
|
||||
}),
|
||||
...(name && {
|
||||
name:{
|
||||
model:wikiItemModel,
|
||||
value:{
|
||||
exp:"%like%",
|
||||
value:name
|
||||
}
|
||||
}
|
||||
}),
|
||||
},"and",{
|
||||
model:wikiItemModel,
|
||||
field:"name",
|
||||
type:"asc"
|
||||
},page*size,size)
|
||||
let countSql=convertCountSql(sql);
|
||||
let count=Number(Object.values(await mysql.executeOne(countSql))[0])
|
||||
let totalPage=CommonUtil.pageTotal(count,size)
|
||||
let ret=await mysql.execute(sql)
|
||||
return {
|
||||
count:count,
|
||||
totalPage:totalPage,
|
||||
page:page,
|
||||
data:ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const wikiItemMapper=new WikiItemMapper()
|
@ -8,6 +8,11 @@ import {ECommon_Model_Role_Reserved, ECommon_Model_Role_Type} from "../../../com
|
||||
import {ECommon_Model_Organization_Member_Type} from "../../../common/model/organization";
|
||||
import {Err} from "../../../common/status/error";
|
||||
import {IServer_Common_Event_Types} from "../../common/event/types";
|
||||
import {
|
||||
ECommon_Wiki_Content_Line_Config_Type,
|
||||
ICommon_Wiki_Content_Line
|
||||
} from "../../../common/model/wiki_item_content";
|
||||
import {emitServiceEvent} from "../../common/event/event";
|
||||
|
||||
export class WikiService extends Entity<typeof wikiModel,typeof wikiMapper> {
|
||||
constructor() {
|
||||
@ -33,6 +38,8 @@ export class WikiService extends Entity<typeof wikiModel,typeof wikiMapper> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override async delete(eventPublish?: keyof IServer_Common_Event_Types): Promise<void> {
|
||||
await super.delete(eventPublish);
|
||||
await wikiMapper.clearWiki(this.getId());
|
||||
@ -155,11 +162,63 @@ export class WikiItemService extends Entity<typeof wikiItemModel,typeof wikiItem
|
||||
}
|
||||
|
||||
async saveContent(content:string,modified_by:string) {
|
||||
let oldObjFile=await this.generateLineObj()
|
||||
content=content.replaceAll("\\\"","\\\\\"")
|
||||
await wikiItemMapper.saveContent(this.getId(),content,modified_by);
|
||||
let newObjFile=await this.generateLineObj()
|
||||
for(let key in oldObjFile) {
|
||||
let oldCount=oldObjFile[key]
|
||||
let newCount=newObjFile[key]
|
||||
if(newCount!==undefined) {
|
||||
if(oldCount!==newCount) {
|
||||
if(oldCount>newCount) {
|
||||
emitServiceEvent("fileUnref",key,oldCount-newCount)
|
||||
} else {
|
||||
emitServiceEvent("fileRef",key,newCount-oldCount)
|
||||
}
|
||||
}
|
||||
delete newObjFile[key]
|
||||
} else {
|
||||
emitServiceEvent("fileUnref",key,oldCount)
|
||||
}
|
||||
}
|
||||
for(let key in newObjFile) {
|
||||
let count=newObjFile[key]
|
||||
emitServiceEvent("fileRef",key,count)
|
||||
}
|
||||
}
|
||||
|
||||
async generateLineObj():Promise<{
|
||||
[param:string]:number
|
||||
}> {
|
||||
let objFile:{
|
||||
[param:string]:number
|
||||
}={}
|
||||
let content=await this.getContent()
|
||||
if(content.content) {
|
||||
let arr=JSON.parse(content.content) as ICommon_Wiki_Content_Line[]
|
||||
for(let obj of arr) {
|
||||
for(let obj1 of obj.arr) {
|
||||
if(obj1.type===ECommon_Wiki_Content_Line_Config_Type.FILE || obj1.type===ECommon_Wiki_Content_Line_Config_Type.IMAGE) {
|
||||
if(!objFile[obj1.value]) {
|
||||
objFile[obj1.value]=1
|
||||
} else {
|
||||
objFile[obj1.value]++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return objFile
|
||||
}
|
||||
|
||||
async getContent() {
|
||||
let ret=await wikiItemMapper.getContent(this.getId());
|
||||
return ret;
|
||||
}
|
||||
|
||||
static async filterWikiItem(organizationId:string,wikiId:string,name:string,page:number,size:number) {
|
||||
let ret=await wikiItemMapper.filterWikiItem(organizationId,wikiId,name,page,size)
|
||||
return ret;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user