fix
@ -12,23 +12,20 @@
|
|||||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/vue-fontawesome": "^3.0.3",
|
"@fortawesome/vue-fontawesome": "^3.0.3",
|
||||||
"@logicflow/core": "^1.1.31",
|
"@logicflow/core": "^1.2.10",
|
||||||
"@socket.io/redis-adapter": "^8.2.1",
|
|
||||||
"@socket.io/redis-emitter": "^5.1.0",
|
|
||||||
"blueimp-md5": "^2.19.0",
|
"blueimp-md5": "^2.19.0",
|
||||||
"eventemitter3": "^5.0.0",
|
"eventemitter3": "^5.0.0",
|
||||||
"mediasoup-client": "^3.6.98",
|
"mediasoup-client": "^3.6.98",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"moment-timezone": "^0.5.42",
|
"moment-timezone": "^0.5.42",
|
||||||
"pinia": "^2.1.4",
|
"pinia": "^2.1.4",
|
||||||
"socket.io": "^4.7.1",
|
|
||||||
"socket.io-client": "^4.6.1",
|
"socket.io-client": "^4.6.1",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.2"
|
"vue-router": "^4.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@arco-design/web-vue": "^2.48.1",
|
"@arco-design/web-vue": "^2.49.1",
|
||||||
"@rollup/plugin-typescript": "^10.0.1",
|
"@rollup/plugin-typescript": "^10.0.1",
|
||||||
"@types/blueimp-md5": "^2.18.0",
|
"@types/blueimp-md5": "^2.18.0",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<a-spin style="width: 100%;min-height: 100px;border: 1px solid lightgray" :loading="loading" v-drop.file.shortcut.disk="onDrop">
|
||||||
|
<RichEditor v-model="content" style="width: 100%" @upload-file="onUploadFile" :pop-menu-list="popMenuList" @pop-menu-click="onPopMenuClick" @custom-anchor-click="onCustomAnchorClick" ref="objEditorUser"></RichEditor>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {getCurrentInstance, inject, Ref, ref} from "vue";
|
||||||
|
import RichEditor from "@/business/common/component/richEditor/richEditor.vue";
|
||||||
|
import {
|
||||||
|
ECommon_Content_Line_Config_Type,
|
||||||
|
ICommon_Content_Line,
|
||||||
|
ICommon_Content_Line_Config
|
||||||
|
} from "../../../../../../common/model/content";
|
||||||
|
import {RichEditorEventHandle} from "@/business/common/component/richEditorEventHandle";
|
||||||
|
import {DropParam, vDrop} from "@/teamOS/common/directive/drop";
|
||||||
|
import {apiFile} from "@/business/common/request/request";
|
||||||
|
import {onDialogOk} from "@/business/common/component/dialog/dialog";
|
||||||
|
|
||||||
|
const loading=ref(false)
|
||||||
|
const root =inject("dialogRootRef") as Ref<HTMLElement>
|
||||||
|
const appContext=getCurrentInstance().appContext
|
||||||
|
const content = ref<ICommon_Content_Line[]>([])
|
||||||
|
const popMenuList=ref(RichEditorEventHandle.popMenuList)
|
||||||
|
const objEditorUser=ref<InstanceType<typeof RichEditor>>()
|
||||||
|
const onCustomAnchorClick=(type:ECommon_Content_Line_Config_Type,value:string,link:string,label:string)=>{
|
||||||
|
RichEditorEventHandle.onCustomAnchorClick(type,value,link,label)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDrop=(data?:DropParam)=>{
|
||||||
|
RichEditorEventHandle.onDrop(objEditorUser,data)
|
||||||
|
}
|
||||||
|
|
||||||
|
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=(type:ECommon_Content_Line_Config_Type,handleFunc:(item:ICommon_Content_Line_Config)=>void)=>{
|
||||||
|
RichEditorEventHandle.onPopMenuClick(type,root,appContext,loading,handleFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
onDialogOk(async ()=>{
|
||||||
|
return content.value
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,6 +1,7 @@
|
|||||||
import {renderComponent} from "../../../../teamOS/common/util/component";
|
import {renderComponent} from "../../../../teamOS/common/util/component";
|
||||||
import DialogView from "./dialogView.vue";
|
import DialogView from "./dialogView.vue";
|
||||||
import {AppContext, Component, inject, ref} from "vue";
|
import {AppContext, Component, inject, markRaw, ref} from "vue";
|
||||||
|
import DiaglogRich from "@/business/common/component/dialog/diaglogRich.vue";
|
||||||
|
|
||||||
export function onDialogOk(func:()=>void){
|
export function onDialogOk(func:()=>void){
|
||||||
const events:any=inject("dialogEvents");
|
const events:any=inject("dialogEvents");
|
||||||
@ -104,4 +105,49 @@ export class Dialog {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inputRich(el:HTMLElement,appContext: AppContext,title:string) {
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
let ele=document.createElement("div")
|
||||||
|
const events:{
|
||||||
|
onOk:()=>any,
|
||||||
|
onClose:()=>void
|
||||||
|
}={
|
||||||
|
onOk:null,
|
||||||
|
onClose:null
|
||||||
|
}
|
||||||
|
const loading=ref(false);
|
||||||
|
let destroyFunc=renderComponent(ele,DialogView,appContext,{
|
||||||
|
component:markRaw(DiaglogRich),
|
||||||
|
title,
|
||||||
|
events,
|
||||||
|
onOk,
|
||||||
|
onClose,
|
||||||
|
loading
|
||||||
|
});
|
||||||
|
el.appendChild(ele);
|
||||||
|
async function onOk(){
|
||||||
|
if(events.onOk) {
|
||||||
|
loading.value=true;
|
||||||
|
let ret=await events.onOk();
|
||||||
|
loading.value=false
|
||||||
|
if(ret!==false) {
|
||||||
|
destroyFunc();
|
||||||
|
ele.parentNode.removeChild(ele);
|
||||||
|
resolve(ret)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
destroyFunc();
|
||||||
|
ele.parentNode.removeChild(ele);
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onClose(){
|
||||||
|
events.onClose?.();
|
||||||
|
destroyFunc();
|
||||||
|
ele.parentNode.removeChild(ele);
|
||||||
|
resolve(null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="position: absolute;left: 0;top: 0;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;background-color: rgba(29,33,41,0.6);z-index: 10000">
|
<div style="position: absolute;left: 0;top: 0;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;background-color: rgba(29,33,41,0.6);z-index: 10000" ref="root">
|
||||||
<div style="background-color: white;width: 60%;height:auto;max-height: 80%;border-radius: 5px;display: flex;flex-direction: column">
|
<div style="background-color: white;width: 60%;height:auto;max-height: 80%;border-radius: 5px;display: flex;flex-direction: column">
|
||||||
<div style="height: 35px;line-height: 35px;width: 100%;text-align: center;color: rgb(93,93,93);border-bottom: 1px solid gainsboro;flex: 1 1 auto">
|
<div style="height: 35px;line-height: 35px;width: 100%;text-align: center;color: rgb(93,93,93);border-bottom: 1px solid gainsboro;flex: 1 1 auto">
|
||||||
<b>{{component?title:input?"Input":"Alert"}}</b>
|
<b>{{component?title:input?"Input":"Alert"}}</b>
|
||||||
@ -42,6 +42,8 @@ const props=defineProps<{
|
|||||||
}
|
}
|
||||||
}>()
|
}>()
|
||||||
const inputValue=props.input?props.input.text:ref("")
|
const inputValue=props.input?props.input.text:ref("")
|
||||||
|
const root=ref()
|
||||||
|
provide("dialogRootRef",root)
|
||||||
if(props.events) {
|
if(props.events) {
|
||||||
provide("dialogEvents",props.events);
|
provide("dialogEvents",props.events);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<UserAvatar v-if="showValue" :photo="showValue.photo" :name="showValue.nickname" :organization-user-id="showValue.organizationUserId"></UserAvatar>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">No User</span>
|
||||||
|
</template>
|
||||||
|
<a-row style="padding-right: 10px" v-else>
|
||||||
|
<a-select allow-search allow-clear v-model="editValue" @search="onSearchAssigner">
|
||||||
|
<a-option v-for="item in assignerList" :label="item.organizationUser.nickname" :value="item.organizationUser.id">
|
||||||
|
<a-avatar :size="24" :image-url="item.user.photo"></a-avatar>
|
||||||
|
{{ item.organizationUser.nickname }}
|
||||||
|
</a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import UserAvatar from "../../userAvatar.vue";
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
import {apiIssue, apiOrganization, DCSType} from "../../../request/request";
|
||||||
|
import {ICommon_Route_Res_Organization_User_Item} from "../../../../../../../common/routes/response";
|
||||||
|
import {SessionStorage} from "../../../storage/session";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:{
|
||||||
|
id:string,
|
||||||
|
organizationUserId?:string,
|
||||||
|
photo?:string,
|
||||||
|
nickname?:string
|
||||||
|
},
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:{
|
||||||
|
id:string,
|
||||||
|
organizationUserId?:string,
|
||||||
|
photo?:string,
|
||||||
|
nickname?:string
|
||||||
|
}]
|
||||||
|
}>()
|
||||||
|
const editValue=ref("")
|
||||||
|
const assignerList=ref<DCSType<ICommon_Route_Res_Organization_User_Item>[]>([])
|
||||||
|
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=""
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
|
||||||
|
const onClick=async()=>{
|
||||||
|
let res=await apiIssue.editBasicField({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
assignerId:editValue.value as string
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",res.data.assigner_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchAssigner=async (keyword:string)=>{
|
||||||
|
let res=await apiOrganization.listUser({
|
||||||
|
organizationId:SessionStorage.get("organizationId"),
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
assignerList.value=res.data.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,121 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<RichEditor v-if="!isEdit" :model-value="showValue?JSON.parse(showValue):[]" :readonly="true" @custom-anchor-click="onCustomAnchorClick"></RichEditor>
|
||||||
|
<template v-else>
|
||||||
|
<div style="width: 100%">
|
||||||
|
<div>
|
||||||
|
<a-spin :loading="loading" v-drop.file.shortcut.disk="onDrop" style="width: 100%">
|
||||||
|
<RichEditor v-model="editValue" @upload-file="onUploadFile" :pop-menu-list="popMenuList" @pop-menu-click="onPopMenuClick" @custom-anchor-click="onCustomAnchorClick" @quote-list="onQuoteList" ref="objEditor"></RichEditor>
|
||||||
|
</a-spin>
|
||||||
|
</div>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {apiFile, apiIssue} from "../../../request/request";
|
||||||
|
import {getCurrentInstance, ref, watch} from "vue";
|
||||||
|
import RichEditor from "../../richEditor/richEditor.vue";
|
||||||
|
import {
|
||||||
|
ECommon_Content_Line_Config_Type,
|
||||||
|
ICommon_Content_Line,
|
||||||
|
ICommon_Content_Line_Config
|
||||||
|
} from "../../../../../../../common/model/content";
|
||||||
|
import {RichEditorEventHandle} from "../../richEditorEventHandle";
|
||||||
|
import {DropParam, vDrop} from "../../../../../teamOS/common/directive/drop";
|
||||||
|
import {getRootNavigatorRef} from "../../../../../teamOS/common/component/navigator/navigator";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:string,
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:string]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const root=getRootNavigatorRef()
|
||||||
|
const appContext=getCurrentInstance().appContext
|
||||||
|
const editValue=ref<ICommon_Content_Line[]>([])
|
||||||
|
const objEditor=ref<InstanceType<typeof RichEditor>>()
|
||||||
|
const loading=ref(false)
|
||||||
|
const popMenuList=ref(RichEditorEventHandle.popMenuList)
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=props.showValue?JSON.parse(props.showValue):[]
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
const onClick=async()=>{
|
||||||
|
let value=JSON.stringify(editValue.value.map(item=>{
|
||||||
|
return {
|
||||||
|
arr:item.arr
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
let res=await apiIssue.editDescription({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
description:JSON.stringify(editValue.value.map(item=>{
|
||||||
|
return {
|
||||||
|
arr:item.arr
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
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=(type:ECommon_Content_Line_Config_Type,handleFunc:(item:ICommon_Content_Line_Config)=>void)=>{
|
||||||
|
RichEditorEventHandle.onPopMenuClick(type,root,appContext,loading,handleFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCustomAnchorClick=(type:ECommon_Content_Line_Config_Type,value:string,link:string,label:string)=>{
|
||||||
|
RichEditorEventHandle.onCustomAnchorClick(type,value,link,label)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onQuoteList=(keyword:string,handleFunc:(list:{
|
||||||
|
value:string,
|
||||||
|
label:string,
|
||||||
|
photo:string
|
||||||
|
}[])=>void)=>{
|
||||||
|
RichEditorEventHandle.onQuoteList(keyword,handleFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDrop=(data?:DropParam)=>{
|
||||||
|
RichEditorEventHandle.onDrop(objEditor,data,loading)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<a-space wrap size="mini" v-if="(showValue as ICommon_Model_Project_Release[]).length>0">
|
||||||
|
<ProjectReleasePreview v-for="item in (showValue as ICommon_Model_Project_Release[])" :key="item.id" :project-release-id="item.id" :name="item.name"></ProjectReleasePreview>
|
||||||
|
</a-space>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
||||||
|
</template>
|
||||||
|
<a-row style="padding-right: 10px" v-else>
|
||||||
|
<a-space size="mini" wrap>
|
||||||
|
<a-tag v-for="(item,index) in (editValue as {id:string,name:string}[])" :closable="true" @close="onCloseLabelTag(index)" :key="item.id">
|
||||||
|
{{item.name}}
|
||||||
|
</a-tag>
|
||||||
|
<a-select v-model="addValue" allow-search @search="onSearchRelease" v-if="showInput" @change="onAddChange">
|
||||||
|
<a-option v-for="item in labelList" :label="item.name" :value="item.id"></a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-tag v-else :style="{backgroundColor: 'var(--color-fill-2)',border: '1px dashed var(--color-fill-3)',cursor: 'pointer',}" @click="showInput=true">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
Add
|
||||||
|
</a-tag>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ICommon_Model_Project_Release} from "../../../../../../../common/model/project_release";
|
||||||
|
import ProjectReleasePreview from "../../../../controller/app/project/release/projectReleasePreview.vue";
|
||||||
|
import {inject, ref, watch} from "vue";
|
||||||
|
import {injectProjectInfo} from "../../../util/symbol";
|
||||||
|
import {apiIssue, apiRelease, DCSType} from "../../../request/request";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:DCSType<ICommon_Model_Project_Release>[],
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:DCSType<ICommon_Model_Project_Release>[]]
|
||||||
|
}>()
|
||||||
|
const labelList=ref<{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]>([])
|
||||||
|
const editValue=ref<{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]>()
|
||||||
|
const showInput=ref(false)
|
||||||
|
const addValue=ref("")
|
||||||
|
const projectId=inject(injectProjectInfo).id;
|
||||||
|
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=props.showValue.length>0?props.showValue.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
}):[]
|
||||||
|
showInput.value=false
|
||||||
|
addValue.value=""
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const onCloseLabelTag=(index:number)=>{
|
||||||
|
editValue.value.splice(index,1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAddChange=()=>{
|
||||||
|
let arr=editValue.value as {
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]
|
||||||
|
let index=labelList.value.findIndex((item)=>{
|
||||||
|
if(item.id==addValue.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
arr.push({
|
||||||
|
id:labelList.value[index].id,
|
||||||
|
name:labelList.value[index].name
|
||||||
|
})
|
||||||
|
addValue.value=""
|
||||||
|
showInput.value=false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchRelease=async (keyword:string)=>{
|
||||||
|
let res=await apiRelease.list({
|
||||||
|
projectId,
|
||||||
|
name:keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
labelList.value=res.data.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick=async ()=>{
|
||||||
|
let arr=editValue.value as {
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]
|
||||||
|
let arrId=Array.from(new Set(arr.map(item=>item.id)));
|
||||||
|
let res=await apiIssue.bindReleases({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
projectReleaseIds:arrId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<a-space wrap size="mini" v-if="(showValue as ICommon_Model_Project_Label[]).length>0">
|
||||||
|
<a-tag v-for="item in (showValue as ICommon_Model_Project_Label[])" color="blue">{{item.name}}</a-tag>
|
||||||
|
</a-space>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
||||||
|
</template>
|
||||||
|
<a-row style="padding-right: 10px" v-else>
|
||||||
|
<a-space size="mini" wrap>
|
||||||
|
<a-tag v-for="(item,index) in (editValue as {id:string,name:string}[])" :closable="true" @close="onCloseLabelTag(index)" :key="item.id">
|
||||||
|
{{item.name}}
|
||||||
|
</a-tag>
|
||||||
|
<a-select v-model="addValue" allow-search @search="onSearchLabel" v-if="showInput" @change="onAddChange">
|
||||||
|
<a-option v-for="item in labelList" :label="item.name" :value="item.id"></a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-tag v-else :style="{backgroundColor: 'var(--color-fill-2)',border: '1px dashed var(--color-fill-3)',cursor: 'pointer',}" @click="showInput=true">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
Add
|
||||||
|
</a-tag>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ICommon_Model_Project_Label} from "../../../../../../../common/model/project_label";
|
||||||
|
import {inject, ref, watch} from "vue";
|
||||||
|
import {apiIssue, apiProject} from "../../../request/request";
|
||||||
|
import {injectProjectInfo} from "../../../util/symbol";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:ICommon_Model_Project_Label[],
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:ICommon_Model_Project_Label[]]
|
||||||
|
}>()
|
||||||
|
const labelList=ref<{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]>([])
|
||||||
|
const editValue=ref<{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]>()
|
||||||
|
const showInput=ref(false)
|
||||||
|
const addValue=ref("")
|
||||||
|
const projectId=inject(injectProjectInfo).id;
|
||||||
|
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=props.showValue.length>0?props.showValue.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
}):[]
|
||||||
|
showInput.value=false
|
||||||
|
addValue.value=""
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
|
||||||
|
const onCloseLabelTag=(index:number)=>{
|
||||||
|
editValue.value.splice(index,1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchLabel=async (keyword:string)=>{
|
||||||
|
let res=await apiProject.listLabel({
|
||||||
|
projectId,
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
labelList.value=res.data.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAddChange=()=>{
|
||||||
|
let arr=editValue.value as {
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]
|
||||||
|
let index=labelList.value.findIndex((item)=>{
|
||||||
|
if(item.id==addValue.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
arr.push({
|
||||||
|
id:labelList.value[index].id,
|
||||||
|
name:labelList.value[index].name
|
||||||
|
})
|
||||||
|
addValue.value=""
|
||||||
|
showInput.value=false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick=async ()=>{
|
||||||
|
let arr=editValue.value as {
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]
|
||||||
|
let arrId=Array.from(new Set(arr.map(item=>item.id)));
|
||||||
|
let res=await apiIssue.bindLabel({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
labelIds:arrId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<a-space wrap size="mini" v-if="showValue.length>0">
|
||||||
|
<template #split>
|
||||||
|
/
|
||||||
|
</template>
|
||||||
|
<span v-for="item in showValue" style="color: blue">{{item.name}}</span>
|
||||||
|
</a-space>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
||||||
|
</template>
|
||||||
|
<a-row style="padding-right: 10px" v-else>
|
||||||
|
<a-cascader v-model="editValue" :field-names="fields" :options="moduleList" placeholder="please select" :format-label="format" check-strictly allow-clear allow-search></a-cascader>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ICommon_Model_Project_Module} from "../../../../../../../common/model/project_module";
|
||||||
|
import {inject, ref, watch} from "vue";
|
||||||
|
import {injectProjectInfo} from "../../../util/symbol";
|
||||||
|
import {ICommon_Route_Res_Project_CreateModule_Data} from "../../../../../../../common/routes/response";
|
||||||
|
import {apiIssue, apiProject} from "../../../request/request";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:ICommon_Model_Project_Module[],
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:ICommon_Model_Project_Module[]]
|
||||||
|
}>()
|
||||||
|
const labelList=ref<{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]>([])
|
||||||
|
const editValue=ref("")
|
||||||
|
const fields={
|
||||||
|
label:"name",
|
||||||
|
value:"id",
|
||||||
|
children:"data"
|
||||||
|
}
|
||||||
|
const projectId=inject(injectProjectInfo).id;
|
||||||
|
const moduleList=ref<ICommon_Route_Res_Project_CreateModule_Data[]>([])
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=props.showValue.length>0?props.showValue[props.showValue.length-1].id:""
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
watch(()=>props.isEdit,()=>{
|
||||||
|
getModuleList()
|
||||||
|
})
|
||||||
|
const format = (options) => {
|
||||||
|
const labels = options.map(option => option.name)
|
||||||
|
return labels.join('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getModuleList=async ()=>{
|
||||||
|
let res=await apiProject.listModule({
|
||||||
|
projectId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
moduleList.value=res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick=async ()=>{
|
||||||
|
let res=await apiIssue.bindModule({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
moduleId:editValue.value
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<span style="font-size: 24px;font-weight: bold" v-if="!isEdit">{{ showValue }}</span>
|
||||||
|
<template v-else>
|
||||||
|
<a-row style="padding-right: 10px">
|
||||||
|
<a-input v-model="editValue"></a-input>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
import {apiIssue} from "../../../request/request";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:string,
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:string]
|
||||||
|
}>()
|
||||||
|
const editValue=ref("")
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=props.showValue
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
|
||||||
|
const onClick=async()=>{
|
||||||
|
let res=await apiIssue.editBasicField({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
name:editValue.value as string
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",res.data.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<FieldPriority :priority="showValue" v-if="!isEdit"></FieldPriority>
|
||||||
|
<template v-else>
|
||||||
|
<a-space size="mini">
|
||||||
|
<a-select v-model="editValue">
|
||||||
|
<a-option label="low" :value="ECommon_Model_Project_Issue_Priority.LOW"></a-option>
|
||||||
|
<a-option label="medium" :value="ECommon_Model_Project_Issue_Priority.MEDIUM"></a-option>
|
||||||
|
<a-option label="high" :value="ECommon_Model_Project_Issue_Priority.HIGH"></a-option>
|
||||||
|
<a-option label="urgent" :value="ECommon_Model_Project_Issue_Priority.URGENT"></a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ECommon_Model_Project_Issue_Priority} from "../../../../../../../common/model/project_issue";
|
||||||
|
import FieldPriority from "../fieldPriority.vue";
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
import {apiIssue} from "../../../request/request";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:ECommon_Model_Project_Issue_Priority,
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:ECommon_Model_Project_Issue_Priority]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const editValue=ref<ECommon_Model_Project_Issue_Priority>()
|
||||||
|
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=props.showValue
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
|
||||||
|
const onClick=async ()=>{
|
||||||
|
let res=await apiIssue.editBasicField({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
priority:editValue.value
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",editValue.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<UserAvatar v-if="showValue" :photo="showValue.photo" :name="showValue.nickname" :organization-user-id="showValue.organizationUserId"></UserAvatar>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">No User</span>
|
||||||
|
</template>
|
||||||
|
<a-row style="padding-right: 10px" v-else>
|
||||||
|
<a-select allow-search allow-clear v-model="editValue" @search="onSearchReporter">
|
||||||
|
<a-option v-for="item in reporterList" :label="item.organizationUser.nickname" :value="item.organizationUser.id">
|
||||||
|
<a-avatar :size="24" :image-url="item.user.photo"></a-avatar>
|
||||||
|
{{ item.organizationUser.nickname }}
|
||||||
|
</a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-button type="text" @click="onClick">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import UserAvatar from "../../userAvatar.vue";
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
import {apiIssue, apiOrganization, DCSType} from "../../../request/request";
|
||||||
|
import {ICommon_Route_Res_Organization_User_Item} from "../../../../../../../common/routes/response";
|
||||||
|
import {SessionStorage} from "../../../storage/session";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
isEdit:boolean,
|
||||||
|
showValue?:{
|
||||||
|
id:string,
|
||||||
|
organizationUserId?:string,
|
||||||
|
photo?:string,
|
||||||
|
nickname?:string
|
||||||
|
},
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
cancel:[],
|
||||||
|
update:[value:{
|
||||||
|
id:string,
|
||||||
|
organizationUserId?:string,
|
||||||
|
photo?:string,
|
||||||
|
nickname?:string
|
||||||
|
}]
|
||||||
|
}>()
|
||||||
|
const editValue=ref("")
|
||||||
|
const reporterList=ref<DCSType<ICommon_Route_Res_Organization_User_Item>[]>([])
|
||||||
|
const assignValue=()=>{
|
||||||
|
editValue.value=""
|
||||||
|
}
|
||||||
|
watch(()=>props.showValue,()=>{
|
||||||
|
assignValue()
|
||||||
|
},{
|
||||||
|
immediate:true,
|
||||||
|
deep:true
|
||||||
|
})
|
||||||
|
|
||||||
|
const onClick=async()=>{
|
||||||
|
let res=await apiIssue.editBasicField({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
reporterId:editValue.value as string
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("update",res.data.reporter_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchReporter=async (keyword:string)=>{
|
||||||
|
let res=await apiOrganization.listUser({
|
||||||
|
organizationId:SessionStorage.get("organizationId"),
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
reporterList.value=res.data.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
emit('cancel')
|
||||||
|
assignValue()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,291 @@
|
|||||||
|
<template>
|
||||||
|
<div @focus="onFocus" tabindex="-1" class="hover">
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<template v-if="showValue.id">
|
||||||
|
<UserAvatar :organization-user-id="showValue.id" v-if="type==='user'"></UserAvatar>
|
||||||
|
<ProjectReleasePreview v-else-if="type==='release'" :project-release-id="showValue.id" :name="showValue.name"></ProjectReleasePreview>
|
||||||
|
<ProjectIssuePreview :name="showValue.name" :project-issue-id="showValue.id" v-else-if="type==='issue'"></ProjectIssuePreview>
|
||||||
|
<a-tag v-else>
|
||||||
|
{{showValue.name}}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-space size="mini" wrap>
|
||||||
|
<a-select v-model="addValue" allow-search allow-clear @search="onSearch" v-model:input-value="label">
|
||||||
|
<a-option v-for="item1 in searchValueList" :label="item1.name" :value="item1.id"></a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-button type="text" @click="onSubmit">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref, watch, watchEffect} from "vue";
|
||||||
|
import {
|
||||||
|
apiField,
|
||||||
|
apiIssue,
|
||||||
|
apiOrganization,
|
||||||
|
apiProject,
|
||||||
|
apiRelease,
|
||||||
|
apiTeam,
|
||||||
|
apiWorkflow
|
||||||
|
} from "@/business/common/request/request";
|
||||||
|
import UserAvatar from "@/business/common/component/userAvatar.vue";
|
||||||
|
import ProjectIssuePreview from "@/business/controller/app/project/issue/projectIssuePreview.vue";
|
||||||
|
import ProjectReleasePreview from "@/business/controller/app/project/release/projectReleasePreview.vue";
|
||||||
|
|
||||||
|
const emit=defineEmits<{
|
||||||
|
(e:"update:modelValue",value:string):void
|
||||||
|
}>()
|
||||||
|
const props=defineProps<{
|
||||||
|
modelValue:string,
|
||||||
|
type:"user"|"team"|"release"|"label"|"tag"|"issue"|"field",
|
||||||
|
projectId?:string,
|
||||||
|
workflowNodeId?:string
|
||||||
|
}>()
|
||||||
|
const showValue=ref<{
|
||||||
|
name?:string,
|
||||||
|
id:string,
|
||||||
|
}>({} as any);
|
||||||
|
const isEdit=ref(false)
|
||||||
|
const searchValueList=ref<{
|
||||||
|
name:string,
|
||||||
|
id:string,
|
||||||
|
}[]>([])
|
||||||
|
const addValue=ref("")
|
||||||
|
const label=ref("")
|
||||||
|
const request=async ()=>{
|
||||||
|
if(props.modelValue && props.modelValue.length>0) {
|
||||||
|
let ret:{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}
|
||||||
|
if(props.type==="team") {
|
||||||
|
ret=await apiTeam.info({
|
||||||
|
teamId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="user") {
|
||||||
|
ret=await apiOrganization.user({
|
||||||
|
organizationUserId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="release") {
|
||||||
|
ret=await apiRelease.info({
|
||||||
|
projectReleaseId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="label") {
|
||||||
|
ret=await apiProject.getLabel({
|
||||||
|
labelId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="tag") {
|
||||||
|
ret=await apiOrganization.getTag({
|
||||||
|
memberTagId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="issue") {
|
||||||
|
ret=await apiIssue.basicInfo({
|
||||||
|
projectIssueId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.project.keyword+"-"+data.data.unique_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="field") {
|
||||||
|
ret=await apiField.workflowNodeFieldInfo({
|
||||||
|
workflowNodeFieldTypeId:props.modelValue
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.field.id,
|
||||||
|
name:data.data.field.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
showValue.value=ret
|
||||||
|
label.value=showValue.value.name
|
||||||
|
} else {
|
||||||
|
showValue.value={} as any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watchEffect(()=>{
|
||||||
|
request()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(isEdit,async ()=>{
|
||||||
|
if(isEdit.value) {
|
||||||
|
if(props.type==="field") {
|
||||||
|
let res=await apiWorkflow.listApprovalField({
|
||||||
|
workflowNodeId:props.workflowNodeId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const onFocus=()=>{
|
||||||
|
isEdit.value=true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
isEdit.value=false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit=()=>{
|
||||||
|
isEdit.value=false
|
||||||
|
emit("update:modelValue",addValue.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const onSearch=async (keyword:string)=>{
|
||||||
|
if(keyword) {
|
||||||
|
if(props.type==="team") {
|
||||||
|
let res=await apiTeam.list({
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="user") {
|
||||||
|
let res=await apiOrganization.listUser({
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.organizationUser.id,
|
||||||
|
name:item.organizationUser.nickname
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="release") {
|
||||||
|
let res=await apiRelease.list({
|
||||||
|
page:0,
|
||||||
|
size:10,
|
||||||
|
name:keyword,
|
||||||
|
projectId:props.projectId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="label") {
|
||||||
|
let res=await apiProject.listLabel({
|
||||||
|
page:0,
|
||||||
|
size:10,
|
||||||
|
keyword,
|
||||||
|
projectId:props.projectId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="tag") {
|
||||||
|
let res=await apiOrganization.listTag({
|
||||||
|
keyword
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="issue") {
|
||||||
|
let res=await apiIssue.filter({
|
||||||
|
page:0,
|
||||||
|
size:10,
|
||||||
|
projectId:props.projectId,
|
||||||
|
name:keyword
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.hover:hover {
|
||||||
|
background-color: rgb(230,231,237);
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,281 @@
|
|||||||
|
<template>
|
||||||
|
<div @focus="onFocus" tabindex="-1" class="hover">
|
||||||
|
<template v-if="!isEdit">
|
||||||
|
<a-space wrap v-if="showValue && showValue.length>0">
|
||||||
|
<template v-for="(item,index) in editValue" :key="item.id">
|
||||||
|
<UserAvatar :organization-user-id="item.id" v-if="type==='user'"></UserAvatar>
|
||||||
|
<ProjectReleasePreview v-else-if="type==='release'" :project-release-id="item.id" :name="item.name"></ProjectReleasePreview>
|
||||||
|
<ProjectIssuePreview :name="item.name" :project-issue-id="item.id" v-else-if="type==='issue'"></ProjectIssuePreview>
|
||||||
|
<a-tag v-else>
|
||||||
|
{{item.name}}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
</a-space>
|
||||||
|
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-space size="mini" wrap>
|
||||||
|
<a-tag v-for="(value,index) in editValue" :closable="true" @close="onClose(index)" :key="value.id">
|
||||||
|
{{value.name}}
|
||||||
|
</a-tag>
|
||||||
|
<a-select v-model="addValue" allow-search @search="onSearch" v-if="showInput" @change="onChange">
|
||||||
|
<a-option v-for="item1 in searchValueList" :label="item1.name" :value="item1.id"></a-option>
|
||||||
|
</a-select>
|
||||||
|
<a-tag v-else :style="{backgroundColor: 'var(--color-fill-2)',border: '1px dashed var(--color-fill-3)',cursor: 'pointer',}" @click="showInput=true">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
Add
|
||||||
|
</a-tag>
|
||||||
|
<a-button type="text" @click="onSubmit">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="onBlur">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref, watchEffect} from "vue";
|
||||||
|
import {apiIssue, apiOrganization, apiProject, apiRelease, apiTeam} from "@/business/common/request/request";
|
||||||
|
import UserAvatar from "@/business/common/component/userAvatar.vue";
|
||||||
|
import ProjectIssuePreview from "@/business/controller/app/project/issue/projectIssuePreview.vue";
|
||||||
|
import ProjectReleasePreview from "@/business/controller/app/project/release/projectReleasePreview.vue";
|
||||||
|
|
||||||
|
const emit=defineEmits<{
|
||||||
|
(e:"update:modelValue",value:string[]):void
|
||||||
|
}>()
|
||||||
|
const props=defineProps<{
|
||||||
|
modelValue:string[],
|
||||||
|
type:"user"|"team"|"release"|"label"|"tag"|"issue",
|
||||||
|
projectId?:string
|
||||||
|
}>()
|
||||||
|
const showValue=ref<{
|
||||||
|
name?:string,
|
||||||
|
id:string,
|
||||||
|
}[]>([]);
|
||||||
|
const editValue=ref<{
|
||||||
|
name?:string,
|
||||||
|
id:string
|
||||||
|
}[]>([]);
|
||||||
|
const isEdit=ref(false)
|
||||||
|
const searchValueList=ref<{
|
||||||
|
name:string,
|
||||||
|
id:string,
|
||||||
|
}[]>([])
|
||||||
|
const addValue=ref("")
|
||||||
|
const showInput = ref(false);
|
||||||
|
const request=async ()=>{
|
||||||
|
if(props.modelValue && props.modelValue.length>0) {
|
||||||
|
let arr=await Promise.all(props.modelValue.map(item=>{
|
||||||
|
if(props.type==="team") {
|
||||||
|
return apiTeam.info({
|
||||||
|
teamId:item
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="user") {
|
||||||
|
return apiOrganization.user({
|
||||||
|
organizationUserId:item
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="release") {
|
||||||
|
return apiRelease.info({
|
||||||
|
projectReleaseId:item
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="label") {
|
||||||
|
return apiProject.getLabel({
|
||||||
|
labelId:item
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="tag") {
|
||||||
|
return apiOrganization.getTag({
|
||||||
|
memberTagId:item
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if(props.type==="issue") {
|
||||||
|
return apiIssue.basicInfo({
|
||||||
|
projectIssueId:item
|
||||||
|
}).then(data=>{
|
||||||
|
if(data.code==0) {
|
||||||
|
return {
|
||||||
|
id:data.data.id,
|
||||||
|
name:data.data.project.keyword+"-"+data.data.unique_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
arr=arr.filter(item=>{
|
||||||
|
return item!=null
|
||||||
|
})
|
||||||
|
showValue.value=arr
|
||||||
|
editValue.value=[...arr]
|
||||||
|
} else {
|
||||||
|
showValue.value=[]
|
||||||
|
editValue.value=[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watchEffect(()=>{
|
||||||
|
request()
|
||||||
|
})
|
||||||
|
|
||||||
|
const onFocus=()=>{
|
||||||
|
isEdit.value=true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur=()=>{
|
||||||
|
isEdit.value=false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit=()=>{
|
||||||
|
isEdit.value=false
|
||||||
|
emit("update:modelValue",editValue.value.map(item=>item.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange=()=>{
|
||||||
|
showInput.value=false
|
||||||
|
editValue.value=[...editValue.value,searchValueList.value.find(item=>{
|
||||||
|
if(item.id==addValue.value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})]
|
||||||
|
addValue.value=""
|
||||||
|
}
|
||||||
|
const onClose=(index:number)=>{
|
||||||
|
editValue.value.splice(index,1)
|
||||||
|
}
|
||||||
|
const onSearch=async (keyword:string)=>{
|
||||||
|
if(keyword) {
|
||||||
|
if(props.type==="team") {
|
||||||
|
let res=await apiTeam.list({
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="user") {
|
||||||
|
let res=await apiOrganization.listUser({
|
||||||
|
keyword,
|
||||||
|
page:0,
|
||||||
|
size:10
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.organizationUser.id,
|
||||||
|
name:item.organizationUser.nickname
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="release") {
|
||||||
|
let res=await apiRelease.list({
|
||||||
|
page:0,
|
||||||
|
size:10,
|
||||||
|
name:keyword,
|
||||||
|
projectId:props.projectId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="label") {
|
||||||
|
let res=await apiProject.listLabel({
|
||||||
|
page:0,
|
||||||
|
size:10,
|
||||||
|
keyword,
|
||||||
|
projectId:props.projectId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="tag") {
|
||||||
|
let res=await apiOrganization.listTag({
|
||||||
|
keyword
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if(props.type==="issue") {
|
||||||
|
let res=await apiIssue.filter({
|
||||||
|
page:0,
|
||||||
|
size:10,
|
||||||
|
projectId:props.projectId,
|
||||||
|
name:keyword
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
searchValueList.value=res.data.data.map(item=>{
|
||||||
|
return {
|
||||||
|
id:item.id,
|
||||||
|
name:item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.hover:hover {
|
||||||
|
background-color: rgb(230,231,237);
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,206 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<span style="display: inline-block;width: 100%;cursor: text" @mouseenter="onEnter" @mouseleave="onLeave" tabindex="-1" @focusin="onFocus" ref="element">
|
<span style="display: inline-block;width: 100%;cursor: text" @mouseenter="onEnter" @mouseleave="onLeave" tabindex="-1" @focus="onFocus" ref="element">
|
||||||
<template v-if="type==EClient_Field_Basic_Type.NAME">
|
<FieldEditBasicName :is-edit="isEdit" :show-value="showValue as string" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.NAME" @update="onUpdate" @cancel="onBlur"></FieldEditBasicName>
|
||||||
<span style="font-size: 24px;font-weight: bold" v-if="!isEdit">{{ showValue }}</span>
|
<FieldEditBasicDescription :is-edit="isEdit" :show-value="showValue as string" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.DESCRIPTION" @update="onUpdate" @cancel="onBlur"></FieldEditBasicDescription>
|
||||||
<template v-else>
|
<FieldEditBasicAssigner :is-edit="isEdit" :show-value="showValue as User" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.ASSIGNER" @update="onUpdate" @cancel="onBlur"></FieldEditBasicAssigner>
|
||||||
<a-row style="padding-right: 10px">
|
<FieldEditBasicReporter :is-edit="isEdit" :show-value="showValue as User" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.REPORTER" @update="onUpdate" @cancel="onBlur"></FieldEditBasicReporter>
|
||||||
<a-input v-model="editValue"></a-input>
|
<FieldEditBasicPriority :is-edit="isEdit" :show-value="showValue as ECommon_Model_Project_Issue_Priority" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.PRIORITY" @update="onUpdate" @cancel="onBlur"></FieldEditBasicPriority>
|
||||||
<a-button type="text" @click="onClick">
|
<FieldEditBasicLabel :is-edit="isEdit" :show-value="showValue as ICommon_Model_Project_Label[]" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.LABEL" @update="onUpdate" @cancel="onBlur"></FieldEditBasicLabel>
|
||||||
<template #icon>
|
<FieldEditBasicModule :is-edit="isEdit" :show-value="showValue as ICommon_Model_Project_Module[]" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.MODULE" @update="onUpdate" @cancel="onBlur"></FieldEditBasicModule>
|
||||||
<icon-check></icon-check>
|
<FieldEditBasicFixVersion :is-edit="isEdit" :show-value="showValue as DCSType<ICommon_Model_Project_Release>[]" :project-issue-id="projectIssueId" v-if="type==EClient_Field_Basic_Type.FIXVERSIONS" @update="onUpdate" @cancel="onBlur"></FieldEditBasicFixVersion>
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.DESCRIPTION">
|
|
||||||
<span style="line-height: 30px" v-if="!isEdit">{{ showValue }}</span>
|
|
||||||
<template v-else>
|
|
||||||
<a-row style="padding-right: 10px">
|
|
||||||
<a-textarea v-model="editValue" allow-clear></a-textarea>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.ASSIGNER">
|
|
||||||
<template v-if="!isEdit">
|
|
||||||
<UserAvatar v-if="showValue" :photo="showValue.photo" :name="showValue.nickname" :organization-user-id="showValue.organizationUserId"></UserAvatar>
|
|
||||||
<span v-else style="line-height: 30px;width: 100%;color: gray">No User</span>
|
|
||||||
</template>
|
|
||||||
<a-row style="padding-right: 10px" v-else>
|
|
||||||
<a-select allow-search allow-clear v-model="editValue" @search="onSearchAssigner">
|
|
||||||
<a-option v-for="item in assignerList" :label="item.organizationUser.nickname" :value="item.organizationUser.id">
|
|
||||||
<a-avatar :size="24" :image-url="item.user.photo"></a-avatar>
|
|
||||||
{{ item.organizationUser.nickname }}
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.REPORTER">
|
|
||||||
<template v-if="!isEdit">
|
|
||||||
<UserAvatar v-if="showValue" :photo="showValue.photo" :name="showValue.nickname" :organization-user-id="showValue.organizationUserId"></UserAvatar>
|
|
||||||
<span v-else style="line-height: 30px;width: 100%;color: gray">No User</span>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<a-row style="padding-right: 10px">
|
|
||||||
<a-select allow-search allow-clear v-model="editValue" @search="onSearchReporter">
|
|
||||||
<a-option v-for="item in reporterList" :label="item.organizationUser.nickname" :value="item.organizationUser.id">
|
|
||||||
<a-avatar :size="24" :image-url="item.user.photo"></a-avatar>
|
|
||||||
{{item.organizationUser.nickname}}
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.PRIORITY">
|
|
||||||
<FieldPriority :priority="showValue" v-if="!isEdit"></FieldPriority>
|
|
||||||
<template v-else>
|
|
||||||
<a-space size="mini">
|
|
||||||
<a-select v-model="editValue">
|
|
||||||
<a-option label="low" :value="ECommon_Model_Project_Issue_Priority.LOW"></a-option>
|
|
||||||
<a-option label="medium" :value="ECommon_Model_Project_Issue_Priority.MEDIUM"></a-option>
|
|
||||||
<a-option label="high" :value="ECommon_Model_Project_Issue_Priority.HIGH"></a-option>
|
|
||||||
<a-option label="urgent" :value="ECommon_Model_Project_Issue_Priority.URGENT"></a-option>
|
|
||||||
</a-select>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.LABEL">
|
|
||||||
<template v-if="!isEdit">
|
|
||||||
<a-space wrap size="mini" v-if="showValue.length>0">
|
|
||||||
<a-tag v-for="item in showValue" color="blue">{{item.name}}</a-tag>
|
|
||||||
</a-space>
|
|
||||||
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
|
||||||
</template>
|
|
||||||
<a-row style="padding-right: 10px" v-else>
|
|
||||||
<a-space size="mini" wrap>
|
|
||||||
<a-tag v-for="(item,index) in editValue" :closable="true" @close="onCloseLabelTag(index)" :key="item.id">
|
|
||||||
{{item.name}}
|
|
||||||
</a-tag>
|
|
||||||
<a-select v-model="addValue" allow-search @search="onSearchLabel" v-if="showInput" @change="onAddChange">
|
|
||||||
<a-option v-for="item in labelList" :label="item.name" :value="item.id"></a-option>
|
|
||||||
</a-select>
|
|
||||||
<a-tag v-else :style="{backgroundColor: 'var(--color-fill-2)',border: '1px dashed var(--color-fill-3)',cursor: 'pointer',}" @click="showInput=true">
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
Add
|
|
||||||
</a-tag>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.MODULE">
|
|
||||||
<template v-if="!isEdit">
|
|
||||||
<a-space wrap size="mini" v-if="showValue.length>0">
|
|
||||||
<template #split>
|
|
||||||
/
|
|
||||||
</template>
|
|
||||||
<span v-for="item in showValue" style="color: blue">{{item.name}}</span>
|
|
||||||
</a-space>
|
|
||||||
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
|
||||||
</template>
|
|
||||||
<a-row style="padding-right: 10px" v-else>
|
|
||||||
<a-cascader v-model="editValue" :field-names="fields" :options="moduleList" placeholder="please select" :format-label="format" check-strictly allow-clear allow-search></a-cascader>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
<template v-if="type==EClient_Field_Basic_Type.FIXVERSIONS">
|
|
||||||
<template v-if="!isEdit">
|
|
||||||
<a-space wrap size="mini" v-if="showValue.length>0">
|
|
||||||
<ProjectReleasePreview v-for="item in showValue" :key="item.id" :project-release-id="item.id" :name="item.name"></ProjectReleasePreview>
|
|
||||||
</a-space>
|
|
||||||
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
|
||||||
</template>
|
|
||||||
<a-row style="padding-right: 10px" v-else>
|
|
||||||
<a-space size="mini" wrap>
|
|
||||||
<a-tag v-for="(item,index) in editValue" :closable="true" @close="onCloseLabelTag(index)" :key="item.id">
|
|
||||||
{{item.name}}
|
|
||||||
</a-tag>
|
|
||||||
<a-select v-model="addValue" allow-search @search="onSearchRelease" v-if="showInput" @change="onAddChange">
|
|
||||||
<a-option v-for="item in labelList" :label="item.name" :value="item.id"></a-option>
|
|
||||||
</a-select>
|
|
||||||
<a-tag v-else :style="{backgroundColor: 'var(--color-fill-2)',border: '1px dashed var(--color-fill-3)',cursor: 'pointer',}" @click="showInput=true">
|
|
||||||
<template #icon>
|
|
||||||
<icon-plus />
|
|
||||||
</template>
|
|
||||||
Add
|
|
||||||
</a-tag>
|
|
||||||
<a-button type="text" @click="onClick">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="onBlur">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -208,118 +15,61 @@
|
|||||||
import {EClient_Field_Basic_Type} from "./fieldBasicType";
|
import {EClient_Field_Basic_Type} from "./fieldBasicType";
|
||||||
import {ICommon_Model_Project_Label} from "../../../../../../common/model/project_label";
|
import {ICommon_Model_Project_Label} from "../../../../../../common/model/project_label";
|
||||||
import {ICommon_Model_Project_Module} from "../../../../../../common/model/project_module";
|
import {ICommon_Model_Project_Module} from "../../../../../../common/model/project_module";
|
||||||
import {inject, onMounted, ref, watch} from "vue";
|
import {inject, ref, watch} from "vue";
|
||||||
import {apiIssue, apiOrganization, apiProject, apiRelease, DCSType} from "../../request/request";
|
import {DCSType} from "../../request/request";
|
||||||
import UserAvatar from "../userAvatar.vue";
|
|
||||||
import {
|
|
||||||
ICommon_Route_Res_Organization_User_Item,
|
|
||||||
ICommon_Route_Res_Project_CreateModule_Data
|
|
||||||
} from "../../../../../../common/routes/response";
|
|
||||||
import FieldPriority from "./fieldPriority.vue";
|
|
||||||
import {ECommon_Model_Project_Issue_Priority} from "../../../../../../common/model/project_issue";
|
import {ECommon_Model_Project_Issue_Priority} from "../../../../../../common/model/project_issue";
|
||||||
import {injectProjectInfo} from "../../util/symbol";
|
import {injectProjectInfo} from "../../util/symbol";
|
||||||
import {checkPermission, Permission_Types} from "../../../../../../common/permission/permission";
|
import {checkPermission, Permission_Types} from "../../../../../../common/permission/permission";
|
||||||
import {ICommon_Model_Project_Release} from "../../../../../../common/model/project_release";
|
import {ICommon_Model_Project_Release} from "../../../../../../common/model/project_release";
|
||||||
import ProjectReleasePreview from "../../../controller/app/project/release/projectReleasePreview.vue";
|
import FieldEditBasicName from "./basic/fieldEditBasicName.vue";
|
||||||
import {SessionStorage} from "../../storage/session";
|
import FieldEditBasicDescription from "./basic/fieldEditBasicDescription.vue";
|
||||||
|
import FieldEditBasicAssigner from "./basic/fieldEditBasicAssigner.vue";
|
||||||
|
import FieldEditBasicPriority from "./basic/fieldEditBasicPriority.vue";
|
||||||
|
import FieldEditBasicReporter from "./basic/fieldEditBasicReporter.vue";
|
||||||
|
import FieldEditBasicLabel from "./basic/fieldEditBasicLabel.vue";
|
||||||
|
import FieldEditBasicModule from "./basic/fieldEditBasicModule.vue";
|
||||||
|
import FieldEditBasicFixVersion from "./basic/fieldEditBasicFixVersion.vue";
|
||||||
|
|
||||||
type User={
|
type User={
|
||||||
id:string,
|
id:string,
|
||||||
organizationUserId:string,
|
organizationUserId?:string,
|
||||||
photo?:string,
|
photo?:string,
|
||||||
nickname?:string
|
nickname?:string
|
||||||
}
|
}
|
||||||
type Value=string|ECommon_Model_Project_Issue_Priority|User|ICommon_Model_Project_Label[]|ICommon_Model_Project_Module[]|number|ICommon_Model_Project_Release[]
|
type Value=string|ECommon_Model_Project_Issue_Priority|User|ICommon_Model_Project_Label[]|ICommon_Model_Project_Module[]|number|ICommon_Model_Project_Release[]
|
||||||
const props=defineProps<{
|
type Props={
|
||||||
projectIssueId:string,
|
projectIssueId:string
|
||||||
type:EClient_Field_Basic_Type,
|
} & (
|
||||||
value?:Value
|
{
|
||||||
}>()
|
type:EClient_Field_Basic_Type.NAME | EClient_Field_Basic_Type.DESCRIPTION,
|
||||||
const fields={
|
value?:string
|
||||||
label:"name",
|
} | {
|
||||||
value:"id",
|
type:EClient_Field_Basic_Type.PRIORITY,
|
||||||
children:"data"
|
value?:number
|
||||||
}
|
} | {
|
||||||
const showInput=ref(false)
|
type:EClient_Field_Basic_Type.ASSIGNER | EClient_Field_Basic_Type.REPORTER,
|
||||||
const addValue=ref("")
|
value?:User
|
||||||
|
} | {
|
||||||
|
type:EClient_Field_Basic_Type.LABEL,
|
||||||
|
value?:ICommon_Model_Project_Label[]
|
||||||
|
} | {
|
||||||
|
type:EClient_Field_Basic_Type.MODULE,
|
||||||
|
value?:ICommon_Model_Project_Module[]
|
||||||
|
} | {
|
||||||
|
type:EClient_Field_Basic_Type.FIXVERSIONS,
|
||||||
|
value?:ICommon_Model_Project_Release[]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const props=defineProps<Props>()
|
||||||
const element=ref<HTMLSpanElement>(null)
|
const element=ref<HTMLSpanElement>(null)
|
||||||
const showValue=ref(props.value)
|
const showValue=ref(props.value)
|
||||||
const editValue=ref<string|ECommon_Model_Project_Issue_Priority|string[]|{
|
|
||||||
id:string,
|
|
||||||
name:string
|
|
||||||
}[]>(null)
|
|
||||||
const assignEditValue=()=>{
|
|
||||||
switch (props.type) {
|
|
||||||
case EClient_Field_Basic_Type.DESCRIPTION:
|
|
||||||
case EClient_Field_Basic_Type.NAME: {
|
|
||||||
editValue.value=showValue.value as string
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case EClient_Field_Basic_Type.PRIORITY:{
|
|
||||||
editValue.value=showValue.value as number
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case EClient_Field_Basic_Type.REPORTER:
|
|
||||||
case EClient_Field_Basic_Type.ASSIGNER:{
|
|
||||||
editValue.value=""
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case EClient_Field_Basic_Type.LABEL:{
|
|
||||||
let value=showValue.value as ICommon_Model_Project_Label[]
|
|
||||||
editValue.value=value.length>0?value.map(item=>{
|
|
||||||
return {
|
|
||||||
id:item.id,
|
|
||||||
name:item.name
|
|
||||||
}
|
|
||||||
}):[]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case EClient_Field_Basic_Type.MODULE:{
|
|
||||||
let value=showValue.value as ICommon_Model_Project_Module[]
|
|
||||||
editValue.value=value.length>0?value[value.length-1].id:""
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case EClient_Field_Basic_Type.FIXVERSIONS:{
|
|
||||||
let value=showValue.value as ICommon_Model_Project_Release[]
|
|
||||||
editValue.value=value.length>0?value.map(item=>{
|
|
||||||
return {
|
|
||||||
id:item.id,
|
|
||||||
name:item.name
|
|
||||||
}
|
|
||||||
}):[]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const projectId=inject(injectProjectInfo).id;
|
|
||||||
const permission=inject(injectProjectInfo).permission
|
const permission=inject(injectProjectInfo).permission
|
||||||
const isEdit=ref(false)
|
const isEdit=ref(false)
|
||||||
const assignerList=ref<DCSType<ICommon_Route_Res_Organization_User_Item[]>>([])
|
|
||||||
const reporterList=ref<DCSType<ICommon_Route_Res_Organization_User_Item[]>>([])
|
|
||||||
const labelList=ref<{
|
|
||||||
id:string,
|
|
||||||
name:string
|
|
||||||
}[]>([])
|
|
||||||
const moduleList=ref<ICommon_Route_Res_Project_CreateModule_Data[]>([])
|
|
||||||
watch(()=>props.value,(newValue,oldValue)=>{
|
watch(()=>props.value,(newValue,oldValue)=>{
|
||||||
showValue.value=props.value
|
showValue.value=props.value
|
||||||
if(props.type===EClient_Field_Basic_Type.DESCRIPTION) {
|
|
||||||
if(!showValue.value) {
|
|
||||||
isEdit.value=true
|
|
||||||
} else {
|
|
||||||
isEdit.value=false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assignEditValue()
|
|
||||||
},{
|
},{
|
||||||
immediate:true
|
immediate:true,
|
||||||
})
|
deep:true
|
||||||
watch(isEdit,()=>{
|
|
||||||
if(isEdit.value && props.type==EClient_Field_Basic_Type.MODULE) {
|
|
||||||
getModuleList()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
const onEnter=(event:MouseEvent)=>{
|
const onEnter=(event:MouseEvent)=>{
|
||||||
if(!isEdit.value) {
|
if(!isEdit.value) {
|
||||||
@ -339,180 +89,14 @@ const onFocus=async (event:MouseEvent)=>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onBlur=async ()=>{
|
const onBlur=async ()=>{
|
||||||
if(props.type===EClient_Field_Basic_Type.DESCRIPTION && !editValue.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isEdit.value=false
|
isEdit.value=false
|
||||||
showInput.value=false
|
|
||||||
addValue.value=""
|
|
||||||
assignEditValue()
|
|
||||||
}
|
}
|
||||||
const onClick=async ()=>{
|
|
||||||
if(props.type==EClient_Field_Basic_Type.NAME) {
|
const onUpdate=(value)=>{
|
||||||
let res=await apiIssue.editBasicField({
|
showValue.value=value
|
||||||
projectIssueId:props.projectIssueId,
|
isEdit.value=false
|
||||||
name:editValue.value as string
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=editValue.value as string
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.DESCRIPTION) {
|
|
||||||
let res=await apiIssue.editDescription({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
description:editValue.value as string
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=editValue.value as string
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.ASSIGNER) {
|
|
||||||
let res=await apiIssue.editBasicField({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
assignerId:editValue.value as string
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=res.data.assigner_id as User
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.REPORTER) {
|
|
||||||
let res=await apiIssue.editBasicField({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
reporterId:editValue.value as string
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=res.data.reporter_id as User
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.PRIORITY) {
|
|
||||||
let res=await apiIssue.editBasicField({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
priority:editValue.value as ECommon_Model_Project_Issue_Priority
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=editValue.value as number
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.LABEL) {
|
|
||||||
let arr=editValue.value as {
|
|
||||||
id:string,
|
|
||||||
name:string
|
|
||||||
}[]
|
|
||||||
let arrId=Array.from(new Set(arr.map(item=>item.id)));
|
|
||||||
let res=await apiIssue.bindLabel({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
labelIds:arrId
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=res.data
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.MODULE) {
|
|
||||||
let res=await apiIssue.bindModule({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
moduleId:editValue.value as string
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=res.data
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
} else if(props.type==EClient_Field_Basic_Type.FIXVERSIONS) {
|
|
||||||
let arr=editValue.value as {
|
|
||||||
id:string,
|
|
||||||
name:string
|
|
||||||
}[]
|
|
||||||
let arrId=Array.from(new Set(arr.map(item=>item.id)));
|
|
||||||
let res=await apiIssue.bindReleases({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
projectReleaseIds:arrId
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
showValue.value=res.data
|
|
||||||
onBlur()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onSearchAssigner=async (keyword:string)=>{
|
|
||||||
let res=await apiOrganization.listUser({
|
|
||||||
organizationId:SessionStorage.get("organizationId"),
|
|
||||||
keyword,
|
|
||||||
page:0,
|
|
||||||
size:10
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
assignerList.value=res.data.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onSearchReporter=async (keyword:string)=>{
|
|
||||||
let res=await apiOrganization.listUser({
|
|
||||||
organizationId:SessionStorage.get("organizationId"),
|
|
||||||
keyword,
|
|
||||||
page:0,
|
|
||||||
size:10
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
reporterList.value=res.data.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onSearchLabel=async (keyword:string)=>{
|
|
||||||
let res=await apiProject.listLabel({
|
|
||||||
projectId,
|
|
||||||
keyword,
|
|
||||||
page:0,
|
|
||||||
size:10
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
labelList.value=res.data.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onSearchRelease=async (keyword:string)=>{
|
|
||||||
let res=await apiRelease.list({
|
|
||||||
projectId,
|
|
||||||
name:keyword,
|
|
||||||
page:0,
|
|
||||||
size:10
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
labelList.value=res.data.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const getModuleList=async ()=>{
|
|
||||||
let res=await apiProject.listModule({
|
|
||||||
projectId
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
moduleList.value=res.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const format = (options) => {
|
|
||||||
const labels = options.map(option => option.name)
|
|
||||||
return labels.join('/')
|
|
||||||
}
|
|
||||||
onMounted(()=>{
|
|
||||||
if(props.type==EClient_Field_Basic_Type.DESCRIPTION && showValue.value=="") {
|
|
||||||
element.value.focus()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const onCloseLabelTag=(index:number)=>{
|
|
||||||
(editValue.value as any[]).splice(index,1)
|
|
||||||
}
|
|
||||||
const onAddChange=()=>{
|
|
||||||
let arr=editValue.value as {
|
|
||||||
id:string,
|
|
||||||
name:string
|
|
||||||
}[]
|
|
||||||
let index=labelList.value.findIndex((item)=>{
|
|
||||||
if(item.id==addValue.value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
arr.push({
|
|
||||||
id:labelList.value[index].id,
|
|
||||||
name:labelList.value[index].name
|
|
||||||
})
|
|
||||||
addValue.value=""
|
|
||||||
showInput.value=false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-space v-if="!isEdit">
|
<a-space v-if="!isEdit" wrap>
|
||||||
<template v-if="showValue && showValue.length>0">
|
<template v-if="showValue && showValue.length>0">
|
||||||
<a-tag v-for="item in showValue">{{item.value}}</a-tag>
|
<a-tag v-for="item in showValue">{{item.value}}</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
|
||||||
</a-space>
|
</a-space>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-space size="mini">
|
<a-space size="mini" wrap>
|
||||||
<a-select v-model="editValue" allow-clear allow-search multiple>
|
<a-select v-model="editValue" allow-clear allow-search multiple>
|
||||||
<a-option v-for="item1 in list" :label="item1.value" :value="item1.id"></a-option>
|
<a-option v-for="item1 in list" :label="item1.value" :value="item1.id"></a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, watchEffect} from "vue";
|
import {ref, watchEffect} from "vue";
|
||||||
import {
|
import {
|
||||||
ICommon_Model_Workflow_Node_Field_Type_Config
|
ICommon_Model_Workflow_Node_Field_Type_Config
|
||||||
} from "../../../../../../common/model/workflow_node_field_type_config";
|
} from "../../../../../../common/model/workflow_node_field_type_config";
|
||||||
|
|
||||||
const props=defineProps<{
|
const props=defineProps<{
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
<a-textarea :default-value="item.field.default_string_value" v-else-if="item.fieldType.type===ECommon_Field_Type.MULTITEXT" v-model="item.fieldValue.value"></a-textarea>
|
<a-textarea :default-value="item.field.default_string_value" v-else-if="item.fieldType.type===ECommon_Field_Type.MULTITEXT" v-model="item.fieldValue.value"></a-textarea>
|
||||||
<a-date-picker v-else-if="item.fieldType.type===ECommon_Field_Type.DATE" v-model="item.fieldValue.value"/>
|
<a-date-picker v-else-if="item.fieldType.type===ECommon_Field_Type.DATE" v-model="item.fieldValue.value"/>
|
||||||
<a-time-picker v-else-if="item.fieldType.type===ECommon_Field_Type.TIME" v-model="item.fieldValue.value"/>
|
<a-time-picker v-else-if="item.fieldType.type===ECommon_Field_Type.TIME" v-model="item.fieldValue.value"/>
|
||||||
<a-select v-else-if="item.fieldType.type===ECommon_Field_Type.SELECT" :default-value="item.values.filter(item=>item.selected).map(item=>item.id)" v-model="item.fieldValue.value">
|
<a-select v-else-if="item.fieldType.type===ECommon_Field_Type.SELECT" :default-value="item.values.filter((item1:ICommon_Model_Workflow_Node_Field_Type_Config)=>item1.selected).map((item1:ICommon_Model_Workflow_Node_Field_Type_Config)=>item1.id)" v-model="item.fieldValue.value">
|
||||||
<a-option v-for="item in item.values" :label="item.value" :value="item.id"></a-option>
|
<a-option v-for="item in item.values" :label="item.value" :value="item.id"></a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-select multiple v-else-if="item.fieldType.type===ECommon_Field_Type.MULTISELECT" :default-value="item.values.filter(item=>item.selected).map(item=>item.id)" v-model="item.fieldValue.value">
|
<a-select multiple v-else-if="item.fieldType.type===ECommon_Field_Type.MULTISELECT" :default-value="item.values.filter((item1:ICommon_Model_Workflow_Node_Field_Type_Config)=>item1.selected).map((item1:ICommon_Model_Workflow_Node_Field_Type_Config)=>item1.id)" v-model="item.fieldValue.value">
|
||||||
<a-option v-for="item in item.values" :label="item.value" :value="item.id"></a-option>
|
<a-option v-for="item in item.values" :label="item.value" :value="item.id"></a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-select v-else-if="item.fieldType.type===ECommon_Field_Type.MULTILABEL" allow-search @search="onSearchMultiLabel" v-model="item.fieldValue.value" multiple>
|
<a-select v-else-if="item.fieldType.type===ECommon_Field_Type.MULTILABEL" allow-search @search="onSearchMultiLabel" v-model="item.fieldValue.value" multiple>
|
||||||
<a-option v-for="item in multiLabelList" :value="item.id" :label="item.name"></a-option>
|
<a-option v-for="item1 in multiLabelList" :value="item1.id" :label="item1.name"></a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-select v-else-if="item.fieldType.type===ECommon_Field_Type.LABEL" allow-search @search="onSearchLabel" v-model="item.fieldValue.value">
|
<a-select v-else-if="item.fieldType.type===ECommon_Field_Type.LABEL" allow-search @search="onSearchLabel" v-model="item.fieldValue.value">
|
||||||
<a-option v-for="item in labelList" :value="item.id" :label="item.name"></a-option>
|
<a-option v-for="item1 in labelList" :value="item1.id" :label="item1.name"></a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@ -34,6 +34,9 @@ import {
|
|||||||
ECommon_Model_Workflow_Node_Field_Type_Label_Type
|
ECommon_Model_Workflow_Node_Field_Type_Label_Type
|
||||||
} from "../../../../../../common/model/workflow_node_field_type";
|
} from "../../../../../../common/model/workflow_node_field_type";
|
||||||
import {SessionStorage} from "../../storage/session";
|
import {SessionStorage} from "../../storage/session";
|
||||||
|
import {
|
||||||
|
ICommon_Model_Workflow_Node_Field_Type_Config
|
||||||
|
} from "../../../../../../common/model/workflow_node_field_type_config";
|
||||||
|
|
||||||
const props=defineProps<{
|
const props=defineProps<{
|
||||||
item:DCSType<ICommon_Route_Res_Workflow_Node_Field & {
|
item:DCSType<ICommon_Route_Res_Workflow_Node_Field & {
|
||||||
@ -89,16 +92,16 @@ switch (props.item.fieldType.type) {
|
|||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
const multiLabelList=ref<DCSType<ICommon_Route_Res_Project_Issue_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,
|
name:string,
|
||||||
id:string,
|
id:string,
|
||||||
photo:string
|
photo:string
|
||||||
}[]>>([])
|
}>[]>([])
|
||||||
const labelList=ref<DCSType<ICommon_Route_Res_Project_Issue_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,
|
name:string,
|
||||||
id:string,
|
id:string,
|
||||||
photo:string
|
photo:string
|
||||||
}[]>>([])
|
}>[]>([])
|
||||||
const onSearchMultiLabel=async (value:string)=>{
|
const onSearchMultiLabel=async (value:string)=>{
|
||||||
if(props.item.field.label_type===ECommon_Model_Workflow_Node_Field_Type_Label_Type.ISSUE) {
|
if(props.item.field.label_type===ECommon_Model_Workflow_Node_Field_Type_Label_Type.ISSUE) {
|
||||||
let res=await apiIssue.filter({
|
let res=await apiIssue.filter({
|
||||||
|
51
code/client/src/business/common/component/flow/approval.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import {DiamondNode, DiamondNodeModel} from "@logicflow/core";
|
||||||
|
import {NodeTextTheme} from "@logicflow/core/types/constant/DefaultTheme";
|
||||||
|
import {
|
||||||
|
ECommon_Model_Workflow_Node_Status,
|
||||||
|
ICommon_Model_Workflow_Node
|
||||||
|
} from "../../../../../../common/model/workflow_node";
|
||||||
|
|
||||||
|
class approvalModel extends DiamondNodeModel {
|
||||||
|
override getNodeStyle(): { [p: string]: any; width?: number; height?: number; radius?: number; fill?: string; stroke?: string; strokeWidth?: number } {
|
||||||
|
const style=super.getNodeStyle();
|
||||||
|
style.strokeWidth=0
|
||||||
|
let props=this.getProperties() as ICommon_Model_Workflow_Node
|
||||||
|
if(props.status==ECommon_Model_Workflow_Node_Status.INPROGRESS) {
|
||||||
|
style.fill="rgb(4,57,192)"
|
||||||
|
} else if(props.status==ECommon_Model_Workflow_Node_Status.DONE) {
|
||||||
|
style.fill="rgb(15,119,72)"
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
|
||||||
|
override getTextStyle(): NodeTextTheme {
|
||||||
|
const style=super.getTextStyle();
|
||||||
|
let props=this.getProperties() as ICommon_Model_Workflow_Node
|
||||||
|
if(props.status==ECommon_Model_Workflow_Node_Status.INPROGRESS) {
|
||||||
|
style.fill="white"
|
||||||
|
style.stroke="white"
|
||||||
|
} else if(props.status==ECommon_Model_Workflow_Node_Status.DONE) {
|
||||||
|
style.fill="white"
|
||||||
|
style.stroke="white"
|
||||||
|
}
|
||||||
|
style.fontSize=13
|
||||||
|
style.strokeWidth=0.8
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
override initNodeData(data: any) {
|
||||||
|
super.initNodeData(data);
|
||||||
|
this.rx=40
|
||||||
|
this.ry=40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class approvalView extends DiamondNode {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const flowApproval= {
|
||||||
|
type: "approval",
|
||||||
|
view: approvalView,
|
||||||
|
model: approvalModel
|
||||||
|
};
|
@ -54,4 +54,4 @@ export const flowNode= {
|
|||||||
type: "node",
|
type: "node",
|
||||||
view: UserTaskView,
|
view: UserTaskView,
|
||||||
model: UserTaskModel
|
model: UserTaskModel
|
||||||
};
|
};
|
@ -132,6 +132,24 @@
|
|||||||
|
|
||||||
to you
|
to you
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="obj.type===ECommon_Model_Notification_Type.ISSUE_APPROVAL_RESOLVE">
|
||||||
|
ISSUE:
|
||||||
|
|
||||||
|
<UserAvatar :organization-user-id="obj.operationOrganizationUser.id" :name="obj.operationOrganizationUser.name" :photo="obj.operationOrganizationUser.photo" :organization-id="obj.organization_id"></UserAvatar>
|
||||||
|
|
||||||
|
resolved the approval of issue
|
||||||
|
|
||||||
|
<a href="javascript:void(0)" @click="onIssue">{{(obj.data as ISSUE)?.project.keyword}}-{{(obj.data as ISSUE)?.issue.unique_id}}</a>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="obj.type===ECommon_Model_Notification_Type.ISSUE_APPROVAL_REJECT">
|
||||||
|
ISSUE:
|
||||||
|
|
||||||
|
<UserAvatar :organization-user-id="obj.operationOrganizationUser.id" :name="obj.operationOrganizationUser.name" :photo="obj.operationOrganizationUser.photo" :organization-id="obj.organization_id"></UserAvatar>
|
||||||
|
|
||||||
|
rejected the approval of issue
|
||||||
|
|
||||||
|
<a href="javascript:void(0)" @click="onIssue">{{(obj.data as ISSUE)?.project.keyword}}-{{(obj.data as ISSUE)?.issue.unique_id}}</a>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -264,6 +264,9 @@ export class RichEditorEvent {
|
|||||||
onMouseUp(event:MouseEvent){
|
onMouseUp(event:MouseEvent){
|
||||||
this.isMouseDown=false
|
this.isMouseDown=false
|
||||||
let selection=window.getSelection()
|
let selection=window.getSelection()
|
||||||
|
if(selection.rangeCount==0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let range=selection.getRangeAt(0)
|
let range=selection.getRangeAt(0)
|
||||||
if(this.selectElementList.length>0) {
|
if(this.selectElementList.length>0) {
|
||||||
range=range.cloneRange()
|
range=range.cloneRange()
|
||||||
|
Before Width: | Height: | Size: 434 KiB |
@ -59,7 +59,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("dragType",EClient_Drag_Type.FILE)
|
ele.setAttribute("dragType",EClient_Drag_Type.FILE)
|
||||||
ele.setAttribute("dragValue",obj.value)
|
ele.setAttribute("dragValue",obj.value)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-file"
|
icon.className="svg svg-file"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="gray"
|
icon.style.color="gray"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -86,7 +86,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-list-alt"
|
icon.className="svg svg-project"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="green"
|
icon.style.color="green"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -114,7 +114,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-link"
|
icon.className="svg svg-project-issue"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="green"
|
icon.style.color="green"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -142,7 +142,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-tasks"
|
icon.className="svg svg-project-release"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="green"
|
icon.style.color="green"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -169,7 +169,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-files-o"
|
icon.className="svg svg-wiki"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="rgb(0,120,212)"
|
icon.style.color="rgb(0,120,212)"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -197,7 +197,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-file-text-o"
|
icon.className="svg svg-wiki-item"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="rgb(0,120,212)"
|
icon.style.color="rgb(0,120,212)"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -224,7 +224,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-calendar-o"
|
icon.className="svg svg-calendar-event"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="orange"
|
icon.style.color="orange"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
@ -252,7 +252,7 @@ export class RichEditorHandle {
|
|||||||
ele.setAttribute("shortcutRefId",obj.value)
|
ele.setAttribute("shortcutRefId",obj.value)
|
||||||
ele.setAttribute("shortcutName",obj.label)
|
ele.setAttribute("shortcutName",obj.label)
|
||||||
let icon=document.createElement("i")
|
let icon=document.createElement("i")
|
||||||
icon.className="fa fa-video-camera"
|
icon.className="svg svg-meeting-room"
|
||||||
icon.style.marginRight="5px"
|
icon.style.marginRight="5px"
|
||||||
icon.style.color="red"
|
icon.style.color="red"
|
||||||
ele.prepend(icon)
|
ele.prepend(icon)
|
||||||
|
@ -21,7 +21,6 @@ import {
|
|||||||
ICommon_Content_Line,
|
ICommon_Content_Line,
|
||||||
ICommon_Content_Line_Config
|
ICommon_Content_Line_Config
|
||||||
} from "../../../../../../common/model/content";
|
} from "../../../../../../common/model/content";
|
||||||
import "./font/css/font-awesome.min.css"
|
|
||||||
import UserShortView from "../userShortView.vue";
|
import UserShortView from "../userShortView.vue";
|
||||||
import {dragElementList, EClient_Drag_Type} from "../../../../teamOS/common/directive/drag";
|
import {dragElementList, EClient_Drag_Type} from "../../../../teamOS/common/directive/drag";
|
||||||
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../common/model/finder_item";
|
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../common/model/finder_item";
|
||||||
@ -147,6 +146,9 @@ const onMouseMove=(event:MouseEvent)=>{
|
|||||||
|
|
||||||
const calculateIndex=()=>{
|
const calculateIndex=()=>{
|
||||||
let selection=window.getSelection()
|
let selection=window.getSelection()
|
||||||
|
if(selection.rangeCount==0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let range=selection.getRangeAt(0)
|
let range=selection.getRangeAt(0)
|
||||||
let startOffset=range.startOffset
|
let startOffset=range.startOffset
|
||||||
selectStartIndexPath=[]
|
selectStartIndexPath=[]
|
||||||
@ -343,4 +345,38 @@ div {
|
|||||||
:deep a[fileId]:hover {
|
:deep a[fileId]:hover {
|
||||||
background-color: lightgray;
|
background-color: lightgray;
|
||||||
}
|
}
|
||||||
|
:deep .svg {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-size: contain;
|
||||||
|
height: 1em;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
:deep .svg-file {
|
||||||
|
background-image: url("@/assert/custom/file.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-project {
|
||||||
|
background-image: url("@/assert/custom/project_item.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-project-issue {
|
||||||
|
background-image: url("@/assert/custom/project_issue_item.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-project-release {
|
||||||
|
background-image: url("@/assert/custom/project_release_item.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-wiki {
|
||||||
|
background-image: url("@/assert/custom/wiki_space_item.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-wiki-item {
|
||||||
|
background-image: url("@/assert/custom/wiki_item.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-calendar-event {
|
||||||
|
background-image: url("@/assert/custom/calendar_event_item.svg");
|
||||||
|
}
|
||||||
|
:deep .svg-meeting-room {
|
||||||
|
background-image: url("@/assert/custom/meeting_room_item.svg");
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -62,7 +62,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, ref} from "vue";
|
import {computed, onBeforeMount, ref, watch} from "vue";
|
||||||
import {ICommon_Model_Organization_User} from "../../../../../common/model/organization_user";
|
import {ICommon_Model_Organization_User} from "../../../../../common/model/organization_user";
|
||||||
import {apiOrganization, DCSType} from "../request/request";
|
import {apiOrganization, DCSType} from "../request/request";
|
||||||
import {EClient_EVENTBUS_TYPE, eventBus} from "../event/event";
|
import {EClient_EVENTBUS_TYPE, eventBus} from "../event/event";
|
||||||
@ -73,7 +73,7 @@ import {Message} from "@arco-design/web-vue";
|
|||||||
|
|
||||||
const loading=ref(true)
|
const loading=ref(true)
|
||||||
const props=defineProps<{
|
const props=defineProps<{
|
||||||
name:string,
|
name?:string,
|
||||||
photo?:string,
|
photo?:string,
|
||||||
organizationUserId:string,
|
organizationUserId:string,
|
||||||
closeable?:boolean,
|
closeable?:boolean,
|
||||||
@ -87,13 +87,21 @@ const emit=defineEmits<{
|
|||||||
const myOrganizationUserId=SessionStorage.get("organizationUserId")
|
const myOrganizationUserId=SessionStorage.get("organizationUserId")
|
||||||
const showCloseable=ref(false)
|
const showCloseable=ref(false)
|
||||||
const root=ref(null);
|
const root=ref(null);
|
||||||
|
const name=ref("")
|
||||||
|
const photo=ref("")
|
||||||
const status=ref(ECommon_User_Online_Status.OFFLINE)
|
const status=ref(ECommon_User_Online_Status.OFFLINE)
|
||||||
|
watch(()=>[props.name,props.photo],()=>{
|
||||||
|
name.value=props.name
|
||||||
|
photo.value=props.photo
|
||||||
|
},{
|
||||||
|
immediate:true
|
||||||
|
})
|
||||||
const imgName=computed(()=>{
|
const imgName=computed(()=>{
|
||||||
if(props.name.includes(" ")) {
|
if(name.value?.includes(" ")) {
|
||||||
let arr=props.name.split(" ")
|
let arr=name.value.split(" ")
|
||||||
return arr[0][0].toUpperCase()+arr[1][0].toUpperCase()
|
return arr[0][0].toUpperCase()+arr[1][0].toUpperCase()
|
||||||
} else {
|
} else {
|
||||||
return props.name[0].toUpperCase()
|
return name.value?name.value[0].toUpperCase():""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const info=ref<DCSType<ICommon_Model_Organization_User>>(null)
|
const info=ref<DCSType<ICommon_Model_Organization_User>>(null)
|
||||||
@ -141,6 +149,20 @@ const onMessage=()=>{
|
|||||||
}
|
}
|
||||||
eventBus.emit(EClient_EVENTBUS_TYPE.OPEN_IM_CHAT,props.organizationUserId,ECommon_IM_Message_EntityType.USER)
|
eventBus.emit(EClient_EVENTBUS_TYPE.OPEN_IM_CHAT,props.organizationUserId,ECommon_IM_Message_EntityType.USER)
|
||||||
}
|
}
|
||||||
|
onBeforeMount(async ()=>{
|
||||||
|
if(props.organizationUserId && !props.name) {
|
||||||
|
let res=await apiOrganization.user({
|
||||||
|
organizationUserId:props.organizationUserId,
|
||||||
|
...(props.organizationId && {
|
||||||
|
organizationId:props.organizationId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
name.value=res.data.nickname
|
||||||
|
photo.value=res.data.user.photo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
<template v-if="calendarEventInfo?.meeting">
|
<template v-if="calendarEventInfo?.meeting">
|
||||||
<a-switch v-model="form.meeting"></a-switch>
|
<a-switch v-model="form.meeting"></a-switch>
|
||||||
<a-popover position="right" v-if="form.meeting" trigger="click">
|
<a-popover position="right" v-if="form.meeting" trigger="click">
|
||||||
<a-button type="primary" status="danger" style="margin-left: 20px">
|
<a-button type="primary" status="success" style="margin-left: 20px">
|
||||||
Start Meeting
|
Start Meeting
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
@ -91,7 +91,7 @@
|
|||||||
<a-switch v-model="form.meeting" v-else></a-switch>
|
<a-switch v-model="form.meeting" v-else></a-switch>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<a-button type="primary" status="danger" @click="onMeeting" v-else>
|
<a-button type="primary" status="success" @click="onMeeting" v-else>
|
||||||
Join Meeting
|
Join Meeting
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="flex: 1 1 auto;display: flex;align-items: center">
|
<div style="flex: 1 1 auto;display: flex;align-items: center">
|
||||||
<a-popover position="right" trigger="click" v-if="isSelf">
|
<a-popover position="right" trigger="click" v-if="isSelf">
|
||||||
<a-button type="primary" status="danger" size="mini">
|
<a-button type="primary" status="success" size="mini">
|
||||||
Start Meeting
|
Start Meeting
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
@ -58,7 +58,7 @@
|
|||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
<a-button type="primary" status="danger" size="mini" @click="onMeeting" v-else>
|
<a-button type="primary" status="success" size="mini" @click="onMeeting" v-else>
|
||||||
Join Meeting
|
Join Meeting
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -106,7 +106,11 @@ const onPopMenuClick=(type:ECommon_Content_Line_Config_Type,handleFunc:(item:ICo
|
|||||||
|
|
||||||
const onSend = () => {
|
const onSend = () => {
|
||||||
if(content.value.length>0) {
|
if(content.value.length>0) {
|
||||||
props.meetingClient.sendMessage(JSON.stringify(content.value))
|
props.meetingClient.sendMessage(JSON.stringify(content.value.map(item=>{
|
||||||
|
return {
|
||||||
|
arr:item.arr
|
||||||
|
}
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
content.value = []
|
content.value = []
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,210 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-comment :avatar="store.userInfo.photo" style="margin-right: 10px">
|
||||||
|
<template #content>
|
||||||
|
<a-spin :loading="loading" style="width: 100%;border: 1px solid lightgray" v-drop.file.shortcut.disk="onDropAdd">
|
||||||
|
<RichEditor v-model="commentAdd" @upload-file="onUploadFile" :pop-menu-list="popMenuList" @pop-menu-click="onPopMenuClick" @custom-anchor-click="onCustomAnchorClick" @quote-list="onQuoteList" ref="objEditor"></RichEditor>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<a-button type="primary" size="small" @click="onCommentAdd" style="margin-top: 10px">Save</a-button>
|
||||||
|
</template>
|
||||||
|
</a-comment>
|
||||||
|
<a-comment v-for="(item,index) in commentList" :author="item.value.created_by.nickname" :datetime="moment(item.value.created_time).format('YYYY-MM-DD HH:mm:ss')">
|
||||||
|
<template #avatar>
|
||||||
|
<UserAvatar :organization-user-id="item.value.created_by.organizationUserId" :name="item.value.created_by.nickname" :photo="item.value.created_by.photo" :only-photo="true"></UserAvatar>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<template v-if="!item.isEdit">
|
||||||
|
<RichEditor :model-value="JSON.parse(item.value.content)" :readonly="true" @custom-anchor-click="onCustomAnchorClick"></RichEditor>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-spin :loading="loading" style="width: 100%" v-drop.file.shortcut.disk="onDrop.bind(null,index)">
|
||||||
|
<RichEditor v-model="item.editContent" @upload-file="onUploadFile" :pop-menu-list="popMenuList" @pop-menu-click="onPopMenuClick" @custom-anchor-click="onCustomAnchorClick" @quote-list="onQuoteList" ref="objEditor"></RichEditor>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template #actions v-if="checkPermission(permission,Permission_Types.Project.ADMIN) || item.value.created_by.id==store.userInfo.id">
|
||||||
|
<template v-if="!item.isEdit">
|
||||||
|
<a-link href="javascript:void(0)" style="color: gray;font-size: 13px;padding: 0px" @click="onEdit(item)">
|
||||||
|
Edit
|
||||||
|
</a-link>
|
||||||
|
<a-link href="javascript:void(0)" style="color: gray;font-size: 13px;padding: 0px" @click="onRemoveComment(index)">
|
||||||
|
Delete
|
||||||
|
</a-link>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-button type="text" @click="onSave(item)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-check></icon-check>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" @click="item.editContent=[],item.isEdit=false">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-comment>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import moment from "moment/moment";
|
||||||
|
import {checkPermission, Permission_Types} from "../../../../../../../common/permission/permission";
|
||||||
|
import {getCurrentInstance, inject, onBeforeMount, ref} from "vue";
|
||||||
|
import {apiFile, apiIssue, DCSType} from "../../../../common/request/request";
|
||||||
|
import {
|
||||||
|
ECommon_Content_Line_Config_Type,
|
||||||
|
ICommon_Content_Line,
|
||||||
|
ICommon_Content_Line_Config,
|
||||||
|
ICommon_Model_Content
|
||||||
|
} from "../../../../../../../common/model/content";
|
||||||
|
import {Message} from "@arco-design/web-vue";
|
||||||
|
import {Dialog} from "../../../../common/component/dialog/dialog";
|
||||||
|
import {getRootNavigatorRef} from "../../../../../teamOS/common/component/navigator/navigator";
|
||||||
|
import {useDesktopStore} from "../../../desktop/store/desktop";
|
||||||
|
import {injectProjectInfo} from "../../../../common/util/symbol";
|
||||||
|
import RichEditor from "../../../../common/component/richEditor/richEditor.vue";
|
||||||
|
import {RichEditorEventHandle} from "../../../../common/component/richEditorEventHandle";
|
||||||
|
import {DropParam, vDrop} from "../../../../../teamOS/common/directive/drop";
|
||||||
|
import UserAvatar from "../../../../common/component/userAvatar.vue";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const commentList=ref<DCSType<{
|
||||||
|
value:ICommon_Model_Content,
|
||||||
|
isEdit:boolean,
|
||||||
|
editContent:ICommon_Content_Line[]
|
||||||
|
}>[]>([])
|
||||||
|
const commentAdd=ref<ICommon_Content_Line[]>([])
|
||||||
|
const permission=inject(injectProjectInfo).permission
|
||||||
|
const root=getRootNavigatorRef()
|
||||||
|
const appContext=getCurrentInstance().appContext
|
||||||
|
const store=useDesktopStore()
|
||||||
|
const objEditor=ref<InstanceType<typeof RichEditor>>()
|
||||||
|
const objEditorAdd=ref<InstanceType<typeof RichEditor>>()
|
||||||
|
const loading=ref(false)
|
||||||
|
const popMenuList=ref(RichEditorEventHandle.popMenuList)
|
||||||
|
const getCommentList=async ()=>{
|
||||||
|
let res=await apiIssue.commentList({
|
||||||
|
projectIssueId:props.projectIssueId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
commentList.value=res.data.map(item=>{
|
||||||
|
return {
|
||||||
|
value:item,
|
||||||
|
isEdit:false,
|
||||||
|
editContent:[]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onCommentAdd=async ()=>{
|
||||||
|
let value=JSON.stringify(commentAdd.value.map(item=>{
|
||||||
|
return {
|
||||||
|
arr:item.arr
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
let res=await apiIssue.commentCreate({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
content:value
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
commentList.value.unshift({
|
||||||
|
value:res.data,
|
||||||
|
isEdit:false,
|
||||||
|
editContent:[]
|
||||||
|
})
|
||||||
|
commentAdd.value=[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onSave=async (item:DCSType<{
|
||||||
|
value:ICommon_Model_Content,
|
||||||
|
isEdit:boolean,
|
||||||
|
editContent:ICommon_Content_Line[]
|
||||||
|
}>)=>{
|
||||||
|
let value=JSON.stringify(item.editContent.map(item=>{
|
||||||
|
return {
|
||||||
|
arr:item.arr
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
if(value.length==0) {
|
||||||
|
Message.error("content can not be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let res=await apiIssue.commentEdit({
|
||||||
|
contentId:item.value.id,
|
||||||
|
content:value
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
item.value=res.data
|
||||||
|
item.isEdit=false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onRemoveComment=async (index:number)=>{
|
||||||
|
let item=commentList.value[index];
|
||||||
|
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this comment?")
|
||||||
|
if(ret) {
|
||||||
|
let res=await apiIssue.commentRemove({
|
||||||
|
contentId:item.value.id
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
commentList.value.splice(index,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onEdit=async (item:DCSType<{
|
||||||
|
value:ICommon_Model_Content,
|
||||||
|
isEdit:boolean,
|
||||||
|
editContent:ICommon_Content_Line[]
|
||||||
|
}>)=>{
|
||||||
|
item.isEdit=true
|
||||||
|
item.editContent=JSON.parse(item.value.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
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=(type:ECommon_Content_Line_Config_Type,handleFunc:(item:ICommon_Content_Line_Config)=>void)=>{
|
||||||
|
RichEditorEventHandle.onPopMenuClick(type,root,appContext,loading,handleFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCustomAnchorClick=(type:ECommon_Content_Line_Config_Type,value:string,link:string,label:string)=>{
|
||||||
|
RichEditorEventHandle.onCustomAnchorClick(type,value,link,label)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onQuoteList=(keyword:string,handleFunc:(list:{
|
||||||
|
value:string,
|
||||||
|
label:string,
|
||||||
|
photo:string
|
||||||
|
}[])=>void)=>{
|
||||||
|
RichEditorEventHandle.onQuoteList(keyword,handleFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDrop=(index:number,data?:DropParam)=>{
|
||||||
|
RichEditorEventHandle.onDrop(objEditor.value[index],data,loading)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDropAdd=(data?:DropParam)=>{
|
||||||
|
RichEditorEventHandle.onDrop(objEditorAdd.value,data,loading)
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(()=>{
|
||||||
|
getCommentList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div class="issueProfileDetail">
|
||||||
|
<a-collapse :default-active-key="['detail']">
|
||||||
|
<a-collapse-item key="detail" header="Detail">
|
||||||
|
<a-form layout="vertical" :model="{}">
|
||||||
|
<a-form-item label="Issue Type">
|
||||||
|
{{info.issueType.name}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Assigner">
|
||||||
|
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.ASSIGNER" :value="info.assigner_id"></FieldEditBasic>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Reporter">
|
||||||
|
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.REPORTER" :value="info.reporter_id"></FieldEditBasic>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Priority">
|
||||||
|
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.PRIORITY" :value="info.priority"></FieldEditBasic>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Module">
|
||||||
|
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.MODULE" :value="moduleList"></FieldEditBasic>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Label">
|
||||||
|
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.LABEL" :value="labelList"></FieldEditBasic>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Fix Versions">
|
||||||
|
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.FIXVERSIONS" :value="releaseList"></FieldEditBasic>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-collapse-item>
|
||||||
|
<a-collapse-item key="more" header="More">
|
||||||
|
<a-form layout="vertical" :model="{}" v-if="fieldList.length>0">
|
||||||
|
<a-form-item v-for="item in fieldList" :label="item.nodeField.field.name" :key="item.issueFieldValue.id">
|
||||||
|
<FieldEdit :item="item"></FieldEdit>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-collapse-item>
|
||||||
|
</a-collapse>
|
||||||
|
<a-row style="margin-top: 10px;color: gray;font-size: 12px;line-height: 1.3;padding-left: 5px;margin-bottom: 10px">
|
||||||
|
Created {{moment(info.created_time).format('YYYY-MM-DD HH:mm:ss')}}
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {EClient_Field_Basic_Type} from "../../../../common/component/field/fieldBasicType";
|
||||||
|
import moment from "moment/moment";
|
||||||
|
import FieldEdit from "../../../../common/component/field/fieldEdit.vue";
|
||||||
|
import FieldEditBasic from "../../../../common/component/field/fieldEditBasic.vue";
|
||||||
|
import {apiIssue, DCSType} from "../../../../common/request/request";
|
||||||
|
import {
|
||||||
|
ICommon_Route_Res_ProjectIssue_BasicInfo,
|
||||||
|
ICommon_Route_Res_ProjectIssue_fieldsInfo
|
||||||
|
} from "../../../../../../../common/routes/response";
|
||||||
|
import {onBeforeMount, ref} from "vue";
|
||||||
|
import {ICommon_Model_Project_Label} from "../../../../../../../common/model/project_label";
|
||||||
|
import {ICommon_Model_Project_Module} from "../../../../../../../common/model/project_module";
|
||||||
|
import {ICommon_Model_Project_Release} from "../../../../../../../common/model/project_release";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
info:DCSType<ICommon_Route_Res_ProjectIssue_BasicInfo>,
|
||||||
|
moduleList:DCSType<ICommon_Model_Project_Module>[],
|
||||||
|
labelList:DCSType<ICommon_Model_Project_Label>[],
|
||||||
|
fieldList:ICommon_Route_Res_ProjectIssue_fieldsInfo[]
|
||||||
|
}>()
|
||||||
|
const releaseList=ref<DCSType<ICommon_Model_Project_Release[]>>([])
|
||||||
|
|
||||||
|
const getReleaseList=async ()=>{
|
||||||
|
let res=await apiIssue.releaseList({
|
||||||
|
projectIssueId:props.info.id
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
releaseList.value=res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(()=>{
|
||||||
|
getReleaseList()
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.issueProfileDetail :deep(div[role="region"]) {
|
||||||
|
background-color: white !important;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
.issueProfileDetail :deep .arco-form-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.issueProfileDetail :deep .arco-form-item-label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,91 @@
|
|||||||
|
<template xmlns="http://www.w3.org/1999/html">
|
||||||
|
<div>
|
||||||
|
<a-list hoverable>
|
||||||
|
<a-list-item v-for="item in historyList">
|
||||||
|
<div style="width: 100%;">
|
||||||
|
<template v-if="item.type===ECommon_Model_Project_Issue_History_Type.CREATE_ISSUE">
|
||||||
|
<div style="width: 100%;align-items: center;display: flex">
|
||||||
|
<UserAvatar :organization-user-id="item.organization_user_id"></UserAvatar>
|
||||||
|
created the issue
|
||||||
|
<span style="color: gray">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="item.type===ECommon_Model_Project_Issue_History_Type.APPROVAL_RESOLVE">
|
||||||
|
<div style="width: 100%;align-items: center;display: flex">
|
||||||
|
<UserAvatar :organization-user-id="item.organization_user_id"></UserAvatar>
|
||||||
|
resolved your approval
|
||||||
|
<span style="color: gray">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="item.type===ECommon_Model_Project_Issue_History_Type.APPROVAL_REJECT">
|
||||||
|
<div style="width: 100%;align-items: center;display: flex">
|
||||||
|
<UserAvatar :organization-user-id="item.organization_user_id"></UserAvatar>
|
||||||
|
rejected your approval
|
||||||
|
<span style="color: gray">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="item.type===ECommon_Model_Project_Issue_History_Type.UPDATE_FIELD">
|
||||||
|
<div style="width: 100%;align-items: center;display: flex">
|
||||||
|
<UserAvatar :organization-user-id="item.organization_user_id"></UserAvatar>
|
||||||
|
updated the field
|
||||||
|
<span style="color: blue">
|
||||||
|
{{item.name}}
|
||||||
|
</span>
|
||||||
|
<span style="color: gray">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="item.value" style="display: flex;align-items: center">
|
||||||
|
new value :
|
||||||
|
<UserAvatar v-if="/\d{19,}/.test(item.value)" :organization-user-id="item.value"></UserAvatar>
|
||||||
|
<span v-else style="color: gray">{{item.value}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="item.type===ECommon_Model_Project_Issue_History_Type.UPDATE_NODE">
|
||||||
|
<div style="width: 100%;align-items: center;display: flex">
|
||||||
|
<UserAvatar :organization-user-id="item.organization_user_id"></UserAvatar>
|
||||||
|
updated the workflow
|
||||||
|
<span style="color: #544646">
|
||||||
|
{{item.name}}
|
||||||
|
</span>
|
||||||
|
<span style="color: gray">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
new workflow : <span style="color: gray">{{item.value}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {apiIssue, DCSType} from "../../../../common/request/request";
|
||||||
|
import {onBeforeMount, ref} from "vue";
|
||||||
|
import {
|
||||||
|
ECommon_Model_Project_Issue_History_Type,
|
||||||
|
ICommon_Model_Project_Issue_History
|
||||||
|
} from "../../../../../../../common/model/project_issue_history";
|
||||||
|
import UserAvatar from "../../../../common/component/userAvatar.vue";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const historyList=ref<DCSType<ICommon_Model_Project_Issue_History>[]>([])
|
||||||
|
const listHistory=async ()=>{
|
||||||
|
let res=await apiIssue.listHistory({
|
||||||
|
projectIssueId:props.projectIssueId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
historyList.value=res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(()=>{
|
||||||
|
listHistory()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -50,6 +50,7 @@
|
|||||||
</a-space>
|
</a-space>
|
||||||
</a-row>
|
</a-row>
|
||||||
<a-divider></a-divider>
|
<a-divider></a-divider>
|
||||||
|
<span style="font-size: small;color: gray">If you wanna open in a new tab,hold command(Mac) or control(Win) Key,click the link below</span>
|
||||||
<a-table style="margin-top: 10px" :columns="columns" :data="issueList" :pagination="pagination" @pageChange="onPageChange">
|
<a-table style="margin-top: 10px" :columns="columns" :data="issueList" :pagination="pagination" @pageChange="onPageChange">
|
||||||
<template #type="{record}">
|
<template #type="{record}">
|
||||||
{{record.issueType.name}}
|
{{record.issueType.name}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-layout style="height: 100%">
|
<a-layout style="height: 100%">
|
||||||
<a-layout-content id="issueProfileContent">
|
<a-layout-content class="issueProfileContent">
|
||||||
<a-row style="color: gray" v-drag.shortcut="()=>({
|
<a-row style="color: gray" v-drag.shortcut="()=>({
|
||||||
shortcutType:ECommon_Model_Finder_Shortcut_Type.PROJECT_ISSUE,
|
shortcutType:ECommon_Model_Finder_Shortcut_Type.PROJECT_ISSUE,
|
||||||
shortcutRefId:projectIssueId,
|
shortcutRefId:projectIssueId,
|
||||||
@ -11,15 +11,28 @@
|
|||||||
<a-row style="margin-top: 10px">
|
<a-row style="margin-top: 10px">
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.NAME" :value="info.name" v-if="info"></FieldEditBasic>
|
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.NAME" :value="info.name" v-if="info"></FieldEditBasic>
|
||||||
</a-row>
|
</a-row>
|
||||||
<a-row style="margin-top: 10px">
|
<a-row v-if="info?.approval?.type===ECommon_Model_Project_Issue_Approval_Type.REJECTED" style="align-items: center;margin-top: 10px;">
|
||||||
<a-space>
|
<UserAvatar :organization-user-id="info.approval.approval_organization_user_id"></UserAvatar>
|
||||||
|
<span style="color: orange;font-weight: bold"> rejected your approval</span>
|
||||||
|
<a-popover v-if="info.approval.reason" position="right">
|
||||||
|
<icon-info-circle-fill style="color: orange;margin-left: 10px"></icon-info-circle-fill>
|
||||||
|
<template #content>
|
||||||
|
<RichEditor style="color: black" :model-value="JSON.parse(info.approval.reason)" :readonly="true" @custom-anchor-click="onCustomAnchorClick"></RichEditor>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
</a-row>
|
||||||
|
<a-row style="margin-top: 20px">
|
||||||
|
<a-space wrap>
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<a-button :disabled="actionList.length==0" :type="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.NOTSTART?'secondary':'primary'" :status="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.DONE?'success':'normal'">{{info?.workflowNode.name}} <icon-down></icon-down>
|
<a-button :disabled="actionList.length==0" :type="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.NOTSTART?'secondary':'primary'" :status="info?.approval?.type===ECommon_Model_Project_Issue_Approval_Type.REJECTED?'danger':info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.DONE?'success':'normal'">{{calculateApprovalName}} <icon-down></icon-down>
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-doption v-for="item in actionList" :key="item.id" @click="onAction(item)">{{item.name}}</a-doption>
|
<a-doption v-for="item in actionList as any[]" :key="item.isApproval?item.name:item.id" @click="onAction(item)">{{item.name}}</a-doption>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
|
<a-button v-if="!parentIssue" @click="onCreateSubIssue">
|
||||||
|
Create Child Issue
|
||||||
|
</a-button>
|
||||||
<a-dropdown-button>
|
<a-dropdown-button>
|
||||||
Link Issue
|
Link Issue
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -52,6 +65,7 @@
|
|||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
|
<a-doption v-if="checkPermission(permission,Permission_Types.Project.EDIT)" @click="onCopy">Copy</a-doption>
|
||||||
<a-doption v-if="checkPermission(permission,Permission_Types.Project.ADMIN) || info?.created_by.id===store.userInfo.id" @click="onDelete" style="color: red">Delete</a-doption>
|
<a-doption v-if="checkPermission(permission,Permission_Types.Project.ADMIN) || info?.created_by.id===store.userInfo.id" @click="onDelete" style="color: red">Delete</a-doption>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
@ -61,151 +75,26 @@
|
|||||||
Description
|
Description
|
||||||
</a-row>
|
</a-row>
|
||||||
<a-row style="margin-top: 10px">
|
<a-row style="margin-top: 10px">
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.DESCRIPTION" :value="description"></FieldEditBasic>
|
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.DESCRIPTION" :value="description" style="margin-right: 10px;box-sizing: border-box"></FieldEditBasic>
|
||||||
</a-row>
|
</a-row>
|
||||||
<template v-if="parentIssue">
|
<ProjectIssueRelated :project-issue-id="projectIssueId" :child-issue-list="childIssueList" :parent-issue="parentIssue" :related-issue-list="relatedIssueList" @remove-parent="parentIssue=null"></ProjectIssueRelated>
|
||||||
<a-row style="margin-top: 20px;font-weight: bold">Parent Issue</a-row>
|
<a-tabs type="rounded" style="margin-top: 50px;" lazy-load size="small">
|
||||||
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
|
<a-tab-pane key="comment" title="Comments">
|
||||||
<a-list-item>
|
<ProjectIssueComment style="margin-top: 10px" :project-issue-id="projectIssueId"></ProjectIssueComment>
|
||||||
<a-space size="large">
|
</a-tab-pane>
|
||||||
{{key+"-"+parentIssue.unique_id}}
|
<a-tab-pane key="history" title="History">
|
||||||
<a-link href="javascript:void(0)">{{parentIssue.name}}</a-link>
|
<ProjectIssueHistory :project-issue-id="projectIssueId"></ProjectIssueHistory>
|
||||||
<FieldPriority :priority="parentIssue.priority"></FieldPriority>
|
</a-tab-pane>
|
||||||
</a-space>
|
</a-tabs>
|
||||||
<template #actions>
|
|
||||||
<a-button type="text" size="mini" @click="onRemoveItem('parent')">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</a-list-item>
|
|
||||||
</a-list>
|
|
||||||
</template>
|
|
||||||
<template v-if="childIssueList.length>0">
|
|
||||||
<a-row style="margin-top: 20px;font-weight: bold">Child Issues</a-row>
|
|
||||||
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
|
|
||||||
<a-list-item v-for="(item,index) in childIssueList" :key="item.id">
|
|
||||||
<a-space size="large">
|
|
||||||
{{key+"-"+item.unique_id}}
|
|
||||||
<a-link href="javascript:void(0)">{{item.name}}</a-link>
|
|
||||||
<FieldPriority :priority="item.priority"></FieldPriority>
|
|
||||||
</a-space>
|
|
||||||
<template #actions>
|
|
||||||
<a-button type="text" size="mini" @click="onRemoveItem('child',index)">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</a-list-item>
|
|
||||||
</a-list>
|
|
||||||
</template>
|
|
||||||
<template v-if="relatedIssueList.length>0">
|
|
||||||
<a-row style="margin-top: 20px;font-weight: bold">Related Issues</a-row>
|
|
||||||
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
|
|
||||||
<a-list-item v-for="(item,index) in relatedIssueList" :key="item.id">
|
|
||||||
<a-space size="large">
|
|
||||||
{{key+"-"+item.unique_id}}
|
|
||||||
<a-link href="javascript:void(0)">{{item.name}}</a-link>
|
|
||||||
<FieldPriority :priority="item.priority"></FieldPriority>
|
|
||||||
</a-space>
|
|
||||||
<template #actions>
|
|
||||||
<a-button type="text" size="mini" @click="onRemoveItem('related',index)">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</a-list-item>
|
|
||||||
</a-list>
|
|
||||||
</template>
|
|
||||||
<a-row style="margin-top: 50px;font-weight: bold">Comments</a-row>
|
|
||||||
<a-comment v-for="(item,index) in commentList" :author="item.value.created_by.nickname" :datetime="moment(item.value.created_time).format('YYYY-MM-DD HH:mm:ss')" :avatar="item.value.created_by.photo" style="margin-right: 10px">
|
|
||||||
<template #content>
|
|
||||||
<template v-if="!item.isEdit">
|
|
||||||
{{item.value.content}}
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<a-textarea allow-clear v-model="item.editContent"></a-textarea>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template #actions v-if="checkPermission(permission,Permission_Types.Project.ADMIN) || item.value.created_by.id==store.userInfo.id">
|
|
||||||
<template v-if="!item.isEdit">
|
|
||||||
<a-link href="javascript:void(0)" style="color: gray;font-size: 13px;padding: 0px" @click="item.isEdit=true">
|
|
||||||
Edit
|
|
||||||
</a-link>
|
|
||||||
<a-link href="javascript:void(0)" style="color: gray;font-size: 13px;padding: 0px" @click="onRemoveComment(index)">
|
|
||||||
Delete
|
|
||||||
</a-link>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<a-button type="text" @click="onEditComment(item)">
|
|
||||||
<template #icon>
|
|
||||||
<icon-check></icon-check>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" @click="item.editContent='',item.isEdit=false">
|
|
||||||
<template #icon>
|
|
||||||
<icon-close style="color: red"></icon-close>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</a-comment>
|
|
||||||
<a-comment :avatar="store.userInfo.photo" style="margin-right: 10px">
|
|
||||||
<template #content>
|
|
||||||
<a-textarea placeholder="please type your comment" v-model="commentAdd"></a-textarea>
|
|
||||||
</template>
|
|
||||||
<template #actions>
|
|
||||||
<a-button type="primary" size="small" @click="onCommentAdd">Save</a-button>
|
|
||||||
</template>
|
|
||||||
</a-comment>
|
|
||||||
</a-layout-content>
|
</a-layout-content>
|
||||||
<a-layout-sider :resize-directions="['left']" :width="200" style="overflow-y: auto">
|
<a-layout-sider :resize-directions="['left']" :width="200" style="overflow-y: auto">
|
||||||
<a-collapse :default-active-key="['detail']" style="margin: 5px 5px 0px 5px" id="issueProfileDetail">
|
<ProjectIssueField :label-list="labelList" :module-list="moduleList" :field-list="fieldList" :info="info" v-if="info" style="margin: 5px 5px 0px 5px"></ProjectIssueField>
|
||||||
<a-collapse-item key="detail" header="Detail">
|
|
||||||
<a-form layout="vertical" :model="{}">
|
|
||||||
<a-form-item label="Issue Type">
|
|
||||||
{{info?.issueType.name}}
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Assigner">
|
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.ASSIGNER" :value="info.assigner_id" v-if="info"></FieldEditBasic>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Reporter">
|
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.REPORTER" :value="info.reporter_id" v-if="info"></FieldEditBasic>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Priority">
|
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.PRIORITY" :value="info.priority" v-if="info"></FieldEditBasic>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Module">
|
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.MODULE" :value="moduleList"></FieldEditBasic>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Label">
|
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.LABEL" :value="labelList"></FieldEditBasic>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Fix Versions">
|
|
||||||
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.FIXVERSIONS" :value="releaseList"></FieldEditBasic>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-collapse-item>
|
|
||||||
<a-collapse-item key="more" header="More">
|
|
||||||
<a-form layout="vertical" :model="{}" v-if="fieldList.length>0">
|
|
||||||
<a-form-item v-for="item in fieldList" :label="item.nodeField.field.name" :key="item.issueFieldValue.id">
|
|
||||||
<FieldEdit :item="item"></FieldEdit>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-collapse-item>
|
|
||||||
</a-collapse>
|
|
||||||
<a-row style="margin-top: 10px;color: gray;font-size: 12px;line-height: 1.3;padding-left: 5px;margin-bottom: 10px">
|
|
||||||
Created {{moment(info?.created_time).format('YYYY-MM-DD HH:mm:ss')}}
|
|
||||||
</a-row>
|
|
||||||
</a-layout-sider>
|
</a-layout-sider>
|
||||||
</a-layout>
|
</a-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {getCurrentInstance, inject, markRaw, onBeforeMount, ref, watch} from "vue";
|
import {computed, getCurrentInstance, inject, markRaw, onBeforeMount, ref, watch} from "vue";
|
||||||
import {injectProjectInfo} from "../../../../common/util/symbol";
|
import {injectProjectInfo} from "../../../../common/util/symbol";
|
||||||
import {apiIssue, apiMeeting, DCSType} from "../../../../common/request/request";
|
import {apiIssue, apiMeeting, DCSType} from "../../../../common/request/request";
|
||||||
import {
|
import {
|
||||||
@ -216,28 +105,30 @@ import FieldEditBasic from "../../../../common/component/field/fieldEditBasic.vu
|
|||||||
import {EClient_Field_Basic_Type} from "../../../../common/component/field/fieldBasicType";
|
import {EClient_Field_Basic_Type} from "../../../../common/component/field/fieldBasicType";
|
||||||
import {ICommon_Model_Project_Label} from "../../../../../../../common/model/project_label";
|
import {ICommon_Model_Project_Label} from "../../../../../../../common/model/project_label";
|
||||||
import {ICommon_Model_Project_Module} from "../../../../../../../common/model/project_module";
|
import {ICommon_Model_Project_Module} from "../../../../../../../common/model/project_module";
|
||||||
import FieldEdit from "../../../../common/component/field/fieldEdit.vue";
|
|
||||||
import moment from "moment";
|
|
||||||
import {ICommon_Model_Project_Issue} from "../../../../../../../common/model/project_issue";
|
import {ICommon_Model_Project_Issue} from "../../../../../../../common/model/project_issue";
|
||||||
import FieldPriority from "../../../../common/component/field/fieldPriority.vue";
|
|
||||||
import {Dialog} from "../../../../common/component/dialog/dialog";
|
import {Dialog} from "../../../../common/component/dialog/dialog";
|
||||||
import {getCurrentNavigator, getRootNavigatorRef} from "../../../../../teamOS/common/component/navigator/navigator";
|
import {getCurrentNavigator, getRootNavigatorRef} from "../../../../../teamOS/common/component/navigator/navigator";
|
||||||
import ProjectIssueBind from "./projectIssueBind.vue";
|
import ProjectIssueBind from "./projectIssueBind.vue";
|
||||||
import {Message} from "@arco-design/web-vue";
|
import {Message} from "@arco-design/web-vue";
|
||||||
import {ICommon_Model_Content} from "../../../../../../../common/model/content";
|
|
||||||
import {useDesktopStore} from "../../../desktop/store/desktop";
|
import {useDesktopStore} from "../../../desktop/store/desktop";
|
||||||
import {checkPermission, Permission_Types} from "../../../../../../../common/permission/permission";
|
import {checkPermission, Permission_Types} from "../../../../../../../common/permission/permission";
|
||||||
import {ICommon_Model_Workflow_Action} from "../../../../../../../common/model/workflow_action";
|
import {ICommon_Model_Workflow_Action} from "../../../../../../../common/model/workflow_action";
|
||||||
import {ECommon_Model_Workflow_Node_Status} from "../../../../../../../common/model/workflow_node";
|
import {ECommon_Model_Workflow_Node_Status} from "../../../../../../../common/model/workflow_node";
|
||||||
import ProjectIssueNext from "./projectIssueNext.vue";
|
import ProjectIssueNext from "./projectIssueNext.vue";
|
||||||
import {ICommon_Model_Project_Release} from "../../../../../../../common/model/project_release";
|
|
||||||
import {vDrag} from "../../../../../teamOS/common/directive/drag";
|
import {vDrag} from "../../../../../teamOS/common/directive/drag";
|
||||||
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../../common/model/finder_item";
|
|
||||||
import UserAvatar from "../../../../common/component/userAvatar.vue";
|
import UserAvatar from "../../../../common/component/userAvatar.vue";
|
||||||
import {SessionStorage} from "../../../../common/storage/session";
|
import {SessionStorage} from "../../../../common/storage/session";
|
||||||
import {TableRowSelection} from "@arco-design/web-vue/es/table/interface";
|
import {TableRowSelection} from "@arco-design/web-vue/es/table/interface";
|
||||||
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
|
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
|
||||||
import {ECommon_Model_Organization_Member_Type} from "../../../../../../../common/model/organization";
|
import {ECommon_Model_Organization_Member_Type} from "../../../../../../../common/model/organization";
|
||||||
|
import ProjectIssueComment from "./projectIssueComment.vue";
|
||||||
|
import ProjectIssueField from "./projectIssueField.vue";
|
||||||
|
import ProjectIssueRelated from "./projectIssueRelated.vue";
|
||||||
|
import ProjectIssueHistory from "./projectIssueHistory.vue";
|
||||||
|
import {ECommon_Model_Project_Issue_Approval_Type} from "../../../../../../../common/model/project_issue_approval";
|
||||||
|
import RichEditor from "@/business/common/component/richEditor/richEditor.vue";
|
||||||
|
import {ECommon_Content_Line_Config_Type} from "../../../../../../../common/model/content";
|
||||||
|
import {RichEditorEventHandle} from "@/business/common/component/richEditorEventHandle";
|
||||||
|
|
||||||
const props=defineProps<{
|
const props=defineProps<{
|
||||||
projectIssueId:string
|
projectIssueId:string
|
||||||
@ -250,20 +141,16 @@ const key=inject(injectProjectInfo).key
|
|||||||
const permission=inject(injectProjectInfo).permission
|
const permission=inject(injectProjectInfo).permission
|
||||||
const info=ref<DCSType<ICommon_Route_Res_ProjectIssue_BasicInfo>>()
|
const info=ref<DCSType<ICommon_Route_Res_ProjectIssue_BasicInfo>>()
|
||||||
const description=ref("")
|
const description=ref("")
|
||||||
const labelList=ref<DCSType<ICommon_Model_Project_Label[]>>([])
|
|
||||||
const moduleList=ref<DCSType<ICommon_Model_Project_Module[]>>([])
|
|
||||||
const fieldList=ref<ICommon_Route_Res_ProjectIssue_fieldsInfo[]>([])
|
|
||||||
const parentIssue=ref<DCSType<ICommon_Model_Project_Issue>>();
|
const parentIssue=ref<DCSType<ICommon_Model_Project_Issue>>();
|
||||||
const relatedIssueList=ref<DCSType<ICommon_Model_Project_Issue>[]>([])
|
const relatedIssueList=ref<DCSType<ICommon_Model_Project_Issue>[]>([])
|
||||||
const childIssueList=ref<DCSType<ICommon_Model_Project_Issue>[]>([])
|
const childIssueList=ref<DCSType<ICommon_Model_Project_Issue>[]>([])
|
||||||
const commentList=ref<DCSType<{
|
const moduleList=ref<DCSType<ICommon_Model_Project_Module>[]>([])
|
||||||
value:ICommon_Model_Content,
|
const labelList=ref<DCSType<ICommon_Model_Project_Label>[]>([])
|
||||||
isEdit:boolean,
|
const actionList=ref<DCSType<ICommon_Model_Workflow_Action>[] | {
|
||||||
editContent:string
|
isApproval:true,
|
||||||
}[]>>([])
|
name:"Resolve"|"Reject"|"Revoke"|"Commit"
|
||||||
const actionList=ref<DCSType<ICommon_Model_Workflow_Action>[]>([])
|
}[]>([])
|
||||||
const releaseList=ref<DCSType<ICommon_Model_Project_Release[]>>([])
|
const fieldList=ref<ICommon_Route_Res_ProjectIssue_fieldsInfo[]>([])
|
||||||
const commentAdd=ref("")
|
|
||||||
const store=useDesktopStore()
|
const store=useDesktopStore()
|
||||||
const issueRelatedUserList=ref<{
|
const issueRelatedUserList=ref<{
|
||||||
id:string,
|
id:string,
|
||||||
@ -302,7 +189,7 @@ const getDescription=async ()=>{
|
|||||||
projectIssueId:props.projectIssueId
|
projectIssueId:props.projectIssueId
|
||||||
})
|
})
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
description.value=res.data
|
description.value=res.data?res.data:"[]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getOtherInfo=async ()=>{
|
const getOtherInfo=async ()=>{
|
||||||
@ -317,50 +204,7 @@ const getOtherInfo=async ()=>{
|
|||||||
relatedIssueList.value=res.data.relateds
|
relatedIssueList.value=res.data.relateds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getFieldList=async ()=>{
|
|
||||||
let res=await apiIssue.fieldsInfo({
|
|
||||||
projectIssueId:props.projectIssueId
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
fieldList.value=res.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onRemoveItem=async (type:"parent"|"child"|"related",index:number)=>{
|
|
||||||
if(type==="parent") {
|
|
||||||
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove parent issue?")
|
|
||||||
if(ret) {
|
|
||||||
let res=await apiIssue.removeParentIssue({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
projectIssueParentId:parentIssue.value.id
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
parentIssue.value=null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(type=="child") {
|
|
||||||
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove child issue?")
|
|
||||||
if(ret) {
|
|
||||||
let res=await apiIssue.removeChildIssue({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
projectIssueChildId:childIssueList.value[index].id
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
childIssueList.value.splice(index,1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(type=="related") {
|
|
||||||
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove related issue?")
|
|
||||||
if(ret) {
|
|
||||||
let res=await apiIssue.removeRelatedIssue({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
projectIssueRelatedId:relatedIssueList.value[index].id
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
relatedIssueList.value.splice(index,1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onAddItem=async (type:"parent"|"child"|"related")=>{
|
const onAddItem=async (type:"parent"|"child"|"related")=>{
|
||||||
if(type=="parent") {
|
if(type=="parent") {
|
||||||
let ret=await Dialog.open(root.value,appContext,"Parent",markRaw(ProjectIssueBind),{
|
let ret=await Dialog.open(root.value,appContext,"Parent",markRaw(ProjectIssueBind),{
|
||||||
@ -412,64 +256,7 @@ const onAddItem=async (type:"parent"|"child"|"related")=>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getCommentList=async ()=>{
|
|
||||||
let res=await apiIssue.commentList({
|
|
||||||
projectIssueId:props.projectIssueId
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
commentList.value=res.data.map(item=>{
|
|
||||||
return {
|
|
||||||
value:item,
|
|
||||||
isEdit:false,
|
|
||||||
editContent:item.content
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onCommentAdd=async ()=>{
|
|
||||||
let res=await apiIssue.commentCreate({
|
|
||||||
projectIssueId:props.projectIssueId,
|
|
||||||
content:commentAdd.value
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
commentList.value.unshift({
|
|
||||||
value:res.data,
|
|
||||||
isEdit:false,
|
|
||||||
editContent:res.data.content
|
|
||||||
})
|
|
||||||
commentAdd.value=""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onEditComment=async (item:DCSType<{
|
|
||||||
value:ICommon_Model_Content,
|
|
||||||
isEdit:boolean,
|
|
||||||
editContent:string
|
|
||||||
}>)=>{
|
|
||||||
if(!item.editContent) {
|
|
||||||
Message.error("content can not be empty")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let res=await apiIssue.commentEdit({
|
|
||||||
contentId:item.value.id,
|
|
||||||
content:item.editContent
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
item.value.content=item.editContent
|
|
||||||
item.isEdit=false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onRemoveComment=async (index:number)=>{
|
|
||||||
let item=commentList.value[index];
|
|
||||||
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this comment?")
|
|
||||||
if(ret) {
|
|
||||||
let res=await apiIssue.commentRemove({
|
|
||||||
contentId:item.value.id
|
|
||||||
})
|
|
||||||
if(res?.code==0) {
|
|
||||||
commentList.value.splice(index,1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onDelete=async ()=>{
|
const onDelete=async ()=>{
|
||||||
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this issue?")
|
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this issue?")
|
||||||
if(ret) {
|
if(ret) {
|
||||||
@ -490,34 +277,80 @@ const getActionList=async ()=>{
|
|||||||
actionList.value=res.data
|
actionList.value=res.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onAction=async (item:ICommon_Model_Workflow_Action)=>{
|
const onAction=async (item:ICommon_Model_Workflow_Action | {
|
||||||
let res=await apiIssue.getNextNodeFields({
|
isApproval:true,
|
||||||
projectIssueId:props.projectIssueId,
|
name:"Resolve"|"Reject"|"Revoke"|"Commit"
|
||||||
workflowActionId:item.id
|
})=>{
|
||||||
})
|
if("isApproval" in item) {
|
||||||
if(res?.code==0) {
|
if(item.name==="Revoke") {
|
||||||
if(res.data.length>0) {
|
let res=await apiIssue.revokeApproval({
|
||||||
let ret=await Dialog.open(root.value,appContext,item.name,markRaw(ProjectIssueNext),{
|
projectIssueId:props.projectIssueId
|
||||||
projectId:projectId,
|
})
|
||||||
projectIssueId:props.projectIssueId,
|
if(res?.code!=0) {
|
||||||
workflowActionId:item.id,
|
Message.error(res.msg)
|
||||||
items:res.data
|
return
|
||||||
})
|
}
|
||||||
if(!ret) {
|
} else if(item.name==="Resolve") {
|
||||||
return
|
let res=await apiIssue.resolveApproval({
|
||||||
}
|
projectIssueId:props.projectIssueId
|
||||||
} else {
|
})
|
||||||
await apiIssue.confirmNextNode({
|
if(res?.code!=0) {
|
||||||
projectIssueId:props.projectIssueId,
|
Message.error(res.msg)
|
||||||
workflowActionId:item.id
|
return
|
||||||
})
|
}
|
||||||
}
|
} else if(item.name==="Reject") {
|
||||||
getInfo()
|
let ret=await Dialog.inputRich(root.value,appContext,"Reject Reason")
|
||||||
getFieldList()
|
if(ret) {
|
||||||
getActionList()
|
let res=await apiIssue.rejectApproval({
|
||||||
} else {
|
projectIssueId:props.projectIssueId,
|
||||||
Message.error(res.msg)
|
reason:JSON.stringify(ret)
|
||||||
}
|
})
|
||||||
|
if(res?.code!=0) {
|
||||||
|
Message.error(res.msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if(item.name==="Commit") {
|
||||||
|
let res=await apiIssue.commitApproval({
|
||||||
|
projectIssueId:props.projectIssueId
|
||||||
|
})
|
||||||
|
if(res?.code!=0) {
|
||||||
|
Message.error(res.msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let res=await apiIssue.getNextNodeFields({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
workflowActionId:item.id
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
if(res.data.length>0) {
|
||||||
|
let ret=await Dialog.open(root.value,appContext,item.name,markRaw(ProjectIssueNext),{
|
||||||
|
projectId:projectId,
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
workflowActionId:item.id,
|
||||||
|
items:res.data
|
||||||
|
})
|
||||||
|
if(!ret) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await apiIssue.confirmNextNode({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
workflowActionId:item.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Message.error(res.msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getInfo()
|
||||||
|
getActionList()
|
||||||
|
getFieldList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onMeeting=async ()=>{
|
const onMeeting=async ()=>{
|
||||||
@ -530,13 +363,30 @@ const onMeeting=async ()=>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getReleaseList=async ()=>{
|
const onCopy=async ()=>{
|
||||||
let res=await apiIssue.releaseList({
|
let ret=await Dialog.input(root.value,appContext,"type the issue's name")
|
||||||
projectIssueId:props.projectIssueId
|
if(ret) {
|
||||||
})
|
let res=await apiIssue.copy({
|
||||||
if(res?.code==0) {
|
projectIssueId:props.projectIssueId,
|
||||||
releaseList.value=res.data
|
name:ret
|
||||||
}
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
eventBus.emit(EClient_EVENTBUS_TYPE.OPEN_PROJECT_ISSUE_PROFILE,projectId,res.data.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCreateSubIssue=async ()=>{
|
||||||
|
let ret=await Dialog.input(root.value,appContext,"type the issue's name")
|
||||||
|
if(ret) {
|
||||||
|
let res=await apiIssue.createChildIssue({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
name:ret
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
getOtherInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showQuickMeeting=async ()=>{
|
const showQuickMeeting=async ()=>{
|
||||||
@ -548,30 +398,48 @@ const showQuickMeeting=async ()=>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getFieldList=async ()=>{
|
||||||
|
let res=await apiIssue.fieldsInfo({
|
||||||
|
projectIssueId:props.projectIssueId
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
fieldList.value=res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculateApprovalName=computed(()=>{
|
||||||
|
if(info.value) {
|
||||||
|
if(info.value.approval) {
|
||||||
|
if(info.value.approval.type===ECommon_Model_Project_Issue_Approval_Type.PENDING) {
|
||||||
|
return `${info.value.approval.workflowNode.name}(Wait For Approval)`
|
||||||
|
} else if(info.value.approval.type===ECommon_Model_Project_Issue_Approval_Type.RESOLVED) {
|
||||||
|
return info.value.workflowNode.name
|
||||||
|
} else if(info.value.approval.type===ECommon_Model_Project_Issue_Approval_Type.REJECTED) {
|
||||||
|
return `${info.value.approval.workflowNode.name}(Rejected)`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return info.value.workflowNode.name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const onCustomAnchorClick=(type:ECommon_Content_Line_Config_Type,value:string,link:string,label:string)=>{
|
||||||
|
RichEditorEventHandle.onCustomAnchorClick(type,value,link,label)
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeMount(()=>{
|
onBeforeMount(()=>{
|
||||||
getInfo()
|
getInfo()
|
||||||
getDescription()
|
getDescription()
|
||||||
getOtherInfo()
|
getOtherInfo()
|
||||||
getFieldList()
|
|
||||||
getCommentList()
|
|
||||||
getActionList()
|
getActionList()
|
||||||
getReleaseList()
|
getFieldList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
#issueProfileDetail :deep(div[role="region"]) {
|
.issueProfileContent :deep .arco-comment-actions {
|
||||||
background-color: white !important;
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
#issueProfileDetail :deep .arco-form-item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
#issueProfileDetail :deep .arco-form-item-label {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
#issueProfileContent :deep .arco-comment-actions {
|
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -0,0 +1,131 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="parentIssue">
|
||||||
|
<a-row style="margin-top: 20px;font-weight: bold">Parent Issue</a-row>
|
||||||
|
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
|
||||||
|
<a-list-item>
|
||||||
|
<a-space size="large">
|
||||||
|
{{key+"-"+parentIssue.unique_id}}
|
||||||
|
<a-link href="javascript:void(0)" @click="onOpenIssue(parentIssue.id)">{{parentIssue.name}}</a-link>
|
||||||
|
<FieldPriority :priority="parentIssue.priority"></FieldPriority>
|
||||||
|
</a-space>
|
||||||
|
<template #actions>
|
||||||
|
<a-button type="text" size="mini" @click="onRemoveItem('parent',null)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</template>
|
||||||
|
<template v-if="childIssueList.length>0">
|
||||||
|
<a-row style="margin-top: 20px;font-weight: bold">Child Issues</a-row>
|
||||||
|
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
|
||||||
|
<a-list-item v-for="(item,index) in childIssueList" :key="item.id">
|
||||||
|
<a-space size="large">
|
||||||
|
{{key+"-"+item.unique_id}}
|
||||||
|
<a-link href="javascript:void(0)" @click="onOpenIssue(item.id)">{{item.name}}</a-link>
|
||||||
|
<FieldPriority :priority="item.priority"></FieldPriority>
|
||||||
|
</a-space>
|
||||||
|
<template #actions>
|
||||||
|
<a-button type="text" size="mini" @click="onRemoveItem('child',index)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</template>
|
||||||
|
<template v-if="relatedIssueList.length>0">
|
||||||
|
<a-row style="margin-top: 20px;font-weight: bold">Related Issues</a-row>
|
||||||
|
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
|
||||||
|
<a-list-item v-for="(item,index) in relatedIssueList" :key="item.id">
|
||||||
|
<a-space size="large">
|
||||||
|
{{key+"-"+item.unique_id}}
|
||||||
|
<a-link href="javascript:void(0)" @click="onOpenIssue(item.id)">{{item.name}}</a-link>
|
||||||
|
<FieldPriority :priority="item.priority"></FieldPriority>
|
||||||
|
</a-space>
|
||||||
|
<template #actions>
|
||||||
|
<a-button type="text" size="mini" @click="onRemoveItem('related',index)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-close style="color: red"></icon-close>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import FieldPriority from "../../../../common/component/field/fieldPriority.vue";
|
||||||
|
import {apiIssue, DCSType} from "../../../../common/request/request";
|
||||||
|
import {ICommon_Model_Project_Issue} from "../../../../../../../common/model/project_issue";
|
||||||
|
import {getCurrentInstance, inject} from "vue";
|
||||||
|
import {injectProjectInfo} from "../../../../common/util/symbol";
|
||||||
|
import {Dialog} from "../../../../common/component/dialog/dialog";
|
||||||
|
import {getRootNavigatorRef} from "../../../../../teamOS/common/component/navigator/navigator";
|
||||||
|
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
|
||||||
|
|
||||||
|
const props=defineProps<{
|
||||||
|
parentIssue?:DCSType<ICommon_Model_Project_Issue>,
|
||||||
|
childIssueList?:DCSType<ICommon_Model_Project_Issue>[],
|
||||||
|
relatedIssueList?:DCSType<ICommon_Model_Project_Issue>[]
|
||||||
|
projectIssueId:string
|
||||||
|
}>()
|
||||||
|
const emit=defineEmits<{
|
||||||
|
removeParent:[]
|
||||||
|
}>()
|
||||||
|
const key=inject(injectProjectInfo).key
|
||||||
|
const projectId=inject(injectProjectInfo).id
|
||||||
|
const root=getRootNavigatorRef()
|
||||||
|
const appContext=getCurrentInstance().appContext
|
||||||
|
const onRemoveItem=async (type:"parent"|"child"|"related",index:number)=>{
|
||||||
|
if(type==="parent") {
|
||||||
|
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove parent issue?")
|
||||||
|
if(ret) {
|
||||||
|
let res=await apiIssue.removeParentIssue({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
projectIssueParentId:props.parentIssue.id
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
emit("removeParent")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(type=="child") {
|
||||||
|
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove child issue?")
|
||||||
|
if(ret) {
|
||||||
|
let res=await apiIssue.removeChildIssue({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
projectIssueChildId:props.childIssueList[index].id
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
props.childIssueList.splice(index,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(type=="related") {
|
||||||
|
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove related issue?")
|
||||||
|
if(ret) {
|
||||||
|
let res=await apiIssue.removeRelatedIssue({
|
||||||
|
projectIssueId:props.projectIssueId,
|
||||||
|
projectIssueRelatedId:props.relatedIssueList[index].id
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
props.relatedIssueList.splice(index,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onOpenIssue=(projectIssueId:string)=>{
|
||||||
|
eventBus.emit(EClient_EVENTBUS_TYPE.OPEN_PROJECT_ISSUE_PROFILE,projectId,projectIssueId)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -2,7 +2,6 @@
|
|||||||
<a-form style="width: 80%" :model="form" ref="eleForm">
|
<a-form style="width: 80%" :model="form" ref="eleForm">
|
||||||
<a-form-item field="status" label="type" required>
|
<a-form-item field="status" label="type" required>
|
||||||
<a-select v-model="form.status">
|
<a-select v-model="form.status">
|
||||||
<a-option :value="ECommon_Model_Workflow_Node_Status.NOTSTART">NOTSTART</a-option>
|
|
||||||
<a-option :value="ECommon_Model_Workflow_Node_Status.INPROGRESS">INPROGRESS</a-option>
|
<a-option :value="ECommon_Model_Workflow_Node_Status.INPROGRESS">INPROGRESS</a-option>
|
||||||
<a-option :value="ECommon_Model_Workflow_Node_Status.DONE">DONE</a-option>
|
<a-option :value="ECommon_Model_Workflow_Node_Status.DONE">DONE</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
|
@ -107,7 +107,7 @@ import {ICommon_Route_Res_Workflow_Node_Field} from "../../../../../../../common
|
|||||||
import {Message} from "@arco-design/web-vue";
|
import {Message} from "@arco-design/web-vue";
|
||||||
import {ECommon_Field_Type, Field_Types} from "../../../../../../../common/field/type";
|
import {ECommon_Field_Type, Field_Types} from "../../../../../../../common/field/type";
|
||||||
import {
|
import {
|
||||||
ECommon_Model_Workflow_Node_Field_Type_Label_Type
|
ECommon_Model_Workflow_Node_Field_Type_Label_Type
|
||||||
} from "../../../../../../../common/model/workflow_node_field_type";
|
} from "../../../../../../../common/model/workflow_node_field_type";
|
||||||
import AddField from "./addField.vue";
|
import AddField from "./addField.vue";
|
||||||
import {Dialog} from "../../../../common/component/dialog/dialog";
|
import {Dialog} from "../../../../common/component/dialog/dialog";
|
||||||
@ -146,6 +146,7 @@ const form=reactive({
|
|||||||
default_number_value:0,
|
default_number_value:0,
|
||||||
label_type:0,
|
label_type:0,
|
||||||
values:[] as {
|
values:[] as {
|
||||||
|
id?:string
|
||||||
value:string,
|
value:string,
|
||||||
selected:number
|
selected:number
|
||||||
}[]
|
}[]
|
||||||
@ -244,6 +245,7 @@ const onClickRow=async (item:ICommon_Route_Res_Workflow_Node_Field)=>{
|
|||||||
form.values=[]
|
form.values=[]
|
||||||
for(let obj of item.values) {
|
for(let obj of item.values) {
|
||||||
form.values.push({
|
form.values.push({
|
||||||
|
id:obj.id,
|
||||||
value:obj.value,
|
value:obj.value,
|
||||||
selected:obj.selected
|
selected:obj.selected
|
||||||
})
|
})
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
</a-space>
|
</a-space>
|
||||||
<a-layout style="flex:1 1 auto;border: 1px solid gainsboro">
|
<a-layout style="flex:1 1 auto;border: 1px solid gainsboro">
|
||||||
<a-layout-content style="overflow:hidden;">
|
<a-layout-content style="overflow:hidden;">
|
||||||
<div ref="eleWorkflow" style="height: 100%;width: 100%" tabindex="1" @keydown.delete="onKeyDelete"></div>
|
<div ref="eleWorkflow" style="height: 100%;width: 100%" tabindex="-1" @keydown.delete="onKeyDelete"></div>
|
||||||
</a-layout-content>
|
</a-layout-content>
|
||||||
<a-layout-sider :resize-directions="['left']">
|
<a-layout-sider :resize-directions="['left']">
|
||||||
<a-form :model="form" layout="vertical" style="margin:10px 5px 0px 5px;width: 90%" v-if="form.type" @submitSuccess="onSubmit">
|
<a-form :model="form" layout="vertical" style="margin:10px 5px 0px 5px;width: 90%" v-if="form.type" @submitSuccess="onSubmit">
|
||||||
<h3>{{form.type}}</h3>
|
<h3>{{form.type}}</h3>
|
||||||
<a-form-item field="status" label="status" v-if="form.type=='node'" required>
|
<a-form-item field="status" label="status" v-if="form.type=='node' || form.type=='approval'" required>
|
||||||
<a-select v-model="form.status">
|
<a-select v-model="form.status">
|
||||||
<a-option :value="ECommon_Model_Workflow_Node_Status.NOTSTART">NOTSTART</a-option>
|
<a-option :value="ECommon_Model_Workflow_Node_Status.NOTSTART">NOTSTART</a-option>
|
||||||
<a-option :value="ECommon_Model_Workflow_Node_Status.INPROGRESS">INPROGRESS</a-option>
|
<a-option :value="ECommon_Model_Workflow_Node_Status.INPROGRESS">INPROGRESS</a-option>
|
||||||
@ -23,8 +23,27 @@
|
|||||||
<a-form-item field="description" label="description">
|
<a-form-item field="description" label="description">
|
||||||
<a-textarea v-model="form.description"></a-textarea>
|
<a-textarea v-model="form.description"></a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<template v-if="form.status===ECommon_Model_Workflow_Node_Status.INPROGRESS || form.status===ECommon_Model_Workflow_Node_Status.DONE">
|
||||||
|
<a-form-item field="approval" label="approval">
|
||||||
|
<a-switch :checked-value="1" :unchecked-value="0" v-model="form.approval"></a-switch>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="approvalType" label="approval type" v-if="form.approval">
|
||||||
|
<a-select v-model="form.approvalType" @change="onApprovalTypeChange">
|
||||||
|
<a-option :value="ECommon_Model_Workflow_Approval_Type.PERSON">Person</a-option>
|
||||||
|
<a-option :value="ECommon_Model_Workflow_Approval_Type.TEAM">Team</a-option>
|
||||||
|
<a-option :value="ECommon_Model_Workflow_Approval_Type.FIELD">Field</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="approvalValue" :label="form.approvalType===ECommon_Model_Workflow_Approval_Type.PERSON?'choose person':form.approvalType===ECommon_Model_Workflow_Approval_Type.TEAM?'choose team':'choose workflow field'" v-if="form.approval">
|
||||||
|
<FieldCommonMultiLabel style="width: 100%" v-model="form.approvalValue" :type="form.approvalType===ECommon_Model_Workflow_Approval_Type.PERSON?'user':'team'" v-if="form.approvalType===ECommon_Model_Workflow_Approval_Type.PERSON || form.approvalType===ECommon_Model_Workflow_Approval_Type.TEAM"></FieldCommonMultiLabel>
|
||||||
|
<FieldCommonLabel style="width: 100%" v-model="form.approvalValue" type="field" :workflow-node-id="form.id" v-else-if="form.approvalType===ECommon_Model_Workflow_Approval_Type.FIELD"></FieldCommonLabel>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item field="approvalExtra" label="choose member tag" v-if="form.approval && form.approvalType===ECommon_Model_Workflow_Approval_Type.TEAM">
|
||||||
|
<FieldCommonLabel style="width: 100%" v-model="form.approvalExtra" type="tag"></FieldCommonLabel>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-space v-if="form.type=='node'" size="medium">
|
<a-space v-if="form.type=='node' || form.type=='approval'" size="medium">
|
||||||
<a-button html-type="submit" type="primary">Save</a-button>
|
<a-button html-type="submit" type="primary">Save</a-button>
|
||||||
<a-button html-type="button" type="primary" @click="onEditFields">Edit Fields</a-button>
|
<a-button html-type="button" type="primary" @click="onEditFields">Edit Fields</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
@ -37,7 +56,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {getCurrentInstance, markRaw, onBeforeMount, onMounted, reactive, ref} from "vue";
|
import {getCurrentInstance, markRaw, nextTick, onBeforeMount, onMounted, reactive, ref} from "vue";
|
||||||
import LogicFlow from "@logicflow/core";
|
import LogicFlow from "@logicflow/core";
|
||||||
import {apiWorkflow} from "../../../../common/request/request";
|
import {apiWorkflow} from "../../../../common/request/request";
|
||||||
import {Dialog} from "../../../../common/component/dialog/dialog";
|
import {Dialog} from "../../../../common/component/dialog/dialog";
|
||||||
@ -47,11 +66,15 @@ import {ECommon_Model_Workflow_Node_Status} from "../../../../../../../common/mo
|
|||||||
import {Message} from "@arco-design/web-vue";
|
import {Message} from "@arco-design/web-vue";
|
||||||
import {getCurrentNavigator} from "../../../../../teamOS/common/component/navigator/navigator";
|
import {getCurrentNavigator} from "../../../../../teamOS/common/component/navigator/navigator";
|
||||||
import FieldList from "./fieldList.vue";
|
import FieldList from "./fieldList.vue";
|
||||||
|
import {flowApproval} from "@/business/common/component/flow/approval";
|
||||||
|
import {ECommon_Model_Workflow_Approval_Type} from "../../../../../../../common/model/workflow_approval";
|
||||||
|
import FieldCommonMultiLabel from "@/business/common/component/field/common/fieldCommonMultiLabel.vue";
|
||||||
|
import FieldCommonLabel from "@/business/common/component/field/common/fieldCommonLabel.vue";
|
||||||
|
|
||||||
const props=defineProps<{
|
const props=defineProps<{
|
||||||
issueTypeId:string
|
issueTypeId:string
|
||||||
}>()
|
}>()
|
||||||
const eleWorkflow=ref(null);
|
const eleWorkflow=ref<HTMLElement>(null);
|
||||||
const root=ref(null)
|
const root=ref(null)
|
||||||
const appContext=getCurrentInstance().appContext
|
const appContext=getCurrentInstance().appContext
|
||||||
const navigator=getCurrentNavigator();
|
const navigator=getCurrentNavigator();
|
||||||
@ -60,8 +83,12 @@ const form=reactive({
|
|||||||
id:"",
|
id:"",
|
||||||
name:"",
|
name:"",
|
||||||
description:"",
|
description:"",
|
||||||
type:"",
|
type:"" ,
|
||||||
status:ECommon_Model_Workflow_Node_Status.INPROGRESS
|
status:ECommon_Model_Workflow_Node_Status.INPROGRESS,
|
||||||
|
approval:0,
|
||||||
|
approvalType:ECommon_Model_Workflow_Approval_Type.PERSON,
|
||||||
|
approvalValue:[] as string[]|string,
|
||||||
|
approvalExtra:""
|
||||||
})
|
})
|
||||||
let lf:LogicFlow
|
let lf:LogicFlow
|
||||||
const onKeyDelete=async (event:KeyboardEvent)=>{
|
const onKeyDelete=async (event:KeyboardEvent)=>{
|
||||||
@ -75,6 +102,10 @@ const onKeyDelete=async (event:KeyboardEvent)=>{
|
|||||||
type="node"
|
type="node"
|
||||||
name=(<any>elements.nodes[0].text).value;
|
name=(<any>elements.nodes[0].text).value;
|
||||||
id=elements.nodes[0].id
|
id=elements.nodes[0].id
|
||||||
|
if(elements.nodes[0].properties.status===ECommon_Model_Workflow_Node_Status.NOTSTART) {
|
||||||
|
Message.error("not start node can't be removed !!!")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(type) {
|
if(type) {
|
||||||
let ret=await Dialog.confirm(root.value,appContext,`Do you want to delete ${type} ${name}`)
|
let ret=await Dialog.confirm(root.value,appContext,`Do you want to delete ${type} ${name}`)
|
||||||
@ -89,11 +120,17 @@ const onKeyDelete=async (event:KeyboardEvent)=>{
|
|||||||
|
|
||||||
}
|
}
|
||||||
const onSubmit=async ()=>{
|
const onSubmit=async ()=>{
|
||||||
let res=await (form.type=="node"?apiWorkflow.editNode({
|
let res=await ((form.type=="node" || form.type=="approval")?apiWorkflow.editNode({
|
||||||
workflowNodeId:form.id,
|
workflowNodeId:form.id,
|
||||||
name:form.name,
|
name:form.name,
|
||||||
description:form.description,
|
description:form.description,
|
||||||
status:form.status
|
status:form.status,
|
||||||
|
approval:form.approval,
|
||||||
|
...(form.approval && {
|
||||||
|
approvalType:form.approvalType,
|
||||||
|
approvalValue:Array.isArray(form.approvalValue)?form.approvalValue:form.approvalValue?[form.approvalValue]:[],
|
||||||
|
approvalExtra:form.approvalExtra
|
||||||
|
})
|
||||||
}):apiWorkflow.editAction({
|
}):apiWorkflow.editAction({
|
||||||
workflowActionId:form.id,
|
workflowActionId:form.id,
|
||||||
name:form.name,
|
name:form.name,
|
||||||
@ -101,12 +138,10 @@ const onSubmit=async ()=>{
|
|||||||
}))
|
}))
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
Message.success("update success")
|
Message.success("update success")
|
||||||
if(form.type=="node") {
|
if(form.type=="node" || form.type=="approval") {
|
||||||
let obj=lf.getNodeModelById(form.id)
|
let obj=lf.getNodeModelById(form.id)
|
||||||
obj.updateText(form.name)
|
obj.updateText(form.name)
|
||||||
obj.setProperty("name",form.name)
|
obj.setProperties(res.data)
|
||||||
obj.setProperty("description",form.description)
|
|
||||||
obj.setProperty("status",form.status)
|
|
||||||
} else {
|
} else {
|
||||||
let obj=lf.getEdgeModelById(form.id)
|
let obj=lf.getEdgeModelById(form.id)
|
||||||
obj.updateText(form.name)
|
obj.updateText(form.name)
|
||||||
@ -122,6 +157,17 @@ const onEditFields=()=>{
|
|||||||
workflowNodeId:form.id
|
workflowNodeId:form.id
|
||||||
},`${form.name} -> Fields`)
|
},`${form.name} -> Fields`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onApprovalTypeChange=()=> {
|
||||||
|
if(form.approvalType===ECommon_Model_Workflow_Approval_Type.PERSON || form.approvalType===ECommon_Model_Workflow_Approval_Type.TEAM) {
|
||||||
|
form.approvalValue=[];
|
||||||
|
form.approvalExtra=''
|
||||||
|
} else if(form.approvalType===ECommon_Model_Workflow_Approval_Type.FIELD) {
|
||||||
|
form.approvalValue="";
|
||||||
|
form.approvalExtra=''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const requestNodes=async ()=>{
|
const requestNodes=async ()=>{
|
||||||
let res=await apiWorkflow.info({
|
let res=await apiWorkflow.info({
|
||||||
issueTypeId:props.issueTypeId
|
issueTypeId:props.issueTypeId
|
||||||
@ -131,7 +177,7 @@ const requestNodes=async ()=>{
|
|||||||
nodes:res.data.nodes.map(item=>{
|
nodes:res.data.nodes.map(item=>{
|
||||||
return {
|
return {
|
||||||
id:item.id,
|
id:item.id,
|
||||||
type:"node",
|
type:item.is_approval?"approval":"node",
|
||||||
x:item.x,
|
x:item.x,
|
||||||
y:item.y,
|
y:item.y,
|
||||||
text:item.name,
|
text:item.name,
|
||||||
@ -145,7 +191,13 @@ const requestNodes=async ()=>{
|
|||||||
sourceNodeId: item.source_node_id,
|
sourceNodeId: item.source_node_id,
|
||||||
targetNodeId: item.dest_node_id,
|
targetNodeId: item.dest_node_id,
|
||||||
text: item.name,
|
text: item.name,
|
||||||
properties: item
|
properties: item,
|
||||||
|
...(item.source_anchor_point && {
|
||||||
|
startPoint:JSON.parse(item.source_anchor_point)
|
||||||
|
}),
|
||||||
|
...(item.end_anchor_point && {
|
||||||
|
endPoint:JSON.parse(item.end_anchor_point)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -156,14 +208,17 @@ const addNode=async ()=>{
|
|||||||
issueTypeId:props.issueTypeId
|
issueTypeId:props.issueTypeId
|
||||||
})
|
})
|
||||||
if(ret) {
|
if(ret) {
|
||||||
lf.dnd.startDrag({
|
lf.addNode({
|
||||||
id:ret.id,
|
id:ret.data.id,
|
||||||
type:"node",
|
type:"node",
|
||||||
text:ret.name,
|
text:ret.data.name,
|
||||||
properties:ret
|
x:(-lf.graphModel.transformModel.TRANSLATE_X+lf.graphModel.width/2-100),
|
||||||
})
|
y:(-lf.graphModel.transformModel.TRANSLATE_Y+20)*lf.graphModel.transformModel.SCALE_Y,
|
||||||
|
properties:ret.data
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestNodesPromise;
|
let requestNodesPromise;
|
||||||
onBeforeMount(()=>{
|
onBeforeMount(()=>{
|
||||||
requestNodesPromise=requestNodes();
|
requestNodesPromise=requestNodes();
|
||||||
@ -178,6 +233,7 @@ onMounted(async ()=>{
|
|||||||
adjustEdgeStartAndEnd:false,
|
adjustEdgeStartAndEnd:false,
|
||||||
})
|
})
|
||||||
lf.register(flowNode)
|
lf.register(flowNode)
|
||||||
|
lf.register(flowApproval)
|
||||||
lf.setTheme({
|
lf.setTheme({
|
||||||
baseEdge:{
|
baseEdge:{
|
||||||
strokeWidth:1.2,
|
strokeWidth:1.2,
|
||||||
@ -192,24 +248,46 @@ onMounted(async ()=>{
|
|||||||
x:data.x,
|
x:data.x,
|
||||||
y:data.y
|
y:data.y
|
||||||
})
|
})
|
||||||
|
let outgoingEdges=lf.getNodeOutgoingEdge(data.properties.id)
|
||||||
|
outgoingEdges.forEach(item=>{
|
||||||
|
apiWorkflow.editAction({
|
||||||
|
workflowActionId:item.id,
|
||||||
|
sourceAnchorPoint:JSON.stringify(item.startPoint)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let incomingEdges=lf.getNodeIncomingEdge(data.properties.id)
|
||||||
|
incomingEdges.forEach(item=>{
|
||||||
|
apiWorkflow.editAction({
|
||||||
|
workflowActionId:item.id,
|
||||||
|
endAnchorPoint:JSON.stringify(item.endPoint)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
lf.on("edge:add",async ({data})=>{
|
lf.on("edge:add",async ({data})=>{
|
||||||
let res=await apiWorkflow.addAction({
|
let res=await apiWorkflow.addAction({
|
||||||
issueTypeId:props.issueTypeId,
|
issueTypeId:props.issueTypeId,
|
||||||
name:"empty",
|
name:"empty",
|
||||||
sourceNodeId:data.sourceNodeId,
|
sourceNodeId:data.sourceNodeId,
|
||||||
destNodeId:data.targetNodeId
|
destNodeId:data.targetNodeId,
|
||||||
|
sourceAnchorPoint:JSON.stringify(data.startPoint),
|
||||||
|
endAnchorPoint:JSON.stringify(data.endPoint)
|
||||||
})
|
})
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
let obj=lf.getEdgeModelById(data.id)
|
let obj=lf.getEdgeModelById(data.id)
|
||||||
obj.id=res.data.id
|
obj.id=res.data.id
|
||||||
obj.updateText("empty");
|
obj.updateText("empty");
|
||||||
obj.setProperties(res.data)
|
obj.setProperties(res.data)
|
||||||
|
lf.openEdgeAnimation(obj.id)
|
||||||
|
} else {
|
||||||
|
Message.error(res.msg)
|
||||||
|
lf.deleteEdge(data.id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
lf.on("edge:delete",async ({data})=>{
|
lf.on("edge:delete",async ({data})=>{
|
||||||
if(data.properties.id==form.id) {
|
if(data.properties.id==form.id) {
|
||||||
form.type=""
|
form.type=""
|
||||||
|
} else if(!data.properties.id) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
apiWorkflow.deleteAction({
|
apiWorkflow.deleteAction({
|
||||||
workflowActionId:data.properties.id
|
workflowActionId:data.properties.id
|
||||||
@ -219,23 +297,74 @@ onMounted(async ()=>{
|
|||||||
if(data.properties.id==form.id) {
|
if(data.properties.id==form.id) {
|
||||||
form.type=""
|
form.type=""
|
||||||
}
|
}
|
||||||
apiWorkflow.deleteNode({
|
apiWorkflow.deleteNode({
|
||||||
workflowNodeId:data.properties.id
|
workflowNodeId:data.properties.id
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
lf.on("node:click,edge:click",({data})=>{
|
lf.on("node:click,edge:click",({data})=>{
|
||||||
form.id=data.properties.id
|
form.id=data.properties.id
|
||||||
form.type=data.type=="node"?"node":"transition"
|
form.type=data.type=="node"?"node":data.type==='approval'?"approval":"transition"
|
||||||
form.name=data.properties.name
|
form.name=data.properties.name
|
||||||
form.description=data.properties.description
|
form.description=data.properties.description
|
||||||
if(data.type=="node") {
|
if(data.type=="node" || data.type=="approval") {
|
||||||
form.status=data.properties.status
|
form.status=data.properties.status
|
||||||
|
form.approval=data.properties.is_approval
|
||||||
|
if(form.approval) {
|
||||||
|
form.approvalType=data.properties.approval.type
|
||||||
|
if(form.approvalType===ECommon_Model_Workflow_Approval_Type.TEAM || form.approvalType===ECommon_Model_Workflow_Approval_Type.PERSON) {
|
||||||
|
form.approvalValue=data.properties.approval.value
|
||||||
|
if(form.approvalType===ECommon_Model_Workflow_Approval_Type.TEAM) {
|
||||||
|
form.approvalExtra=data.properties.approval.extra
|
||||||
|
}
|
||||||
|
} else if(form.approvalType===ECommon_Model_Workflow_Approval_Type.FIELD) {
|
||||||
|
form.approvalValue=data.properties.approval.value.length>0?data.properties.approval.value[0]:""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
form.approvalType=ECommon_Model_Workflow_Approval_Type.PERSON
|
||||||
|
form.approvalValue=[]
|
||||||
|
form.approvalExtra=""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
lf.on("blank:click",({date})=>{
|
lf.on("blank:click",({date})=>{
|
||||||
form.type=""
|
nextTick(()=>{
|
||||||
|
form.type=""
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
lf.on("text:update",async (param)=>{
|
||||||
|
if(form.type=="node" || form.type=="approval") {
|
||||||
|
let obj=lf.getNodeModelById(form.id)
|
||||||
|
let res=await apiWorkflow.editNode({
|
||||||
|
workflowNodeId:form.id,
|
||||||
|
name:obj.text.value
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
obj.setProperty("name",obj.text.value)
|
||||||
|
form.name=obj.text.value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let obj=lf.getEdgeModelById(form.id)
|
||||||
|
let res=await apiWorkflow.editAction({
|
||||||
|
workflowActionId:form.id,
|
||||||
|
name:obj.text.value
|
||||||
|
})
|
||||||
|
if(res?.code==0) {
|
||||||
|
obj.setProperty("name",obj.text.value)
|
||||||
|
form.name=obj.text.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
lf.on("edge:adjust",({data})=>{
|
||||||
|
apiWorkflow.editAction({
|
||||||
|
workflowActionId:data.properties.id,
|
||||||
|
sourceAnchorPoint:JSON.stringify(data.startPoint),
|
||||||
|
endAnchorPoint:JSON.stringify(data.endPoint)
|
||||||
|
})
|
||||||
|
})
|
||||||
lf.render(ret)
|
lf.render(ret)
|
||||||
|
for(let edge of ret.edges) {
|
||||||
|
lf.openEdgeAnimation(edge.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -80,7 +80,7 @@ const onSearch=async (value:string)=>{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if(form.type==ECommon_Model_Organization_Member_Type.MEMBERTAG) {
|
} else if(form.type==ECommon_Model_Organization_Member_Type.MEMBERTAG) {
|
||||||
let res=await apiOrganization.listTag()
|
let res=await apiOrganization.listTag({})
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
userList.value=res.data.map(item=>{
|
userList.value=res.data.map(item=>{
|
||||||
return {
|
return {
|
||||||
|
@ -43,7 +43,6 @@ import EditProjectProfile from "./editProjectProfile.vue";
|
|||||||
import EditProjectAccess from "./editProjectAccess.vue";
|
import EditProjectAccess from "./editProjectAccess.vue";
|
||||||
import LabelList from "./labelList.vue";
|
import LabelList from "./labelList.vue";
|
||||||
import ModuleList from "./moduleList.vue";
|
import ModuleList from "./moduleList.vue";
|
||||||
import {SessionStorage} from "../../../../common/storage/session";
|
|
||||||
|
|
||||||
const columns=[
|
const columns=[
|
||||||
{
|
{
|
||||||
@ -78,7 +77,6 @@ navigator.register("labelList",markRaw(LabelList));
|
|||||||
navigator.register("moduleList",markRaw(ModuleList));
|
navigator.register("moduleList",markRaw(ModuleList));
|
||||||
const search=async (page:number)=>{
|
const search=async (page:number)=>{
|
||||||
let res=await apiProject.list({
|
let res=await apiProject.list({
|
||||||
organizationUserId:SessionStorage.get("organizationId"),
|
|
||||||
size:pagination.pageSize,
|
size:pagination.pageSize,
|
||||||
page:page-1,
|
page:page-1,
|
||||||
keyword:keyword.value
|
keyword:keyword.value
|
||||||
|
@ -25,7 +25,7 @@ const tagList=ref<{
|
|||||||
checked:boolean
|
checked:boolean
|
||||||
}[]>([])
|
}[]>([])
|
||||||
onBeforeMount(async ()=>{
|
onBeforeMount(async ()=>{
|
||||||
let res=await apiOrganization.listTag();
|
let res=await apiOrganization.listTag({});
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
let userTagIds=props.tags.map(item=>item.id);
|
let userTagIds=props.tags.map(item=>item.id);
|
||||||
tagList.value=res.data.map(item=>{
|
tagList.value=res.data.map(item=>{
|
||||||
|
@ -40,7 +40,7 @@ const data=ref<ICommon_Model_Member_Tag[]>([])
|
|||||||
const root=ref(null);
|
const root=ref(null);
|
||||||
const appContext=getCurrentInstance().appContext
|
const appContext=getCurrentInstance().appContext
|
||||||
const search=async ()=>{
|
const search=async ()=>{
|
||||||
let ret=await apiOrganization.listTag()
|
let ret=await apiOrganization.listTag({})
|
||||||
if(ret?.code==0) {
|
if(ret?.code==0) {
|
||||||
data.value=ret.data
|
data.value=ret.data
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ const onSearch=async (value:string)=>{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if(form.type==ECommon_Model_Organization_Member_Type.MEMBERTAG) {
|
} else if(form.type==ECommon_Model_Organization_Member_Type.MEMBERTAG) {
|
||||||
let res=await apiOrganization.listTag()
|
let res=await apiOrganization.listTag({})
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
userList.value=res.data.map(item=>{
|
userList.value=res.data.map(item=>{
|
||||||
return {
|
return {
|
||||||
|
@ -39,7 +39,6 @@ import {getCurrentNavigator} from "../../../../../teamOS/common/component/naviga
|
|||||||
import EditWikiProfile from "./editWikiProfile.vue";
|
import EditWikiProfile from "./editWikiProfile.vue";
|
||||||
import EditWikiAccess from "./editWikiAccess.vue";
|
import EditWikiAccess from "./editWikiAccess.vue";
|
||||||
import {ICommon_Model_Wiki} from "../../../../../../../common/model/wiki";
|
import {ICommon_Model_Wiki} from "../../../../../../../common/model/wiki";
|
||||||
import {SessionStorage} from "../../../../common/storage/session";
|
|
||||||
|
|
||||||
const columns=[
|
const columns=[
|
||||||
{
|
{
|
||||||
@ -72,7 +71,6 @@ const navigator=getCurrentNavigator();
|
|||||||
navigator.register("editWikiAccess",markRaw(EditWikiAccess));
|
navigator.register("editWikiAccess",markRaw(EditWikiAccess));
|
||||||
const search=async (page:number)=>{
|
const search=async (page:number)=>{
|
||||||
let res=await apiWiki.list({
|
let res=await apiWiki.list({
|
||||||
organizationUserId:SessionStorage.get("organizationId"),
|
|
||||||
size:pagination.pageSize,
|
size:pagination.pageSize,
|
||||||
page:page-1,
|
page:page-1,
|
||||||
keyword:keyword.value
|
keyword:keyword.value
|
||||||
|
@ -32,11 +32,11 @@
|
|||||||
import {onBeforeMount, onBeforeUnmount, ref} from "vue";
|
import {onBeforeMount, onBeforeUnmount, ref} from "vue";
|
||||||
import {apiNotification, DCSType} from "../../common/request/request";
|
import {apiNotification, DCSType} from "../../common/request/request";
|
||||||
import {ICommon_Route_Res_Notification_Item} from "../../../../../common/routes/response";
|
import {ICommon_Route_Res_Notification_Item} from "../../../../../common/routes/response";
|
||||||
import moment from "moment";
|
|
||||||
import NotificationItem from "../../common/component/notificationItem.vue";
|
import NotificationItem from "../../common/component/notificationItem.vue";
|
||||||
import {ECommon_Model_Notification_Type} from "../../../../../common/model/notification";
|
import {ECommon_Model_Notification_Type} from "../../../../../common/model/notification";
|
||||||
import {EClient_EVENTBUS_TYPE, eventBus} from "../../common/event/event";
|
import {EClient_EVENTBUS_TYPE, eventBus} from "../../common/event/event";
|
||||||
import {type} from "os";
|
import {type} from "os";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
let page=0
|
let page=0
|
||||||
const bottom=ref(false)
|
const bottom=ref(false)
|
||||||
@ -51,6 +51,13 @@ const getList=async ()=>{
|
|||||||
types:types.value
|
types:types.value
|
||||||
})
|
})
|
||||||
if(res?.code==0) {
|
if(res?.code==0) {
|
||||||
|
for(let i=0;i<res.data.length;i++) {
|
||||||
|
let obj=res.data[i]
|
||||||
|
if(!obj.data) {
|
||||||
|
res.data.splice(i,1)
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
}
|
||||||
list.value.push(...res.data)
|
list.value.push(...res.data)
|
||||||
if(res.data.length==0) {
|
if(res.data.length==0) {
|
||||||
bottom.value=true
|
bottom.value=true
|
||||||
@ -101,7 +108,7 @@ const onChange=(value:string)=>{
|
|||||||
} else if(value==="organization") {
|
} else if(value==="organization") {
|
||||||
types.value=[ECommon_Model_Notification_Type.ORGANIZATION_USER_QUIT,ECommon_Model_Notification_Type.ORGANIZATION_INVITATION,ECommon_Model_Notification_Type.ORGANIZATION_USER_REMOVE,ECommon_Model_Notification_Type.ORGANIZATION_USER_ROLE_CHANGE]
|
types.value=[ECommon_Model_Notification_Type.ORGANIZATION_USER_QUIT,ECommon_Model_Notification_Type.ORGANIZATION_INVITATION,ECommon_Model_Notification_Type.ORGANIZATION_USER_REMOVE,ECommon_Model_Notification_Type.ORGANIZATION_USER_ROLE_CHANGE]
|
||||||
} else if(value==="issue") {
|
} else if(value==="issue") {
|
||||||
types.value=[ECommon_Model_Notification_Type.ISSUE_FIELD_CHANGE,ECommon_Model_Notification_Type.ISSUE_REMOVE,ECommon_Model_Notification_Type.ISSUE_ASSIGNER_ASSIGN,ECommon_Model_Notification_Type.ISSUE_WORKFLOW_CHANGE,ECommon_Model_Notification_Type.ISSUE_REPORTER_ASSIGN,ECommon_Model_Notification_Type.ISSUE_COMMENT_ADD,ECommon_Model_Notification_Type.ISSUE_COMMENT_AT]
|
types.value=[ECommon_Model_Notification_Type.ISSUE_FIELD_CHANGE,ECommon_Model_Notification_Type.ISSUE_REMOVE,ECommon_Model_Notification_Type.ISSUE_ASSIGNER_ASSIGN,ECommon_Model_Notification_Type.ISSUE_WORKFLOW_CHANGE,ECommon_Model_Notification_Type.ISSUE_REPORTER_ASSIGN,ECommon_Model_Notification_Type.ISSUE_COMMENT_ADD,ECommon_Model_Notification_Type.ISSUE_COMMENT_AT,ECommon_Model_Notification_Type.ISSUE_APPROVAL_REJECT,ECommon_Model_Notification_Type.ISSUE_APPROVAL_RESOLVE]
|
||||||
} else if(value==="team") {
|
} else if(value==="team") {
|
||||||
types.value=[ECommon_Model_Notification_Type.TEAM_USER_QUIT,ECommon_Model_Notification_Type.TEAM_USER_ROLE_CHANGE,ECommon_Model_Notification_Type.TEAM_USER_REMOVE,ECommon_Model_Notification_Type.TEAM_DISMISS,ECommon_Model_Notification_Type.TEAM_USER_ADD]
|
types.value=[ECommon_Model_Notification_Type.TEAM_USER_QUIT,ECommon_Model_Notification_Type.TEAM_USER_ROLE_CHANGE,ECommon_Model_Notification_Type.TEAM_USER_REMOVE,ECommon_Model_Notification_Type.TEAM_DISMISS,ECommon_Model_Notification_Type.TEAM_USER_ADD]
|
||||||
} else if(value==="calendar") {
|
} else if(value==="calendar") {
|
||||||
|
@ -95,6 +95,11 @@ export const useDesktopStore=defineStore("desktop",{
|
|||||||
if(!this.appList.includes(iconSetting)) {
|
if(!this.appList.includes(iconSetting)) {
|
||||||
this.appList.push(iconSetting)
|
this.appList.push(iconSetting)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let index=this.appList.indexOf(iconSetting)
|
||||||
|
if(index>-1) {
|
||||||
|
this.appList.splice(index,1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
@ -24,7 +24,7 @@ import {desktop} from "./desktop";
|
|||||||
import {windowManager} from "../window/windowManager";
|
import {windowManager} from "../window/windowManager";
|
||||||
import {ETeamOS_Window_Status} from "../window/window.js";
|
import {ETeamOS_Window_Status} from "../window/window.js";
|
||||||
import {iconGroupMap} from "../icon/icon";
|
import {iconGroupMap} from "../icon/icon";
|
||||||
import SvgIcon from "../../icon/custom/svgIcon.vue";
|
import SvgIcon from "../../icon/svgIcon.vue";
|
||||||
|
|
||||||
const list=windowManager.getList();
|
const list=windowManager.getList();
|
||||||
const color=desktop.getBaseColor();
|
const color=desktop.getBaseColor();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
|
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
|
||||||
<WindowContainer></WindowContainer>
|
<WindowContainer></WindowContainer>
|
||||||
</IconContainer>
|
</IconContainer>
|
||||||
<DesktopBar style="height: 40px;background-color: rgb(93,92,140)">
|
<DesktopBar style="height: 40px;background-color: rgb(93,92,140);">
|
||||||
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
|
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
|
||||||
</DesktopBar>
|
</DesktopBar>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
import {Icon} from "./icon"
|
import {Icon} from "./icon"
|
||||||
import {vMenu} from "../common/directive/menu";
|
import {vMenu} from "../common/directive/menu";
|
||||||
import {computed, nextTick, ref, watch} from "vue";
|
import {computed, nextTick, ref, watch} from "vue";
|
||||||
import SvgIcon from "../../icon/custom/svgIcon.vue";
|
import SvgIcon from "../../icon/svgIcon.vue";
|
||||||
|
|
||||||
const props=defineProps<{
|
const props=defineProps<{
|
||||||
item:Icon,
|
item:Icon,
|
||||||
|
@ -72,7 +72,7 @@ import {ETeamOS_Window_Status, ETeamOS_Window_Type, Window} from "./window";
|
|||||||
import {vDrag} from "../common/directive/drag";
|
import {vDrag} from "../common/directive/drag";
|
||||||
import {vResize} from "../common/directive/resize";
|
import {vResize} from "../common/directive/resize";
|
||||||
import {v4} from "uuid"
|
import {v4} from "uuid"
|
||||||
import SvgIcon from "../../icon/custom/svgIcon.vue";
|
import SvgIcon from "../../icon/svgIcon.vue";
|
||||||
import {iconGroupMap} from "../icon/icon";
|
import {iconGroupMap} from "../icon/icon";
|
||||||
|
|
||||||
vResize;
|
vResize;
|
||||||
|
@ -18,7 +18,7 @@ export class WindowManager extends Base{
|
|||||||
this.show(arr[0].id)
|
this.show(arr[0].id)
|
||||||
} else {
|
} else {
|
||||||
let focused=this.getFocused()
|
let focused=this.getFocused()
|
||||||
if(focused.group===window.group) {
|
if(focused?.group===window.group) {
|
||||||
focused.nodes.push(...window.nodes)
|
focused.nodes.push(...window.nodes)
|
||||||
focused.activeKey=window.nodes[0].id
|
focused.activeKey=window.nodes[0].id
|
||||||
this.show(focused.id)
|
this.show(focused.id)
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
"noImplicitThis": true,
|
"noImplicitThis": true,
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{ "transform": "../common/transform/transformer.js" }
|
{ "transform": "../common/transform/transformer.js" }
|
||||||
]
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
@ -6,13 +6,18 @@ import viteCompression from 'vite-plugin-compression'
|
|||||||
import {createSvgIconsPlugin} from "vite-plugin-svg-icons";
|
import {createSvgIconsPlugin} from "vite-plugin-svg-icons";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
resolve:{
|
||||||
|
alias:{
|
||||||
|
"@":path.join(__dirname,"src")
|
||||||
|
}
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
viteCompression({
|
viteCompression({
|
||||||
threshold:102400
|
threshold:102400
|
||||||
}),
|
}),
|
||||||
createSvgIconsPlugin({
|
createSvgIconsPlugin({
|
||||||
iconDirs:[path.join(__dirname,"./src/icon/custom")],
|
iconDirs:[path.join(__dirname,"./src/assert/custom")],
|
||||||
symbolId:'[name]'
|
symbolId:'[name]'
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
@ -43,7 +43,8 @@ export enum ECommon_Model_Content_Type {
|
|||||||
PROJECT_ISSUE_DESCRIPTION,
|
PROJECT_ISSUE_DESCRIPTION,
|
||||||
WIKI_ITEM,
|
WIKI_ITEM,
|
||||||
MEETING_CHAT,
|
MEETING_CHAT,
|
||||||
CALENDAR_EVENT_AGENDA
|
CALENDAR_EVENT_AGENDA,
|
||||||
|
PROJECT_ISSUE_REJECT
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICommon_Model_Content {
|
export interface ICommon_Model_Content {
|
||||||
|
@ -18,7 +18,9 @@ export enum ECommon_Model_Notification_Type {
|
|||||||
ISSUE_COMMENT_AT,
|
ISSUE_COMMENT_AT,
|
||||||
ISSUE_REMOVE,
|
ISSUE_REMOVE,
|
||||||
WIKI_ITEM_AT,
|
WIKI_ITEM_AT,
|
||||||
CALENDAR_EVENT_INVITATION
|
CALENDAR_EVENT_INVITATION,
|
||||||
|
ISSUE_APPROVAL_RESOLVE,
|
||||||
|
ISSUE_APPROVAL_REJECT
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ECommon_Model_Notification_Status {
|
export enum ECommon_Model_Notification_Status {
|
||||||
|
24
code/common/model/project_issue_approval.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {BaseModel} from "./base"
|
||||||
|
|
||||||
|
export enum ECommon_Model_Project_Issue_Approval_Type {
|
||||||
|
PENDING,
|
||||||
|
RESOLVED,
|
||||||
|
REJECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICommon_Model_Project_Issue_Approval {
|
||||||
|
id: string,
|
||||||
|
project_issue_id:string
|
||||||
|
workflow_node_id: string,
|
||||||
|
type:ECommon_Model_Project_Issue_Approval_Type,
|
||||||
|
approval_organization_user_id:string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Table_Project_Issue_Approval = "project_issue_approval"
|
||||||
|
|
||||||
|
class ProjectIssueApprovalModel extends BaseModel {
|
||||||
|
table = Table_Project_Issue_Approval
|
||||||
|
model = <ICommon_Model_Project_Issue_Approval>{}
|
||||||
|
}
|
||||||
|
|
||||||
|
export let projectIssueApprovalModel = new ProjectIssueApprovalModel
|
30
code/common/model/project_issue_history.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import {BaseModel} from "./base";
|
||||||
|
|
||||||
|
export enum ECommon_Model_Project_Issue_History_Type {
|
||||||
|
CREATE_ISSUE,
|
||||||
|
UPDATE_FIELD,
|
||||||
|
UPDATE_NODE,
|
||||||
|
APPROVAL_RESOLVE,
|
||||||
|
APPROVAL_REJECT,
|
||||||
|
ISSUE_TYPE_CONVERT
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICommon_Model_Project_Issue_History {
|
||||||
|
id: string,
|
||||||
|
created_time: Date,
|
||||||
|
type:ECommon_Model_Project_Issue_History_Type,
|
||||||
|
project_issue_id:string,
|
||||||
|
organization_user_id:string,
|
||||||
|
project_id:string,
|
||||||
|
name:string,
|
||||||
|
value:string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Table_Project_Issue_History = "project_issue_history"
|
||||||
|
|
||||||
|
class ProjectIssueHistoryModel extends BaseModel {
|
||||||
|
table = Table_Project_Issue_History
|
||||||
|
model = <ICommon_Model_Project_Issue_History>{}
|
||||||
|
}
|
||||||
|
|
||||||
|
export let projectIssueHistoryModel = new ProjectIssueHistoryModel
|
@ -7,6 +7,8 @@ export interface ICommon_Model_Workflow_Action {
|
|||||||
source_node_id :string ,
|
source_node_id :string ,
|
||||||
dest_node_id :string ,
|
dest_node_id :string ,
|
||||||
issue_type_id :string,
|
issue_type_id :string,
|
||||||
|
source_anchor_point:string,
|
||||||
|
end_anchor_point:string
|
||||||
}
|
}
|
||||||
export const Table_Workflow_Action="workflow_action"
|
export const Table_Workflow_Action="workflow_action"
|
||||||
|
|
||||||
|
23
code/common/model/workflow_approval.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {BaseModel} from "./base"
|
||||||
|
|
||||||
|
export enum ECommon_Model_Workflow_Approval_Type {
|
||||||
|
PERSON,
|
||||||
|
TEAM,
|
||||||
|
FIELD
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICommon_Model_Workflow_Approval {
|
||||||
|
id :string ,
|
||||||
|
workflow_node_id:string,
|
||||||
|
type:ECommon_Model_Workflow_Approval_Type,
|
||||||
|
value:string[],
|
||||||
|
extra:string
|
||||||
|
}
|
||||||
|
export const Table_Workflow_Approval="workflow_approval"
|
||||||
|
|
||||||
|
class WorkflowApprovalModel extends BaseModel {
|
||||||
|
table=Table_Workflow_Approval
|
||||||
|
model=<ICommon_Model_Workflow_Approval>{}
|
||||||
|
}
|
||||||
|
|
||||||
|
export let workflowApprovalModel=new WorkflowApprovalModel
|
@ -13,7 +13,8 @@ export interface ICommon_Model_Workflow_Node {
|
|||||||
status :ECommon_Model_Workflow_Node_Status,
|
status :ECommon_Model_Workflow_Node_Status,
|
||||||
issue_type_id :string ,
|
issue_type_id :string ,
|
||||||
x:number,
|
x:number,
|
||||||
y:number
|
y:number,
|
||||||
|
is_approval:number
|
||||||
}
|
}
|
||||||
export const Table_Workflow_Node="workflow_node"
|
export const Table_Workflow_Node="workflow_node"
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ const api={
|
|||||||
req: <{
|
req: <{
|
||||||
workflowNodeFieldTypeId :string,
|
workflowNodeFieldTypeId :string,
|
||||||
data:{
|
data:{
|
||||||
|
id?:string
|
||||||
value :string,
|
value :string,
|
||||||
selected :number
|
selected :number
|
||||||
}[]
|
}[]
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
import {ECommon_HttpApi_Method} from "./types";
|
import {ECommon_HttpApi_Method} from "./types";
|
||||||
import {ICommon_Model_Project_Issue_Field_Value} from "../model/project_issue_field_value";
|
import {ICommon_Model_Project_Issue_Field_Value} from "../model/project_issue_field_value";
|
||||||
import {ICommon_Model_Project_Release} from "../model/project_release";
|
import {ICommon_Model_Project_Release} from "../model/project_release";
|
||||||
|
import {ICommon_Model_Project_Issue_History} from "../model/project_issue_history";
|
||||||
|
|
||||||
const api={
|
const api={
|
||||||
baseUrl:"/issue",
|
baseUrl:"/issue",
|
||||||
@ -143,7 +144,10 @@ const api={
|
|||||||
req:<{
|
req:<{
|
||||||
projectIssueId :string
|
projectIssueId :string
|
||||||
}>{},
|
}>{},
|
||||||
res:<ICommon_Model_Workflow_Action[]>{},
|
res:<ICommon_Model_Workflow_Action[] | {
|
||||||
|
isApproval:true,
|
||||||
|
name:"Resolve"|"Reject"|"Revoke"|"Commit"
|
||||||
|
}[]>{},
|
||||||
permission:[Permission_Types.Project.READ]
|
permission:[Permission_Types.Project.READ]
|
||||||
},
|
},
|
||||||
commentList:{
|
commentList:{
|
||||||
@ -188,7 +192,8 @@ const api={
|
|||||||
method:ECommon_HttpApi_Method.POST,
|
method:ECommon_HttpApi_Method.POST,
|
||||||
path:"/item/copy",
|
path:"/item/copy",
|
||||||
req:<{
|
req:<{
|
||||||
projectIssueId :string
|
projectIssueId :string,
|
||||||
|
name:string
|
||||||
}>{},
|
}>{},
|
||||||
res:<ICommon_Model_Project_Issue>{},
|
res:<ICommon_Model_Project_Issue>{},
|
||||||
permission:[Permission_Types.Project.EDIT]
|
permission:[Permission_Types.Project.EDIT]
|
||||||
@ -339,6 +344,73 @@ const api={
|
|||||||
photo:string
|
photo:string
|
||||||
}[]>{},
|
}[]>{},
|
||||||
permission:[Permission_Types.Project.READ]
|
permission:[Permission_Types.Project.READ]
|
||||||
|
},
|
||||||
|
createChildIssue:{
|
||||||
|
method:ECommon_HttpApi_Method.POST,
|
||||||
|
path:"/item/createchild",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string,
|
||||||
|
name:string
|
||||||
|
}>{},
|
||||||
|
res:<ICommon_Model_Project_Issue>{},
|
||||||
|
permission:[Permission_Types.Project.EDIT]
|
||||||
|
},
|
||||||
|
listHistory:{
|
||||||
|
method:ECommon_HttpApi_Method.GET,
|
||||||
|
path:"/history",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string,
|
||||||
|
}>{},
|
||||||
|
res:<ICommon_Model_Project_Issue_History[]>{},
|
||||||
|
permission:[Permission_Types.Project.READ]
|
||||||
|
},
|
||||||
|
checkApproval:{
|
||||||
|
method:ECommon_HttpApi_Method.GET,
|
||||||
|
path:"/approval/check",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string,
|
||||||
|
}>{},
|
||||||
|
res:<{
|
||||||
|
access:boolean
|
||||||
|
}>{},
|
||||||
|
permission:[Permission_Types.Project.READ]
|
||||||
|
},
|
||||||
|
revokeApproval:{
|
||||||
|
method:ECommon_HttpApi_Method.POST,
|
||||||
|
path:"/approval/revoke",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string,
|
||||||
|
}>{},
|
||||||
|
res:{},
|
||||||
|
permission:[Permission_Types.Project.EDIT]
|
||||||
|
},
|
||||||
|
resolveApproval:{
|
||||||
|
method:ECommon_HttpApi_Method.POST,
|
||||||
|
path:"/approval/resolve",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string,
|
||||||
|
}>{},
|
||||||
|
res:{},
|
||||||
|
permission:[Permission_Types.Project.EDIT]
|
||||||
|
},
|
||||||
|
rejectApproval:{
|
||||||
|
method:ECommon_HttpApi_Method.POST,
|
||||||
|
path:"/approval/reject",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string,
|
||||||
|
reason:string
|
||||||
|
}>{},
|
||||||
|
res:{},
|
||||||
|
permission:[Permission_Types.Project.EDIT]
|
||||||
|
},
|
||||||
|
commitApproval:{
|
||||||
|
method:ECommon_HttpApi_Method.POST,
|
||||||
|
path:"/approval/commit",
|
||||||
|
req:<{
|
||||||
|
projectIssueId :string
|
||||||
|
}>{},
|
||||||
|
res:{},
|
||||||
|
permission:[Permission_Types.Project.EDIT]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,14 @@ const api= {
|
|||||||
notificationId:string
|
notificationId:string
|
||||||
}>{},
|
}>{},
|
||||||
res: <ICommon_Route_Res_Notification_Item>{}
|
res: <ICommon_Route_Res_Notification_Item>{}
|
||||||
|
},
|
||||||
|
remove:{
|
||||||
|
method: ECommon_HttpApi_Method.DELETE,
|
||||||
|
path: "/item",
|
||||||
|
req: <{
|
||||||
|
notificationId:string
|
||||||
|
}>{},
|
||||||
|
res: <ICommon_Route_Res_Notification_Item>{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ const api={
|
|||||||
method:ECommon_HttpApi_Method.GET,
|
method:ECommon_HttpApi_Method.GET,
|
||||||
path:"/user/list",
|
path:"/user/list",
|
||||||
req:<{
|
req:<{
|
||||||
organizationId:string,
|
organizationId?:string,
|
||||||
page:number,
|
page:number,
|
||||||
size:number,
|
size:number,
|
||||||
keyword?:string
|
keyword?:string
|
||||||
@ -193,7 +193,7 @@ const api={
|
|||||||
method:ECommon_HttpApi_Method.GET,
|
method:ECommon_HttpApi_Method.GET,
|
||||||
path:"/tag/list",
|
path:"/tag/list",
|
||||||
req:<{
|
req:<{
|
||||||
|
keyword?:string
|
||||||
}>{},
|
}>{},
|
||||||
res:<ICommon_Model_Member_Tag[]>{},
|
res:<ICommon_Model_Member_Tag[]>{},
|
||||||
permission:[Permission_Types.Organization.READ]
|
permission:[Permission_Types.Organization.READ]
|
||||||
@ -217,6 +217,15 @@ const api={
|
|||||||
res:<ICommon_Model_Member_Tag>{},
|
res:<ICommon_Model_Member_Tag>{},
|
||||||
permission:[Permission_Types.Organization.ADMIN]
|
permission:[Permission_Types.Organization.ADMIN]
|
||||||
},
|
},
|
||||||
|
getTag:{
|
||||||
|
method:ECommon_HttpApi_Method.GET,
|
||||||
|
path:"/tag",
|
||||||
|
req:<{
|
||||||
|
memberTagId:string
|
||||||
|
}>{},
|
||||||
|
res:<ICommon_Model_Member_Tag>{},
|
||||||
|
permission:[Permission_Types.Organization.READ]
|
||||||
|
},
|
||||||
editTag:{
|
editTag:{
|
||||||
method:ECommon_HttpApi_Method.PUT,
|
method:ECommon_HttpApi_Method.PUT,
|
||||||
path:"/tag",
|
path:"/tag",
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
} from './response';
|
} from './response';
|
||||||
import {ECommon_HttpApi_Method} from "./types";
|
import {ECommon_HttpApi_Method} from "./types";
|
||||||
import {ICommon_Model_Role} from "../model/role";
|
import {ICommon_Model_Role} from "../model/role";
|
||||||
|
import {ICommon_Model_Project_Label} from "../model/project_label";
|
||||||
|
|
||||||
const api={
|
const api={
|
||||||
baseUrl:"/project",
|
baseUrl:"/project",
|
||||||
@ -76,6 +77,15 @@ const api={
|
|||||||
res:<ICommon_Route_Res_Project_ListTag>{},
|
res:<ICommon_Route_Res_Project_ListTag>{},
|
||||||
permission:[Permission_Types.Project.READ]
|
permission:[Permission_Types.Project.READ]
|
||||||
},
|
},
|
||||||
|
getLabel:{
|
||||||
|
method:ECommon_HttpApi_Method.GET,
|
||||||
|
path:"/tag/item",
|
||||||
|
req:<{
|
||||||
|
labelId:string
|
||||||
|
}>{},
|
||||||
|
res:<ICommon_Model_Project_Label>{},
|
||||||
|
permission:[Permission_Types.Project.READ]
|
||||||
|
},
|
||||||
createLabel:{//创建tag
|
createLabel:{//创建tag
|
||||||
method:ECommon_HttpApi_Method.POST,
|
method:ECommon_HttpApi_Method.POST,
|
||||||
path:"/tag/item",
|
path:"/tag/item",
|
||||||
|
@ -26,6 +26,8 @@ import {ICommon_Model_Wiki_Item} from "../model/wiki_item";
|
|||||||
import {ICommon_Model_Meeting_Room} from "../model/meeting_room";
|
import {ICommon_Model_Meeting_Room} from "../model/meeting_room";
|
||||||
import {ICommon_Model_Notification} from "../model/notification";
|
import {ICommon_Model_Notification} from "../model/notification";
|
||||||
import {ICommon_Model_Meeting_Miss_Call} from "../model/meeting_miss_call";
|
import {ICommon_Model_Meeting_Miss_Call} from "../model/meeting_miss_call";
|
||||||
|
import {ICommon_Model_Workflow_Approval} from "../model/workflow_approval";
|
||||||
|
import {ICommon_Model_Project_Issue_Approval} from "../model/project_issue_approval";
|
||||||
|
|
||||||
export interface ICommon_Route_Res_Project_CreateModule_Data {
|
export interface ICommon_Route_Res_Project_CreateModule_Data {
|
||||||
id:string,
|
id:string,
|
||||||
@ -141,7 +143,9 @@ export interface ICommon_Route_Res_Workflow_Info_Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ICommon_Route_Res_Workflow_Info {
|
export interface ICommon_Route_Res_Workflow_Info {
|
||||||
nodes:ICommon_Model_Workflow_Node[],
|
nodes:(ICommon_Model_Workflow_Node & {
|
||||||
|
approval?:ICommon_Model_Workflow_Approval
|
||||||
|
})[],
|
||||||
actions:ICommon_Model_Workflow_Action[]
|
actions:ICommon_Model_Workflow_Action[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +170,11 @@ export type ICommon_Route_Req_ProjectIssue_Field_Value={
|
|||||||
export interface ICommon_Route_Res_ProjectIssue_BasicInfo extends Omit<ICommon_Model_Project_Issue,"workflow_node_id"|"issue_type_id"|"project_id"> {
|
export interface ICommon_Route_Res_ProjectIssue_BasicInfo extends Omit<ICommon_Model_Project_Issue,"workflow_node_id"|"issue_type_id"|"project_id"> {
|
||||||
workflowNode:ICommon_Model_Workflow_Node
|
workflowNode:ICommon_Model_Workflow_Node
|
||||||
issueType:ICommon_Model_Issue_Type,
|
issueType:ICommon_Model_Issue_Type,
|
||||||
project:ICommon_Model_Project
|
project:ICommon_Model_Project,
|
||||||
|
approval?:ICommon_Model_Project_Issue_Approval & {
|
||||||
|
reason?:string,
|
||||||
|
workflowNode:ICommon_Model_Workflow_Node
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ICommon_Route_Res_ProjectIssue_fieldsInfo = {
|
export type ICommon_Route_Res_ProjectIssue_fieldsInfo = {
|
||||||
|
@ -5,6 +5,7 @@ import {ECommon_Services} from './../types';
|
|||||||
import {ECommon_HttpApi_Method} from "./types";
|
import {ECommon_HttpApi_Method} from "./types";
|
||||||
import {ICommon_Route_Res_Workflow_Info, ICommon_Route_Res_Workflow_Node_List_Item} from "./response";
|
import {ICommon_Route_Res_Workflow_Info, ICommon_Route_Res_Workflow_Node_List_Item} from "./response";
|
||||||
import {Permission_Types} from "../permission/permission";
|
import {Permission_Types} from "../permission/permission";
|
||||||
|
import {ECommon_Model_Workflow_Approval_Type, ICommon_Model_Workflow_Approval} from "../model/workflow_approval";
|
||||||
|
|
||||||
const api={
|
const api={
|
||||||
baseUrl:"/workflow",
|
baseUrl:"/workflow",
|
||||||
@ -42,9 +43,15 @@ const api={
|
|||||||
description? :string,
|
description? :string,
|
||||||
status? :ECommon_Model_Workflow_Node_Status,
|
status? :ECommon_Model_Workflow_Node_Status,
|
||||||
x?:number,
|
x?:number,
|
||||||
y?:number
|
y?:number,
|
||||||
|
approval?:number,
|
||||||
|
approvalType?:ECommon_Model_Workflow_Approval_Type,
|
||||||
|
approvalValue?:string[],
|
||||||
|
approvalExtra?:string
|
||||||
|
}>{},
|
||||||
|
res:<ICommon_Model_Workflow_Node & {
|
||||||
|
approval?:ICommon_Model_Workflow_Approval
|
||||||
}>{},
|
}>{},
|
||||||
res:<ICommon_Model_Workflow_Node>{},
|
|
||||||
permission:[Permission_Types.Organization.ADMIN]
|
permission:[Permission_Types.Organization.ADMIN]
|
||||||
},
|
},
|
||||||
deleteNode:{
|
deleteNode:{
|
||||||
@ -65,6 +72,8 @@ const api={
|
|||||||
description? :string,
|
description? :string,
|
||||||
sourceNodeId:string,
|
sourceNodeId:string,
|
||||||
destNodeId:string,
|
destNodeId:string,
|
||||||
|
sourceAnchorPoint:string,
|
||||||
|
endAnchorPoint:string
|
||||||
}>{},
|
}>{},
|
||||||
res:<ICommon_Model_Workflow_Action>{},
|
res:<ICommon_Model_Workflow_Action>{},
|
||||||
permission:[Permission_Types.Organization.ADMIN]
|
permission:[Permission_Types.Organization.ADMIN]
|
||||||
@ -78,6 +87,8 @@ const api={
|
|||||||
description? :string,
|
description? :string,
|
||||||
sourceNodeId?:string,
|
sourceNodeId?:string,
|
||||||
destNodeId?:string,
|
destNodeId?:string,
|
||||||
|
sourceAnchorPoint?:string,
|
||||||
|
endAnchorPoint?:string
|
||||||
}>{},
|
}>{},
|
||||||
res:<ICommon_Model_Workflow_Action>{},
|
res:<ICommon_Model_Workflow_Action>{},
|
||||||
permission:[Permission_Types.Organization.ADMIN]
|
permission:[Permission_Types.Organization.ADMIN]
|
||||||
@ -98,6 +109,18 @@ const api={
|
|||||||
res:<ICommon_Route_Res_Workflow_Node_List_Item[]>{},
|
res:<ICommon_Route_Res_Workflow_Node_List_Item[]>{},
|
||||||
permission:[Permission_Types.Organization.READ]
|
permission:[Permission_Types.Organization.READ]
|
||||||
},
|
},
|
||||||
|
listApprovalField:{
|
||||||
|
method:ECommon_HttpApi_Method.GET,
|
||||||
|
path:"/approval/field",
|
||||||
|
req:<{
|
||||||
|
workflowNodeId:string
|
||||||
|
}>{},
|
||||||
|
res:<{
|
||||||
|
id:string,
|
||||||
|
name:string
|
||||||
|
}[]>{},
|
||||||
|
permission:[Permission_Types.Organization.READ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default api
|
export default api
|
@ -250,6 +250,18 @@ export namespace Err {
|
|||||||
unbindReservedWorkflowSolutionForbidden:{
|
unbindReservedWorkflowSolutionForbidden:{
|
||||||
code:3514,
|
code:3514,
|
||||||
msg:"unbind reserved workflow solution forbidden"
|
msg:"unbind reserved workflow solution forbidden"
|
||||||
|
},
|
||||||
|
approvalOnlyHaveOneExport:{
|
||||||
|
code:2515,
|
||||||
|
msg:"approval only have one export"
|
||||||
|
},
|
||||||
|
approvalNotFound:{
|
||||||
|
code:2516,
|
||||||
|
msg:"approval not found"
|
||||||
|
},
|
||||||
|
workflowNodeIsNotApproval:{
|
||||||
|
code:2517,
|
||||||
|
msg:"workflow node is not aproval"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Field:{
|
Field:{
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
import * as mysql from "mysql2";
|
import * as mysql from "mysql2";
|
||||||
import { Pool as PromisePool } from "mysql2/promise";
|
import {Pool as PromisePool} from "mysql2/promise";
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { Err } from '../../../common/status/error';
|
import {Err} from '../../../common/status/error';
|
||||||
import { IServer_Common_Config_Mysql } from './../types/config';
|
import {IServer_Common_Config_Mysql} from './../types/config';
|
||||||
|
|
||||||
var g_mysqlConnection:InstanceType<typeof Mysql>
|
var g_mysqlConnection:InstanceType<typeof Mysql>
|
||||||
export function getMysqlInstance(){
|
export function getMysqlInstance(){
|
||||||
@ -84,6 +83,18 @@ export default class Mysql {
|
|||||||
ret[key]=item[key]
|
ret[key]=item[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(let key in ret) {
|
||||||
|
let obj=ret[key]
|
||||||
|
if(typeof(obj)==="object") {
|
||||||
|
let set=new Set
|
||||||
|
for(let k in obj) {
|
||||||
|
set.add(obj[k])
|
||||||
|
}
|
||||||
|
if(set.size==1 && set.has(null)) {
|
||||||
|
delete ret[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret as any;
|
return ret as any;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -131,6 +142,18 @@ export default class Mysql {
|
|||||||
ret[key as any]=item[key]
|
ret[key as any]=item[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(let key in ret) {
|
||||||
|
let obj=ret[key]
|
||||||
|
if(typeof(obj)==="object") {
|
||||||
|
let set=new Set
|
||||||
|
for(let k in obj) {
|
||||||
|
set.add(obj[k])
|
||||||
|
}
|
||||||
|
if(set.size==1 && set.has(null)) {
|
||||||
|
delete ret[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret as any;
|
return ret as any;
|
||||||
})
|
})
|
||||||
return <T[]><unknown>rows
|
return <T[]><unknown>rows
|
||||||
|
@ -45,7 +45,7 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
|
|||||||
getItem():T["model"] {
|
getItem():T["model"] {
|
||||||
return this.item;
|
return this.item;
|
||||||
}
|
}
|
||||||
async create():Promise<T["model"]> {
|
async create(...param:any):Promise<T["model"]> {
|
||||||
if(!this.item) {
|
if(!this.item) {
|
||||||
throw Err.Common.itemNotFound;
|
throw Err.Common.itemNotFound;
|
||||||
} else if(this.item.id) {
|
} else if(this.item.id) {
|
||||||
@ -60,7 +60,7 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
|
|||||||
})
|
})
|
||||||
return this.item;
|
return this.item;
|
||||||
}
|
}
|
||||||
async update():Promise<T["model"]>{
|
async update(...param:any):Promise<T["model"]>{
|
||||||
if(!this.item || !this.item.id) {
|
if(!this.item || !this.item.id) {
|
||||||
throw Err.Common.itemNotFound;
|
throw Err.Common.itemNotFound;
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
|
|||||||
await this.loadItem();
|
await this.loadItem();
|
||||||
return this.item;
|
return this.item;
|
||||||
}
|
}
|
||||||
async delete(eventPublish?:keyof IServer_Common_Event_Types){
|
async delete(eventPublish?:keyof IServer_Common_Event_Types,...param:any){
|
||||||
await this.mapper.delete(this.item.id);
|
await this.mapper.delete(this.item.id);
|
||||||
if(eventPublish) {
|
if(eventPublish) {
|
||||||
emitServiceEvent(eventPublish,this.item.id);
|
emitServiceEvent(eventPublish,this.item.id);
|
||||||
|
@ -85,6 +85,10 @@ class RpcContentApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearByRefIdAndType(refId:string,type:ECommon_Model_Content_Type) {
|
||||||
|
await ContentService.clearByRefIdAndType(refId,type)
|
||||||
|
}
|
||||||
|
|
||||||
async clearByRefId(refId:string) {
|
async clearByRefId(refId:string) {
|
||||||
await ContentService.clearByRefId(refId)
|
await ContentService.clearByRefId(refId)
|
||||||
}
|
}
|
||||||
|
@ -23,17 +23,19 @@ export class ContentService extends Entity<typeof contentModel,typeof contentMap
|
|||||||
|
|
||||||
override async delete(eventPublish?: keyof IServer_Common_Event_Types): Promise<void> {
|
override async delete(eventPublish?: keyof IServer_Common_Event_Types): Promise<void> {
|
||||||
await super.delete(eventPublish);
|
await super.delete(eventPublish);
|
||||||
for(let objLine of JSON.parse(this.getItem().content) as ICommon_Content_Line[]) {
|
if(this.getItem().content) {
|
||||||
for(let objConfig of objLine.arr) {
|
for(let objLine of JSON.parse(this.getItem().content) as ICommon_Content_Line[]) {
|
||||||
if(objConfig.type===ECommon_Content_Line_Config_Type.FILE || objConfig.type===ECommon_Content_Line_Config_Type.IMAGE) {
|
for(let objConfig of objLine.arr) {
|
||||||
emitServiceEvent("fileUnref",objConfig.value)
|
if(objConfig.type===ECommon_Content_Line_Config_Type.FILE || objConfig.type===ECommon_Content_Line_Config_Type.IMAGE) {
|
||||||
|
emitServiceEvent("fileUnref",objConfig.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override async create(): Promise<typeof contentModel["model"]> {
|
override async create(): Promise<typeof contentModel["model"]> {
|
||||||
this.item.content=this.item.content.replaceAll("\\\"","\\\\\"")
|
this.item.content=this.item.content.replaceAll("\\","\\\\")
|
||||||
let ret=await super.create();
|
let ret=await super.create();
|
||||||
let obj=this.generateLineObj(ret.content)
|
let obj=this.generateLineObj(ret.content)
|
||||||
for(let key in obj.file) {
|
for(let key in obj.file) {
|
||||||
@ -61,7 +63,7 @@ export class ContentService extends Entity<typeof contentModel,typeof contentMap
|
|||||||
|
|
||||||
override async update(): Promise<typeof contentModel["model"]> {
|
override async update(): Promise<typeof contentModel["model"]> {
|
||||||
let oldObj=this.generateLineObj(this._item.content)
|
let oldObj=this.generateLineObj(this._item.content)
|
||||||
this.item.content=this.item.content.replaceAll("\\\"","\\\\\"")
|
this.item.content=this.item.content.replaceAll("\\","\\\\")
|
||||||
let ret=await super.update();
|
let ret=await super.update();
|
||||||
let newObj=this.generateLineObj(ret.content)
|
let newObj=this.generateLineObj(ret.content)
|
||||||
for(let key in oldObj.file) {
|
for(let key in oldObj.file) {
|
||||||
@ -125,7 +127,7 @@ export class ContentService extends Entity<typeof contentModel,typeof contentMap
|
|||||||
[param:string]:number
|
[param:string]:number
|
||||||
}={}
|
}={}
|
||||||
if(content) {
|
if(content) {
|
||||||
let arr=JSON.parse(content) as ICommon_Content_Line[]
|
let arr=JSON.parse(decodeURIComponent(content)) as ICommon_Content_Line[]
|
||||||
for(let obj of arr) {
|
for(let obj of arr) {
|
||||||
for(let obj1 of obj.arr) {
|
for(let obj1 of obj.arr) {
|
||||||
if(obj1.type===ECommon_Content_Line_Config_Type.FILE || obj1.type===ECommon_Content_Line_Config_Type.IMAGE) {
|
if(obj1.type===ECommon_Content_Line_Config_Type.FILE || obj1.type===ECommon_Content_Line_Config_Type.IMAGE) {
|
||||||
@ -161,6 +163,18 @@ export class ContentService extends Entity<typeof contentModel,typeof contentMap
|
|||||||
await Promise.all(arrPromise)
|
await Promise.all(arrPromise)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async clearByRefIdAndType(refId:string,type:ECommon_Model_Content_Type) {
|
||||||
|
let arr=await ContentService.getItemsByExp({
|
||||||
|
ref_id:refId,
|
||||||
|
type
|
||||||
|
})
|
||||||
|
let arrPromise=[]
|
||||||
|
for(let obj of arr) {
|
||||||
|
arrPromise.push(obj.delete())
|
||||||
|
}
|
||||||
|
await Promise.all(arrPromise)
|
||||||
|
}
|
||||||
|
|
||||||
static async clearByRefIds(refIds:string[]) {
|
static async clearByRefIds(refIds:string[]) {
|
||||||
let arrPromise=[]
|
let arrPromise=[]
|
||||||
for(let refId of refIds) {
|
for(let refId of refIds) {
|
||||||
|
@ -124,6 +124,7 @@ class FieldController {
|
|||||||
@DHttpApi(fieldApi.routes.editWorkflowNodeFieldConfig)
|
@DHttpApi(fieldApi.routes.editWorkflowNodeFieldConfig)
|
||||||
async addWorkflowNodeFieldConfig(@DHttpReqParamRequired("workflowNodeFieldTypeId") workflowNodeFieldTypeId:string,
|
async addWorkflowNodeFieldConfig(@DHttpReqParamRequired("workflowNodeFieldTypeId") workflowNodeFieldTypeId:string,
|
||||||
@DHttpReqParamRequired("data") data:{
|
@DHttpReqParamRequired("data") data:{
|
||||||
|
id?:string,
|
||||||
value :string,
|
value :string,
|
||||||
selected :number
|
selected :number
|
||||||
}[]): Promise<typeof fieldApi.routes.editWorkflowNodeFieldConfig.res> {
|
}[]): Promise<typeof fieldApi.routes.editWorkflowNodeFieldConfig.res> {
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
import {Err} from "../../../common/status/error";
|
import {Err} from "../../../common/status/error";
|
||||||
import {DComponent} from "../../common/decorate/component";
|
import {DComponent} from "../../common/decorate/component";
|
||||||
import {DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser} from "../../common/http/http";
|
import {DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser} from "../../common/http/http";
|
||||||
import {ProjectIssueService} from "../service/issue";
|
import {ProjectIssueHistoryService, ProjectIssueService} from "../service/issue";
|
||||||
import {ProjectService} from "../service/project";
|
import {ProjectService} from "../service/project";
|
||||||
import {IUserSession} from "../../user/types/config";
|
import {IUserSession} from "../../user/types/config";
|
||||||
import rpcContentApi from "../../content/rpc/content"
|
import rpcContentApi from "../../content/rpc/content"
|
||||||
@ -15,6 +15,7 @@ import rpcNotificationApi from "../../notification/rpc/notification"
|
|||||||
import {ECommon_Model_Notification_Type} from "../../../common/model/notification";
|
import {ECommon_Model_Notification_Type} from "../../../common/model/notification";
|
||||||
import rpcCooperationApi from "../rpc/cooperation"
|
import rpcCooperationApi from "../rpc/cooperation"
|
||||||
import rpcUserApi from "../../user/rpc/user"
|
import rpcUserApi from "../../user/rpc/user"
|
||||||
|
import {ECommon_Model_Project_Issue_History_Type} from "../../../common/model/project_issue_history";
|
||||||
|
|
||||||
@DComponent
|
@DComponent
|
||||||
@DHttpController(projectIssueApi)
|
@DHttpController(projectIssueApi)
|
||||||
@ -79,7 +80,7 @@ class IssueController {
|
|||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
await projectIssue.confirmNextNode(workflowActionId,values)
|
await projectIssue.confirmNextNode(workflowActionId,values,user.organizationInfo.organizationUserId)
|
||||||
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_WORKFLOW_CHANGE,projectIssueId,null,user.organizationInfo.organizationUserId)
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_WORKFLOW_CHANGE,projectIssueId,null,user.organizationInfo.organizationUserId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -90,7 +91,7 @@ class IssueController {
|
|||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
let ret=await projectIssue.updateFieldValue(value)
|
let ret=await projectIssue.updateFieldValue(value,user.organizationInfo.organizationUserId)
|
||||||
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_FIELD_CHANGE,projectIssueId,null,user.organizationInfo.organizationUserId)
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_FIELD_CHANGE,projectIssueId,null,user.organizationInfo.organizationUserId)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -120,6 +121,30 @@ class IssueController {
|
|||||||
if(name || priority) {
|
if(name || priority) {
|
||||||
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_FIELD_CHANGE,projectIssueId,null,user.organizationInfo.organizationUserId)
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_FIELD_CHANGE,projectIssueId,null,user.organizationInfo.organizationUserId)
|
||||||
}
|
}
|
||||||
|
let key:string,value:string
|
||||||
|
if(name) {
|
||||||
|
key="Name"
|
||||||
|
value=name
|
||||||
|
} else if(priority!==undefined) {
|
||||||
|
key="Priority"
|
||||||
|
value=String(priority)
|
||||||
|
} else if(assignerId) {
|
||||||
|
key="Assigner"
|
||||||
|
value=assignerId
|
||||||
|
} else if(reporterId) {
|
||||||
|
key="Reporter"
|
||||||
|
value=reporterId
|
||||||
|
}
|
||||||
|
let objHistory=new ProjectIssueHistoryService()
|
||||||
|
objHistory.assignItem({
|
||||||
|
project_issue_id:ret.id,
|
||||||
|
name:key,
|
||||||
|
type:ECommon_Model_Project_Issue_History_Type.UPDATE_FIELD,
|
||||||
|
organization_user_id:user.organizationInfo.organizationUserId,
|
||||||
|
project_id:ret.project_id,
|
||||||
|
value:value
|
||||||
|
})
|
||||||
|
objHistory.create()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@DHttpApi(projectIssueApi.routes.editDescription)
|
@DHttpApi(projectIssueApi.routes.editDescription)
|
||||||
@ -184,12 +209,12 @@ class IssueController {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@DHttpApi(projectIssueApi.routes.actionsInfo)
|
@DHttpApi(projectIssueApi.routes.actionsInfo)
|
||||||
async actionsInfo(@DHttpReqParamRequired("projectIssueId") projectIssueId :string):Promise<typeof projectIssueApi.routes.actionsInfo.res> {
|
async actionsInfo(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.actionsInfo.res> {
|
||||||
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
let ret=await projectIssue.actionsInfo()
|
let ret=await projectIssue.actionsInfo(user.organizationInfo.organizationUserId)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@DHttpApi(projectIssueApi.routes.commentList)
|
@DHttpApi(projectIssueApi.routes.commentList)
|
||||||
@ -214,12 +239,18 @@ class IssueController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
@DHttpApi(projectIssueApi.routes.copy)
|
@DHttpApi(projectIssueApi.routes.copy)
|
||||||
async copy(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.copy.res> {
|
async copy(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParam("name") name :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.copy.res> {
|
||||||
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
let ret=await projectIssue.copy()
|
let ret=await projectIssue.copy()
|
||||||
|
if(name) {
|
||||||
|
ret.assignItem({
|
||||||
|
name
|
||||||
|
})
|
||||||
|
await ret.update()
|
||||||
|
}
|
||||||
if(ret.getItem().assigner_id) {
|
if(ret.getItem().assigner_id) {
|
||||||
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_ASSIGNER_ASSIGN,ret.getId(),ret.getItem().assigner_id,user.organizationInfo.organizationUserId)
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_ASSIGNER_ASSIGN,ret.getId(),ret.getItem().assigner_id,user.organizationInfo.organizationUserId)
|
||||||
}
|
}
|
||||||
@ -292,21 +323,21 @@ class IssueController {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@DHttpApi(projectIssueApi.routes.bindLabel)
|
@DHttpApi(projectIssueApi.routes.bindLabel)
|
||||||
async bindTag(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParamRequired("labelIds") labelIds :string[]):Promise<typeof projectIssueApi.routes.bindLabel.res> {
|
async bindTag(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParamRequired("labelIds") labelIds :string[],@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.bindLabel.res> {
|
||||||
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
let ret=await projectIssue.bindLabels(labelIds)
|
let ret=await projectIssue.bindLabels(labelIds,user.organizationInfo.organizationUserId)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@DHttpApi(projectIssueApi.routes.bindModule)
|
@DHttpApi(projectIssueApi.routes.bindModule)
|
||||||
async bindModule(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParam("moduleId") moduleId :string):Promise<typeof projectIssueApi.routes.bindModule.res> {
|
async bindModule(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParam("moduleId") moduleId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.bindModule.res> {
|
||||||
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
let ret=await projectIssue.bindModule(moduleId)
|
let ret=await projectIssue.bindModule(moduleId,user.organizationInfo.organizationUserId)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,12 +369,12 @@ class IssueController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DHttpApi(projectIssueApi.routes.bindReleases)
|
@DHttpApi(projectIssueApi.routes.bindReleases)
|
||||||
async bindReleases(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParamRequired("projectReleaseIds") projectReleaseIds :string[]):Promise<typeof projectIssueApi.routes.bindReleases.res> {
|
async bindReleases(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParamRequired("projectReleaseIds") projectReleaseIds :string[],@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.bindReleases.res> {
|
||||||
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
if(!projectIssue) {
|
if(!projectIssue) {
|
||||||
throw Err.Project.ProjectIssue.projectIssueNotFound
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
}
|
}
|
||||||
let ret=await projectIssue.bindReleases(projectReleaseIds)
|
let ret=await projectIssue.bindReleases(projectReleaseIds,user.organizationInfo.organizationUserId)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,4 +391,91 @@ class IssueController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.createChildIssue)
|
||||||
|
async createChildIssue(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParamRequired("name") name :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.createChildIssue.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
let ret=await projectIssue.copy()
|
||||||
|
ret.assignItem({
|
||||||
|
name
|
||||||
|
})
|
||||||
|
await Promise.all([
|
||||||
|
ret.update(),
|
||||||
|
projectIssue.addChildIssue(ret.getId())
|
||||||
|
])
|
||||||
|
if(ret.getItem().assigner_id) {
|
||||||
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_ASSIGNER_ASSIGN,ret.getId(),ret.getItem().assigner_id,user.organizationInfo.organizationUserId)
|
||||||
|
}
|
||||||
|
if(ret.getItem().reporter_id) {
|
||||||
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_REPORTER_ASSIGN,ret.getId(),ret.getItem().reporter_id,user.organizationInfo.organizationUserId)
|
||||||
|
}
|
||||||
|
return ret.getItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.listHistory)
|
||||||
|
async listHistory(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.listHistory.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
let ret=await ProjectIssueHistoryService.list(projectIssueId)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.checkApproval)
|
||||||
|
async checkApproval(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.checkApproval.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
let ret=await projectIssue.checkApproval(user.organizationInfo.organizationUserId)
|
||||||
|
return {
|
||||||
|
access:ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.revokeApproval)
|
||||||
|
async revokeApproval(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.revokeApproval.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
await projectIssue.revokeApproval()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.resolveApproval)
|
||||||
|
async resolveApproval(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.resolveApproval.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
await projectIssue.resolveApproval(user.organizationInfo.organizationUserId)
|
||||||
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_APPROVAL_RESOLVE,projectIssue.getId(),projectIssue.getItem().assigner_id,user.organizationInfo.organizationUserId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.rejectApproval)
|
||||||
|
async rejectApproval(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpReqParamRequired("reason") reason :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.rejectApproval.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
await projectIssue.rejectApproval(user.organizationInfo.organizationUserId,reason)
|
||||||
|
rpcNotificationApi.createNotification(ECommon_Model_Notification_Type.ISSUE_APPROVAL_REJECT,projectIssue.getId(),projectIssue.getItem().assigner_id,user.organizationInfo.organizationUserId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@DHttpApi(projectIssueApi.routes.commitApproval)
|
||||||
|
async commitApproval(@DHttpReqParamRequired("projectIssueId") projectIssueId :string,@DHttpUser user:IUserSession):Promise<typeof projectIssueApi.routes.commitApproval.res> {
|
||||||
|
let projectIssue=await ProjectIssueService.getItemById(projectIssueId)
|
||||||
|
if(!projectIssue) {
|
||||||
|
throw Err.Project.ProjectIssue.projectIssueNotFound
|
||||||
|
}
|
||||||
|
await projectIssue.commitApproval()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,10 +2,19 @@ import projectApi from "../../../common/routes/project";
|
|||||||
import {DComponent} from "../../common/decorate/component";
|
import {DComponent} from "../../common/decorate/component";
|
||||||
import {DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired} from "../../common/http/http";
|
import {DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired} from "../../common/http/http";
|
||||||
import {ProjectLabelService} from "../service/label";
|
import {ProjectLabelService} from "../service/label";
|
||||||
|
import {Err} from "../../../common/status/error";
|
||||||
|
|
||||||
@DComponent
|
@DComponent
|
||||||
@DHttpController(projectApi)
|
@DHttpController(projectApi)
|
||||||
class TagController {
|
class TagController {
|
||||||
|
@DHttpApi(projectApi.routes.getLabel)
|
||||||
|
async getLabel(@DHttpReqParamRequired("labelId") labelId:string):Promise<typeof projectApi.routes.getLabel.res> {
|
||||||
|
let tag=await ProjectLabelService.getItemById(labelId)
|
||||||
|
if(!tag) {
|
||||||
|
throw Err.Project.Label.labelNotfound
|
||||||
|
}
|
||||||
|
return tag.getItem();
|
||||||
|
}
|
||||||
@DHttpApi(projectApi.routes.listLabel)
|
@DHttpApi(projectApi.routes.listLabel)
|
||||||
async listTag(@DHttpReqParamRequired("projectId") projectId:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("keyword") keyword:string):Promise<typeof projectApi.routes.listLabel.res> {
|
async listTag(@DHttpReqParamRequired("projectId") projectId:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("keyword") keyword:string):Promise<typeof projectApi.routes.listLabel.res> {
|
||||||
let tag=new ProjectLabelService()
|
let tag=new ProjectLabelService()
|
||||||
|