This commit is contained in:
sx1989827 2023-09-10 08:09:03 +08:00
parent 659d93ad7e
commit bc9a907ab1
193 changed files with 2747 additions and 1316 deletions

View File

@ -23,6 +23,7 @@
"socket.io-client": "^4.6.1",
"uuid": "^9.0.0",
"vue": "^3.3.4",
"vue-i18n": "^9.3.0",
"vue-router": "^4.2.2"
},
"devDependencies": {

View File

@ -2,7 +2,7 @@
<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="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?$t("util.input"):$t("util.alert")}}</b>
</div>
<div style="display: flex;overflow: auto;box-sizing: border-box;padding: 10px;flex: 0 1 auto;height: calc(100% - 80px);width: 100%">
<div style="width: 100%;flex: 1">
@ -15,8 +15,8 @@
</div>
<div style="height: 45px;width: 100%;display: flex;justify-content: flex-end;border-top: 1px solid gainsboro;flex: 1 0 auto">
<a-space size="medium">
<a-button type="primary" @click="onOk" size="small" html-type="submit" :loading="props.loading?props.loading.value:false">{{(component || input)?"Ok":"Yes"}}</a-button>
<a-button type="outline" style="margin-right: 10px" size="small" @click="onClose">{{(component || input)?"Close":"No"}}</a-button>
<a-button type="primary" @click="onOk" size="small" html-type="submit" :loading="props.loading?props.loading.value:false">{{(component || input)?$t("util.ok"):$t("util.yes")}}</a-button>
<a-button type="outline" style="margin-right: 10px" size="small" @click="onClose">{{(component || input)?$t("util.close"):$t("util.no")}}</a-button>
</a-space>
</div>
</div>

View File

@ -2,7 +2,7 @@
<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>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("common.component.field.basic.fieldEditBasicAssigner.noUser")}}</span>
</template>
<a-row style="padding-right: 10px" v-else>
<a-select allow-search allow-clear v-model="editValue" @search="onSearchAssigner">

View File

@ -4,7 +4,7 @@
<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: grey">None</span>
<span v-else style="line-height: 30px;width: 100%;color: grey">{{$t("util.none")}}</span>
</template>
<a-row style="padding-right: 10px" v-else>
<a-space size="mini" wrap>
@ -18,7 +18,7 @@
<template #icon>
<icon-plus />
</template>
Add
{{$t("util.add")}}
</a-tag>
<a-button type="text" @click="onClick">
<template #icon>

View File

@ -4,7 +4,7 @@
<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>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
</template>
<a-row style="padding-right: 10px" v-else>
<a-space size="mini" wrap>
@ -18,7 +18,7 @@
<template #icon>
<icon-plus />
</template>
Add
{{$t("util.add")}}
</a-tag>
<a-button type="text" @click="onClick">
<template #icon>

View File

@ -7,10 +7,10 @@
</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>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.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-cascader v-model="editValue" :field-names="fields" :options="moduleList" :placeholder="$t('placeholder.pleaseSelect')" :format-label="format" check-strictly allow-clear allow-search></a-cascader>
<a-button type="text" @click="onClick">
<template #icon>
<icon-check></icon-check>

View File

@ -4,10 +4,10 @@
<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-option :value="ECommon_Model_Project_Issue_Priority.LOW">{{$t("util.low")}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.MEDIUM">{{$t("util.medium")}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.HIGH">{{$t("util.hign")}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.URGENT">{{$t("util.urgent")}}</a-option>
</a-select>
<a-button type="text" @click="onClick">
<template #icon>

View File

@ -2,7 +2,7 @@
<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>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("common.component.field.basic.fieldEditBasicAssigner.noUser")}}</span>
</template>
<a-row style="padding-right: 10px" v-else>
<a-select allow-search allow-clear v-model="editValue" @search="onSearchReporter">

View File

@ -4,7 +4,7 @@
<a-space wrap size="mini" v-if="showValue">
<BoardSprintPreview :key="showValue.id" :board-sprint-id="showValue.id" :name="showValue.name"></BoardSprintPreview>
</a-space>
<span v-else style="line-height: 30px;width: 100%;color: grey">None</span>
<span v-else style="line-height: 30px;width: 100%;color: grey">{{$t("util.none")}}</span>
</template>
<a-row style="padding-right: 10px" v-else>
<a-space size="mini" wrap>

View File

@ -9,7 +9,7 @@
{{showValue.name}}
</a-tag>
</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">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini" wrap>

View File

@ -11,7 +11,7 @@
</a-tag>
</template>
</a-space>
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini" wrap>
@ -25,7 +25,7 @@
<template #icon>
<icon-plus />
</template>
Add
{{$t("util.add")}}
</a-tag>
<a-button type="text" @click="onSubmit">
<template #icon>

View File

@ -1,7 +1,7 @@
<template>
<template v-if="!isEdit">
<span v-if="showValue">{{showValue}}</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini">

View File

@ -6,7 +6,7 @@
<ProjectIssuePreview :name="key+'-'+showValue.uniqueId" :project-issue-id="showValue.id" v-else-if="type===ECommon_Model_Workflow_Node_Field_Type_Label_Type.ISSUE"></ProjectIssuePreview>
<BoardSprintPreview :name="showValue.name" :board-sprint-id="showValue.id" v-else-if="type===ECommon_Model_Workflow_Node_Field_Type_Label_Type.SPRINT"></BoardSprintPreview>
</template>
<span v-else style="line-height: 30px;width: 100%;color: grey">None</span>
<span v-else style="line-height: 30px;width: 100%;color: grey">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini">

View File

@ -6,7 +6,7 @@
<ProjectIssuePreview v-for="value in showValue" :key="value.id" :name="key+'-'+value.uniqueId" :project-issue-id="value.id" v-else-if="type===ECommon_Model_Workflow_Node_Field_Type_Label_Type.ISSUE"></ProjectIssuePreview>
<BoardSprintPreview v-for="value in showValue" :name="value.name" :board-sprint-id="value.id" v-else-if="type===ECommon_Model_Workflow_Node_Field_Type_Label_Type.SPRINT"></BoardSprintPreview>
</a-space>
<span v-else style="line-height: 30px;width: 100%;color: grey">None</span>
<span v-else style="line-height: 30px;width: 100%;color: grey">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini" wrap>

View File

@ -3,7 +3,7 @@
<template v-if="showValue && showValue.length>0">
<a-tag v-for="item in showValue">{{item.value}}</a-tag>
</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">{{$t("util.none")}}</span>
</a-space>
<template v-else>
<a-space size="mini" wrap>

View File

@ -1,7 +1,7 @@
<template>
<template v-if="!isEdit">
<span v-if="showValue">{{showValue}}</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini">

View File

@ -3,7 +3,7 @@
<template v-if="showValue">
<a-tag>{{showValue}}</a-tag>
</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">{{$t("util.none")}}</span>
</a-space>
<template v-else>
<a-space size="mini">

View File

@ -1,7 +1,7 @@
<template>
<template v-if="!isEdit">
<span v-if="showValue">{{showValue}}</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini">

View File

@ -1,7 +1,7 @@
<template>
<template v-if="!isEdit">
<span v-if="showValue">{{showValue}}</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
</template>
<template v-else>
<a-space size="mini">

View File

@ -3,27 +3,27 @@
<span v-if="priority==ECommon_Model_Project_Issue_Priority.LOW">
<icon-down style="color: lightblue"></icon-down>&nbsp;
<template v-if="!onlyIcon">
Low
{{$t("util.low")}}
</template>
</span>
<span v-else-if="priority==ECommon_Model_Project_Issue_Priority.MEDIUM">
<icon-unordered-list style="color: orange"></icon-unordered-list>&nbsp;
<template v-if="!onlyIcon">
Medium
{{$t("util.medium")}}
</template>
</span>
<span v-else-if="priority==ECommon_Model_Project_Issue_Priority.HIGH">
<icon-up style="color: #ea6e41"></icon-up>&nbsp;
<template v-if="!onlyIcon">
High
{{$t("util.high")}}
</template>
</span>
<span v-if="priority==ECommon_Model_Project_Issue_Priority.URGENT">
<icon-double-up style="color: red"></icon-double-up>&nbsp;
<template v-if="!onlyIcon">
Urgent
{{$t("util.urgent")}}
</template>
</span>

View File

@ -190,6 +190,7 @@ import {ICommon_Model_Organization} from "../../../../../common/model/organizati
import UserAvatar from "./userAvatar.vue";
import {Dialog} from "./dialog/dialog";
import {getCurrentInstance} from "vue";
import {useI18n} from "vue-i18n";
type ISSUE={
issue:DCSType<ICommon_Model_Project_Issue>,
@ -199,6 +200,7 @@ const props=defineProps<{
obj:DCSType<ICommon_Route_Res_Notification_Item>
}>()
const appContext=getCurrentInstance().appContext
const {t}=useI18n()
const onTeam=()=>{
const myOrganizationId=SessionStorage.get("organizationId")
if(myOrganizationId===props.obj.organization_id) {
@ -248,7 +250,7 @@ const onCalendarEvent=()=>{
}
const onAcceptOrganizationInvitation=async ()=>{
let ret=await Dialog.confirm(document.body,appContext,"Do you want accept this invitation?")
let ret=await Dialog.confirm(document.body,appContext,t("tip.acceptInvitation"))
if(ret) {
let res=await apiNotification.setStatus({
notificationId:props.obj.id,
@ -256,7 +258,7 @@ const onAcceptOrganizationInvitation=async ()=>{
})
if(res?.code==0) {
props.obj.status=ECommon_Model_Notification_Status.RESOLVED
Message.success("Accepted")
Message.success(t("util.accepted"))
setTimeout(()=>{
eventBus.emit(EClient_EVENTBUS_TYPE.REFRESH_ORGANIZATION_LIST)
},1000)
@ -267,7 +269,7 @@ const onAcceptOrganizationInvitation=async ()=>{
}
const onRejectOrganizationInvitation=async()=>{
let ret=await Dialog.confirm(document.body,appContext,"Do you want reject this invitation?")
let ret=await Dialog.confirm(document.body,appContext,t("tip.rejectInvitation"))
if(ret) {
let res=await apiNotification.setStatus({
notificationId:props.obj.id,
@ -275,7 +277,7 @@ const onRejectOrganizationInvitation=async()=>{
})
if(res?.code==0) {
props.obj.status=ECommon_Model_Notification_Status.REJECTED
Message.success("Rejected")
Message.success(t("util.rejected"))
} else {
Message.error(res.msg)
}

View File

@ -1,7 +1,7 @@
<template>
<div style="width: 100%;height: 100%;padding: 5px;box-sizing: border-box" ref="rootEle" @mousedown="onMouseDown">
<div style="height: 30px;border-bottom: 1px lightgray solid">
<input v-model="keyword" placeholder="type name" style="width: 100%;box-sizing: border-box" @input="onChange">
<input v-model="keyword" :placeholder="$t('placeholder.typeName')" style="width: 100%;box-sizing: border-box" @input="onChange">
</div>
<div class="hover" v-for="item in list" style="height: 40px;display: flex;align-items: center" @click="onClick(item)">
<img v-if="item.photo" style="width: 30px;height: 30px;border-radius: 15px" :src="item.photo">&nbsp;

View File

@ -1,7 +1,7 @@
<template>
<div>
<div ref="root" @mouseover="onMouseOver" @keydown="onKeyDown" style="padding: 10px" @keyup="onKeyUp" :style="{border:border?'border: 1px solid lightgray;':'0px'}" @copy="onCopy" @dragstart="onDragStart">
<div v-for="(item,index) in lineList" :key="index" contenteditable="true" @blur="onBlur(item,$event)" ref="elementList" v-html="RichEditorHandle.handle(item)" @keydown.enter="onEnter(item,index,$event)" @keydown.delete="onDelete(index,item,$event)" style="line-height: 1.5" @focus="onFocus(item,$event)" @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove" @dblclick="onDbClick" @paste="onPaste" @click="onClick" placeholder="type / for command,@ for quote person or drop what you want" v-if="!readonly">
<div v-for="(item,index) in lineList" :key="index" contenteditable="true" @blur="onBlur(item,$event)" ref="elementList" v-html="RichEditorHandle.handle(item)" @keydown.enter="onEnter(item,index,$event)" @keydown.delete="onDelete(index,item,$event)" style="line-height: 1.5" @focus="onFocus(item,$event)" @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove" @dblclick="onDbClick" @paste="onPaste" @click="onClick" :placeholder="$t('placeholder.richText')" v-if="!readonly">
</div>
<div v-for="(item,index) in lineList" @click="onClick" :key="index+1" v-html="RichEditorHandle.handle(item)" style="line-height: 1.5;min-height: 21px" v-else>
</div>

View File

@ -11,7 +11,7 @@
<div class="arco-upload-picture-card" v-else>
<div class="arco-upload-picture-card-text">
<IconPlus />
<div style="margin-top: 10px; font-weight: 600">Upload</div>
<div style="margin-top: 10px; font-weight: 600">{{$t("util.upload")}}</div>
</div>
</div>
</div>

View File

@ -43,15 +43,15 @@
</a-list-item-meta>
<template #actions>
<template v-if="organizationUserId===myOrganizationUserId">
<a-button type="outline" size="small" style="margin-left: 20px" @click="onProfile">Profile</a-button>
<a-button type="outline" size="small" style="margin-left: 20px" @click="onProfile">{{$t("util.profile")}}</a-button>
</template>
<a-row v-else style="flex-direction: column">
<a-button type="outline" size="mini" style="margin-left: 20px" @click="onProfile">Profile</a-button>
<a-button type="outline" size="mini" style="margin-left: 20px" @click="onProfile">{{$t("util.profile")}}</a-button>
<a-button type="outline" size="mini" style="margin-left: 20px;margin-top: 10px" @click="onMessage">
<template #icon>
<icon-message></icon-message>
</template>
Message
{{$t("util.message")}}
</a-button>
</a-row>
</template>
@ -70,6 +70,7 @@ import {SessionStorage} from "../storage/session";
import {ECommon_IM_Message_EntityType} from "../../../../../common/model/im_unread_message";
import {ECommon_User_Online_Status} from "../../../../../common/types";
import {Message} from "@arco-design/web-vue";
import {useI18n} from "vue-i18n";
const loading=ref(true)
const props=defineProps<{
@ -89,6 +90,7 @@ const showCloseable=ref(false)
const root=ref(null);
const name=ref("")
const photo=ref("")
const {t}=useI18n()
const status=ref(ECommon_User_Online_Status.OFFLINE)
watch(()=>[props.name,props.photo],()=>{
name.value=props.name
@ -107,7 +109,7 @@ const imgName=computed(()=>{
const info=ref<DCSType<ICommon_Model_Organization_User>>(null)
const onProfile=()=>{
if(info.value.organization_id!==SessionStorage.get("organizationId")) {
Message.error("you should switch to the specific organization")
Message.error(t("tip.switchToSpecificOrganization"))
return
}
eventBus.emit(EClient_EVENTBUS_TYPE.OPEN_PEOPLE_PROFILE,props.organizationUserId);
@ -144,7 +146,7 @@ const onPopup=async (visible:boolean)=>{
}
const onMessage=()=>{
if(info.value.organization_id!==SessionStorage.get("organizationId")) {
Message.error("you should switch to the specific organization")
Message.error(t("tip.switchToSpecificOrganization"))
return
}
eventBus.emit(EClient_EVENTBUS_TYPE.OPEN_IM_CHAT,props.organizationUserId,ECommon_IM_Message_EntityType.USER)

View File

@ -28,15 +28,15 @@
</a-list-item-meta>
<template #actions>
<template v-if="organizationUserId===myOrganizationUserId">
<a-button type="outline" size="small" style="margin-left: 20px" @mousedown="onProfile">Profile</a-button>
<a-button type="outline" size="small" style="margin-left: 20px" @mousedown="onProfile">{{$t("util.profile")}}</a-button>
</template>
<a-row v-else style="flex-direction: column">
<a-button type="outline" size="mini" style="margin-left: 20px" @mousedown="onProfile">Profile</a-button>
<a-button type="outline" size="mini" style="margin-left: 20px" @mousedown="onProfile">{{$t("util.profile")}}</a-button>
<a-button type="outline" size="mini" style="margin-left: 20px;margin-top: 10px" @mousedown="onMessage">
<template #icon>
<icon-message></icon-message>
</template>
Message
{{$t("util.message")}}
</a-button>
</a-row>
</template>

View File

@ -35,7 +35,8 @@ export enum EClient_EVENTBUS_TYPE {
FINDER_OPEN_WINDOW="finder_open_window",
REFRESH_ORGANIZATION_LIST="refresh_organization_list",
REFRESH_NOTIFICATION_UNREAD="refresh_notification_unread",
REFRESH_MISS_CALL_UNREAD="refresh_miss_call_unread"
REFRESH_MISS_CALL_UNREAD="refresh_miss_call_unread",
USER_LOGIN_EXPIRED="user_login_expired"
}
interface IClient_EventBus_Func {
@ -73,6 +74,7 @@ interface IClient_EventBus_Func {
[EClient_EVENTBUS_TYPE.REFRESH_MISS_CALL_UNREAD]:()=>void
[EClient_EVENTBUS_TYPE.OPEN_PROJECT_SPRINT_KANBAN_PROFILE]:(projectId:string,boardId:string,boardSprintId:string)=>void
[EClient_EVENTBUS_TYPE.OPEN_PROJECT_BOARD_PROFILE]:(projectId:string,boardId:string)=>void
[EClient_EVENTBUS_TYPE.USER_LOGIN_EXPIRED]:()=>void
}
interface IClient_EventBus_Emit_Func {

View File

@ -0,0 +1,18 @@
import en from "../../../../../common/i18n/en"
import {createI18n} from "vue-i18n";
import zh from "../../../../../common/i18n/zh";
const messages={
en,
zh
}
const language=(navigator.language || "en").toLowerCase()
const i18n=createI18n({
legacy:false,
locale:localStorage.getItem("lang") || language.split("-")[0] || "en",
fallbackLocale:"en",
messages
})
export default i18n

View File

@ -5,6 +5,7 @@ import {ECommon_Model_Finder_Item_Type} from "../../../../../common/model/finder
import {EClient_Drag_Type} from "../../../teamOS/common/directive/drag";
import {ECommon_IM_Message_ContentType} from "../../../../../common/model/im_user_message";
import {ECommon_Content_Line_Config_Type, ICommon_Content_Line} from "../../../../../common/model/content";
import i18n from "@/business/common/i18n/i18n";
export function getMemberIdFromRoleMember(item:ICommon_Route_Res_Role_Member_Item){
if(item.memberType==ECommon_Model_Organization_Member_Type.DEFAULT) {
@ -45,7 +46,8 @@ export function dialogFuncGenerator({func,form}:{
let res=await func()
if(typeof(res)=="object") {
if(res?.code==0) {
Message.success("operation success")
const {t}=i18n.global
Message.success(t("tip.operationSuccess"))
return res
} else {
Message.error(res.msg);

View File

@ -2,8 +2,8 @@
<a-layout style="height: 100%">
<a-layout-sider :resize-directions="['right']">
<a-menu style="width: 100%" @menu-item-click="onSubMenuClick" :default-selected-keys="['profile']">
<a-menu-item key="profile">Profile</a-menu-item>
<a-menu-item key="accountSetting">Account Setting</a-menu-item>
<a-menu-item key="profile">{{$t("controller.app.account.account.profile")}}</a-menu-item>
<a-menu-item key="accountSetting">{{$t("controller.app.account.account.accountSetting")}}</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout-content style="flex-direction: column;display: flex;padding: 10px">

View File

@ -1,14 +1,14 @@
<template>
<a-collapse :default-active-key="['wallpaper']">
<a-collapse-item key="wallpaper" header="Wallpaper">
<a-collapse-item key="wallpaper" :header="$t('util.wallpaper')">
<a-form :model="formWallPaper" style="width: 80%" @submitSuccess="onSubmitWallpaper">
<a-form-item field="photo" label="wallpaper">
<a-form-item field="photo" :label="$t('util.wallpaper')">
<Upload :default-uri="formWallPaper.photo" types=".png,.jpg,.jpeg,.gif,.bmp,.svg,.webp" @upload="onUploadWallpaper"></Upload>
</a-form-item>
<a-form-item>
<a-space size="large">
<a-button html-type="submit" type="primary">Save</a-button>
<a-button html-type="button" status="danger" v-if="formWallPaper.photo" @click="onClearWallpaper">Clear</a-button>
<a-button html-type="submit" type="primary">{{$t("util.ok")}}</a-button>
<a-button html-type="button" status="danger" v-if="formWallPaper.photo" @click="onClearWallpaper">{{$t("util.clear")}}</a-button>
</a-space>
</a-form-item>
</a-form>

View File

@ -1,22 +1,22 @@
<template>
<a-form :model="form" style="width: 80%" @submitSuccess="onSubmit">
<a-form-item field="photo" label="avatar">
<a-form-item field="photo" :label="$t('util.avatar')">
<Upload :default-uri="form.photo" types=".png,.jpg,.jpeg,.gif,.bmp,.svg" @upload="onUpload"></Upload>
</a-form-item>
<a-form-item label="username">
{{form.username}}
</a-form-item>
<a-form-item field="password" label="password">
<a-form-item field="password" :label="$t('util.password')">
<a-input-password v-model="form.password"></a-input-password>
</a-form-item>
<a-form-item field="repeatPassword" label="repeat password" v-if="form.password">
<a-form-item field="repeatPassword" :label="$t('util.repeatPassword')" v-if="form.password">
<a-input-password v-model="form.repeatPassword"></a-input-password>
</a-form-item>
<a-form-item field="sign" label="sign">
<a-form-item field="sign" :label="$t('util.sign')">
<a-input v-model="form.sign"></a-input>
</a-form-item>
<a-form-item>
<a-button html-type="submit" type="primary">Save</a-button>
<a-button html-type="submit" type="primary">{{$t("util.save")}}</a-button>
</a-form-item>
</a-form>
</template>
@ -29,6 +29,7 @@ import {apiUser} from "../../../common/request/request";
import {Message} from "@arco-design/web-vue";
import {SessionStorage} from "../../../common/storage/session";
import md5 from "blueimp-md5";
import {useI18n} from "vue-i18n";
const store=useDesktopStore()
const form=reactive({
@ -39,9 +40,10 @@ const form=reactive({
repeatPassword:"",
uploadUriId:""
})
const {t}=useI18n()
const onSubmit=async ()=>{
if(form.password && form.password!==form.repeatPassword) {
Message.error("password not match")
Message.error(t("tip.passwordNotMatch"))
return;
}
let arrPromise=[]
@ -63,7 +65,7 @@ const onSubmit=async ()=>{
}
let [res1,res2]=await Promise.all(arrPromise)
if(res1?.code==0) {
Message.success("update success")
Message.success(t("tip.updateSuccess"))
store.$refreshUser();
} else {
Message.error(res1.msg)

View File

@ -11,7 +11,7 @@
/>
<a-divider :margin="1"></a-divider>
<a-row style="display: flex;justify-content: space-between;margin-top: 10px;align-items: center">
<span style="font-size: small;color: gray">My Calendars</span>
<span style="font-size: small;color: gray">{{$t("controller.app.calendar.calendar.myCalendars")}}</span>
<a-button size="mini" type="text" @click="onAddCalendar">
<template #icon>
<icon-plus style="color: gray"></icon-plus>
@ -40,7 +40,7 @@
<a-layout-content style="flex-direction: column;display: flex;padding: 10px;">
<a-row style="flex: 0 0 40px;display: flex;justify-content: space-between;justify-items: center;flex-wrap: nowrap">
<a-space size="mini">
<a-button type="primary" size="mini" @click="onToday">Today</a-button>
<a-button type="primary" size="mini" @click="onToday">{{$t("controller.app.calendar.calendar.today")}}</a-button>
<a-button type="text" @click="onPrevious">
<template #icon>
<icon-left style="color: rgb(95,99,104);font-size: large"></icon-left>
@ -55,25 +55,25 @@
{{calendarType=="day"?pickerValue.format("YYYY-MM-DD"):pickerValue.format("YYYY-MM")}}
</span>
</a-space>
<a-input style="width: 40%" placeholder="type event name" v-model="searchForm.keyword" allow-clear @input="onSearch">
<a-input style="width: 40%" :placeholder="$t('placeholder.typeEventName')" v-model="searchForm.keyword" allow-clear @input="onSearch">
<template #append>
<a-popover position="br" @popup-visible-change="visible => !visible && onSearch()">
<icon-arrow-down style="margin-left: 10px;cursor: pointer"></icon-arrow-down>
<template #content>
<a-form :model="{}" layout="vertical">
<a-form-item label="calendar">
<a-form-item :label="$t('util.calendar')">
<a-select size="small" v-model="searchForm.calendarId">
<a-option value="all">All</a-option>
<a-option value="all">{{$t("util.all")}}</a-option>
<a-option v-for="item in calendarList" :value="item.id">{{item.name}}</a-option>
</a-select>
</a-form-item>
<a-form-item label="start date">
<a-form-item :label="$t('util.startDate')">
<a-date-picker v-model="searchForm.startDate"></a-date-picker>
</a-form-item>
<a-form-item label="end date">
<a-form-item :label="$t('util.endDate')">
<a-date-picker v-model="searchForm.endDate"></a-date-picker>
</a-form-item>
<a-form-item label="location">
<a-form-item :label="$t('util.location')">
<a-input size="small" v-model="searchForm.location"></a-input>
</a-form-item>
</a-form>
@ -83,9 +83,9 @@
</a-input>
<a-space size="mini">
<a-radio-group type="button" v-model="calendarType" size="small">
<a-radio value="day">Day</a-radio>
<a-radio value="week">Week</a-radio>
<a-radio value="month">Month</a-radio>
<a-radio value="day">{{$t("controller.app.calendar.calendar.day")}}</a-radio>
<a-radio value="week">{{$t("controller.app.calendar.calendar.week")}}</a-radio>
<a-radio value="month">{{$t("controller.app.calendar.calendar.month")}}</a-radio>
</a-radio-group>
<a-button type="text" @click="onShowSetting">
<template #icon>
@ -103,17 +103,17 @@
<CalendarEventSearch :list="searchResultList" :timezone="setting.timezone" v-else-if="searchForm.keyword" style="width: 100%;height: 100%" @edit="onEditCalendarEvent" @delete="onDeleteCalendarEvent"></CalendarEventSearch>
</a-row>
</a-layout-content>
<a-drawer :popup-container="root" :visible="settingVisible" @ok="onSetting" unmount-on-close title="Calendar Global Setting" :closable="false" @cancel="settingVisible=false" :width="400" id="calendarSetting" :drawer-style="{zIndex:100}">
<a-drawer :popup-container="root" :visible="settingVisible" @ok="onSetting" unmount-on-close :title="$t('controller.app.calendar.calendar.calendarGlobalSetting')" :closable="false" @cancel="settingVisible=false" :width="400" id="calendarSetting" :drawer-style="{zIndex:100}">
<a-form :model="{}" layout="vertical">
<a-form-item label="follow device timezone">
<a-form-item :label="$t('controller.app.calendar.calendar.followDeviceTimeZone')">
<a-switch v-model="settingEdit.followDevice"></a-switch>
</a-form-item>
<a-form-item label="timezone" v-if="!settingEdit.followDevice">
<a-form-item :label="$t('util.timeZone')" v-if="!settingEdit.followDevice">
<a-select v-model="settingEdit.timezone">
<a-option v-for="item in timezones" :value="item.id">{{item.label}}</a-option>
</a-select>
</a-form-item>
<a-form-item label="start week day">
<a-form-item :label="$t('controller.app.calendar.calendar.startWeekDay')">
<a-select v-model="settingEdit.start_week_day">
<a-option v-for="item in ECommon_Calendar_WeekDay" :value="item">{{calendarWeekDayName[item]}}</a-option>
</a-select>
@ -163,6 +163,8 @@ import {SessionStorage} from "../../../common/storage/session";
import {ICommon_Route_Res_Calendar_ListEvent_Item} from "../../../../../../common/routes/response";
import CalendarEventSearch from "./calendarEventSearch.vue";
import {debounce} from "../../../common/util/helper";
import calendar from "../../../../../../common/routes/calendar";
import {useI18n} from "vue-i18n";
const props=defineProps<{
calendarEventId?:string
@ -197,6 +199,7 @@ const searchForm=reactive({
})
const searchResultList=ref<DCSType<ICommon_Route_Res_Calendar_ListEvent_Item>[]>([])
let searchDebounce=null
const {t}=useI18n()
provide(injectCalendarSetting,setting)
const startDay=computed(()=>{
let start_week_day=setting.value?.start_week_day
@ -309,13 +312,13 @@ const onEditCalendar=async (item)=>{
}
}
const onDeleteCalendar=async (item)=>{
let ret=await Dialog.confirm(root.value,appContext,"do you want to delete this calendar?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteCalendar"))
if(ret) {
let res=await apiCalendar.removeCalendar({
calendarId:item.id
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
if(selectedCalendar.value.includes(item.id)) {
selectedCalendar.value=selectedCalendar.value.splice(selectedCalendar.value.indexOf(item.id),1)
}
@ -331,7 +334,7 @@ const onSetting=async ()=>{
startWeekDay:settingEdit.value.start_week_day
})
if(res?.code==0) {
Message.success("update success")
Message.success(t("tip.updateSuccess"))
settingVisible.value=false
getSetting()
}
@ -392,7 +395,7 @@ const onAddCalendarEvent=async (date:moment.Moment, point:{
}
const saveCalendarEvent=async (title:string, dateInfo:CalendarEventModelType, calendarId:string)=>{
if(dateInfo.end<dateInfo.start) {
Message.error("end date can't less than start date")
Message.error(t("tip.endDateLess"))
return
}
let res=await apiCalendar.addCalendarEvent({
@ -476,13 +479,13 @@ const listCalendarEvent=async ()=>{
}
}
const onDeleteCalendarEvent=async (event:IClient_Calendar_Info)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this event?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteEvent"))
if(ret) {
let res=await apiCalendar.removeCalendarEvent({
calendarEventId:event.id
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
listCalendarEvent()
}
}

View File

@ -1,9 +1,9 @@
<template>
<a-form ref="eleForm" style="width: 80%" :model="form">
<a-form-item label="name" field="name" required>
<a-form-item :label="$t('util.name')" field="name" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="color" field="color" required>
<a-form-item :label="$t('util.color')" field="color" required>
<a-radio-group v-model="form.color">
<a-radio v-for="item in ECommon_Calendar_Color" :value="item">
<div :style="{backgroundColor:item}" style="display: inline-block;width: 14px;height: 14px;margin-top: 3px;border-radius: 2px"></div>

View File

@ -13,7 +13,7 @@
<template #label>
<icon-info-circle style="font-size: medium"></icon-info-circle>
</template>
<a-input placeholder="New Event Title" v-model="form.name"></a-input>
<a-input :placeholder="$t('placeholder.newEventTitle')" v-model="form.name"></a-input>
</a-form-item>
<a-form-item field="dateInfo" required hide-asterisk>
<template #label>
@ -33,8 +33,8 @@
</div>
<div style="height: 35px">
<a-space style="float: right;margin-right: 10px">
<a-button type="secondary" size="small" @click="emit('more',form.name,form.dateInfo,form.resourceId)">More Option</a-button>
<a-button type="primary" size="small" @click="checkValid">Save</a-button>
<a-button type="secondary" size="small" @click="emit('more',form.name,form.dateInfo,form.resourceId)">{{$t("controller.app.calendar.calendarEventAddSimple.moreOption")}}</a-button>
<a-button type="primary" size="small" @click="checkValid">{{$t("util.save")}}</a-button>
</a-space>
</div>
</div>

View File

@ -14,9 +14,9 @@
</a-row>
<a-row style="height: 40px">
<a-space wrap>
All Day:
{{$t("controller.app.calendar.calendarEventDateEdit.allDay")}}:
<a-switch :checked-value="1" :unchecked-value="0" v-model="data.isAllDay" size="small" @change="onChangeAllDay"></a-switch>
Repeat:
{{$t("controller.app.calendar.calendarEventDateEdit.repeat")}}:
<a-select style="width: 110px" size="small" v-model="data.recurring">
<a-option :value="ECommon_Calendar_Recurring_Type.NONE">No</a-option>
<a-option :value="ECommon_Calendar_Recurring_Type.DAY">Day</a-option>
@ -25,13 +25,13 @@
<a-option :value="ECommon_Calendar_Recurring_Type.MONTH">Month</a-option>
</a-select>
<template v-if="data.recurring===ECommon_Calendar_Recurring_Type.WEEK">
Select Weekday:
{{$t("controller.app.calendar.calendarEventDateEdit.selectWeekday")}}:
<a-select size="small" style="width: 130px" v-model="recurryingWeekDay" @change="onChangeRecurry">
<a-option v-for="item in ECommon_Calendar_WeekDay" :value="item">{{calendarWeekDayName[item]}}</a-option>
</a-select>
</template>
<template v-else-if="data.recurring===ECommon_Calendar_Recurring_Type.MONTH">
Input Day:
{{$t("controller.app.calendar.calendarEventDateEdit.inputDay")}}:
<a-input-number :min="1" :max="31" v-model="recurryingMonthDay" style="width: 100px" @change="onChangeRecurry" size="small"></a-input-number>
</template>

View File

@ -4,7 +4,7 @@
<template #label>
<icon-info-circle style="font-size: medium"></icon-info-circle>
</template>
<a-input placeholder="New Event Title" v-model="form.name" v-if="isSelf"></a-input>
<a-input :placeholder="$t('placeholder.newEventTitle')" v-model="form.name" v-if="isSelf"></a-input>
<template v-else>
{{form.name}}
</template>
@ -16,13 +16,13 @@
<CalendarEventDateEdit :timezone="timezone" :data="form.date"></CalendarEventDateEdit>
</a-form-item>
<a-form-item>
<a-divider orientation="left" :margin="1">Advanced</a-divider>
<a-divider orientation="left" :margin="1">{{$t("controller.app.calendar.calendarEventEdit.advanced")}}</a-divider>
</a-form-item>
<a-form-item field="location">
<template #label>
<icon-location style="font-size: medium"></icon-location>
</template>
<a-input placeholder="location" v-model="form.location" v-if="isSelf"></a-input>
<a-input :placeholder="$t('placeholder.location')" v-model="form.location" v-if="isSelf"></a-input>
<template v-else>
{{form.location?form.location:"None"}}
</template>
@ -32,21 +32,21 @@
<icon-notification style="font-size: medium"></icon-notification>
</template>
<a-select v-model="form.reminder" v-if="isSelf">
<a-option :value="0">No Reminder</a-option>
<a-option :value="5">5 Min Before</a-option>
<a-option :value="15">15 Min Before</a-option>
<a-option :value="30">30 Min Before</a-option>
<a-option :value="60">1 Hour Before</a-option>
<a-option :value="600">6 Hour Before</a-option>
<a-option :value="0">{{$t("controller.app.calendar.calendarEventEdit.noReminder")}}</a-option>
<a-option :value="5">{{$t("controller.app.calendar.calendarEventEdit.fiveMinBefore")}}</a-option>
<a-option :value="15">{{$t("controller.app.calendar.calendarEventEdit.fifteenMinBefore")}}</a-option>
<a-option :value="30">{{$t("controller.app.calendar.calendarEventEdit.thirtyMinBefore")}}</a-option>
<a-option :value="60">{{$t("controller.app.calendar.calendarEventEdit.oneHourBefore")}}</a-option>
<a-option :value="600">{{$t("controller.app.calendar.calendarEventEdit.sixHourBefore")}}</a-option>
</a-select>
<template v-else>
{{({
"0":"No Reminder",
"5":"5 Min Before",
"15":"15 Min Before",
"30":"30 Min Before",
"60":"1 Hour Before",
"600":"6 Hour Before"
"0":$t("controller.app.calendar.calendarEventEdit.noReminder"),
"5":$t("controller.app.calendar.calendarEventEdit.fiveMinBefore"),
"15":$t("controller.app.calendar.calendarEventEdit.fifteenMinBefore"),
"30":$t("controller.app.calendar.calendarEventEdit.thirtyMinBefore"),
"60":$t("controller.app.calendar.calendarEventEdit.oneHourBefore"),
"600":$t("controller.app.calendar.calendarEventEdit.sixHourBefore")
})[form.reminder]}}
</template>
</a-form-item>
@ -73,11 +73,11 @@
<a-switch v-model="form.meeting"></a-switch>
<a-popover position="right" v-if="form.meeting" trigger="click">
<a-button type="primary" status="success" style="margin-left: 20px">
Start Meeting
{{$t("controller.app.calendar.calendarEventEdit.startMeeting")}}
</a-button>
<template #content>
<a-row style="flex-direction: column;align-items: center">
<a-input size="small" placeholder="type user name" v-model="searchUserKey"></a-input>
<a-input size="small" :placeholder="$t('placeholder.typeUserName')" v-model="searchUserKey"></a-input>
<a-table style="width: 100%;margin-top: 10px" row-key="organizationUserId" :columns="columns" :data="(form.guestList as any).filter(item=>(item.organizationUserId!==organizationUserId && item.nickname.includes(searchUserKey)))" :row-selection="rowSelection" v-model:selected-keys="selectKeys" :pagination="false">
<template #name="{record}">
<UserAvatar :organization-user-id="record.organizationUserId" :name="record.nickname" :photo="record.photo"></UserAvatar>
@ -92,7 +92,7 @@
</template>
</template>
<a-button type="primary" status="success" @click="onMeeting" v-else>
Join Meeting
{{$t("controller.app.calendar.calendarEventEdit.joinMeeting")}}
</a-button>
</a-form-item>
<a-form-item field="guestList">
@ -139,6 +139,7 @@ import UserAvatar from "../../../common/component/userAvatar.vue";
import {TableRowSelection} from "@arco-design/web-vue/es/table/interface";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../common/event/event";
import {ECommon_Model_Organization_Member_Type} from "../../../../../../common/model/organization";
import {useI18n} from "vue-i18n";
const props=defineProps<{
type:"add"|"edit",
@ -166,9 +167,10 @@ const rowSelection=ref<TableRowSelection>({
showCheckedAll:true,
onlyCurrent:false
})
const {t}=useI18n()
const columns = [
{
title: 'Name',
title: t("util.name"),
slotName: 'name',
}
]
@ -264,7 +266,7 @@ onDialogOk(dialogFuncGenerator({
form:()=>formEle.value,
func:()=>{
if(form.date.end<form.date.start) {
Message.error("end date can't less than start date")
Message.error(t("tip.endDateLess"))
return false
}
if(isSelf.value) {

View File

@ -1,7 +1,7 @@
<template>
<a-space wrap>
<UserAvatar v-for="value in showValue" v-if="showValue && showValue.length>0" :organization-user-id="value.organizationUserId" :name="value.nickname" :photo="value.photo" :key="value.userId" @close="onClose" :closeable="true"></UserAvatar>
<span v-else style="line-height: 30px;width: 100%;color: gray">None</span>
<span v-else style="line-height: 30px;width: 100%;color: gray">{{$t("util.none")}}</span>
<a-select v-model="addValue" allow-search @search="onSearch" v-if="showInput" @change="onChange">
<a-option v-for="item1 in searchValueList" :label="item1.nickname" :value="item1.userId"></a-option>
</a-select>

View File

@ -44,11 +44,11 @@
<div style="flex: 1 1 auto;display: flex;align-items: center">
<a-popover position="right" trigger="click" v-if="isSelf">
<a-button type="primary" status="success" size="mini">
Start Meeting
{{$t("controller.app.calendar.calendarEventEdit.startMeeting")}}
</a-button>
<template #content>
<a-row style="flex-direction: column;align-items: center">
<a-input size="small" placeholder="type user name" v-model="searchUserKey"></a-input>
<a-input size="small" :placeholder="$t('placeholder.typeUserName')" v-model="searchUserKey"></a-input>
<a-table style="width: 100%;margin-top: 10px" row-key="organizationUserId" :columns="columns" :data="(calendarEventInfo.guestList as any).filter(item=>(item.organizationUserId!==organizationUserId && item.nickname.includes(searchUserKey)))" :row-selection="rowSelection" v-model:selected-keys="selectKeys" :pagination="false">
<template #name="{record}">
<UserAvatar :organization-user-id="record.organizationUserId" :name="record.nickname" :photo="record.photo"></UserAvatar>
@ -59,7 +59,7 @@
</template>
</a-popover>
<a-button type="primary" status="success" size="mini" @click="onMeeting" v-else>
Join Meeting
{{$t("controller.app.calendar.calendarEventEdit.joinMeeting")}}
</a-button>
</div>
</div>
@ -73,7 +73,7 @@
</template>
<template v-else>
<UserAvatar :organization-user-id="selectedEvent.created_by.organizationUserId" :name="selectedEvent.created_by.nickname" :photo="selectedEvent.created_by.photo"></UserAvatar>
&nbsp;invited you
&nbsp;{{$t("controller.app.calendar.calendarEventShortView.invitedYou")}}
</template>
</div>
</div>
@ -95,6 +95,7 @@ import {ICommon_Route_Res_Calendar_Event_Info} from "../../../../../../common/ro
import {TableRowSelection} from "@arco-design/web-vue/es/table/interface";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../common/event/event";
import {ECommon_Model_Organization_Member_Type} from "../../../../../../common/model/organization";
import {useI18n} from "vue-i18n";
const emit=defineEmits<{
edit:[event:IClient_Calendar_Info],
@ -117,9 +118,10 @@ const rowSelection=ref<TableRowSelection>({
showCheckedAll:true,
onlyCurrent:false
})
const {t}=useI18n()
const columns = [
{
title: 'Name',
title: t("util.name"),
slotName: 'name',
}
]

View File

@ -25,7 +25,7 @@
</a-row>
</a-row>
<template v-else-if="mode===EClient_Finder_Mode.SEARCH">
SEARCH RESULT:
{{$t("controller.app.finder.finder.searchResult")}}:
</template>
<a-row>
<a-input-search size="mini" style="background-color: white;border: 1px lightgray solid" @search="onSearch"></a-input-search>

View File

@ -21,10 +21,10 @@
<a-dropdown trigger="hover" position="bl">
<icon-more style="color: gray"></icon-more>
<template #content>
<a-doption @click="onRefresh(nodeData)">Refresh</a-doption>
<a-doption @click="onRenameFolder(nodeData)" v-if="nodeData.key">Rename</a-doption>
<a-doption @click="onAddFolder(nodeData)">Add Folder</a-doption>
<a-doption v-if="nodeData.key" @click="onRemove(nodeData)">Remove</a-doption>
<a-doption @click="onRefresh(nodeData)">{{$t("util.refresh")}}</a-doption>
<a-doption @click="onRenameFolder(nodeData)" v-if="nodeData.key">{{$t("util.rename")}}</a-doption>
<a-doption @click="onAddFolder(nodeData)">{{$t("controller.app.finder.finderFolderTree.addFolder")}}</a-doption>
<a-doption v-if="nodeData.key" @click="onRemove(nodeData)">{{$t("util.remove")}}</a-doption>
</template>
</a-dropdown>
</template>
@ -37,6 +37,7 @@ import {apiFinder} from "../../../common/request/request";
import {getRootNavigatorRef} from "../../../../teamOS/common/component/navigator/navigator";
import {Dialog} from "../../../common/component/dialog/dialog";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../common/event/event";
import {useI18n} from "vue-i18n";
interface FolderTree {
title:string,
@ -52,6 +53,7 @@ const rename=ref("")
const appContext=getCurrentInstance().appContext
const root=getRootNavigatorRef()
const expandKeys=ref<string[]>([])
const {t}=useI18n()
const folderTree=ref<FolderTree[]>([
{
title:"Desktop",
@ -96,7 +98,7 @@ const onConfirmRenameFolder=async (nodeData)=>{
}
const onAddFolder=async (nodeData)=>{
let ret=await Dialog.input(root.value,appContext,"please type folder name")
let ret=await Dialog.input(root.value,appContext,t("tip.typeFolderName"))
if(ret) {
let res=await apiFinder.createFolder({
name:ret,
@ -145,7 +147,7 @@ const findParentNodeData=(key:string,node?)=>{
}
const onRemove=async (nodeData)=>{
let ret=await Dialog.confirm(root.value,appContext,"do you want to delete this folder?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteFolder"))
if(ret) {
let res=await apiFinder.delete({
finderItemId:nodeData.key

View File

@ -27,6 +27,7 @@ import {EClient_Drag_Type, IClient_Drag_Element} from "../../../../teamOS/common
import {DropParam} from "../../../../teamOS/common/directive/drop";
import {SessionStorage} from "../../../common/storage/session";
import {Message} from "@arco-design/web-vue";
import i18n from "@/business/common/i18n/i18n";
export class FinderHandle {
private itemList=ref<Icon[]>([])
@ -65,7 +66,8 @@ export class FinderHandle {
{
title:"New Folder",
func:async value => {
let ret=await Dialog.input(this.root.value.$el?this.root.value.$el:this.root.value,this.appContext,"please type new folder name");
let {t}=i18n.global
let ret=await Dialog.input(this.root.value.$el?this.root.value.$el:this.root.value,this.appContext,t("tip.typeNewFolderName"));
if(ret) {
let res=await apiFinder.createFolder({
...(this.folderId && {
@ -255,7 +257,8 @@ export class FinderHandle {
let valueList=selectedSelectableItems.map(item=>{
return item.getAttribute("dragValue")
})
let ret=await Dialog.confirm(this.root.value.$el?this.root.value.$el:this.root.value,this.appContext,"Do you want to delete these items?")
const {t}=i18n.global
let ret=await Dialog.confirm(this.root.value.$el?this.root.value.$el:this.root.value,this.appContext,t("tip.deleteItems"))
if(ret) {
await Promise.allSettled(valueList.map(value=>{
return apiFinder.delete({
@ -374,7 +377,8 @@ export class FinderHandle {
private async onOpenShortcut(item:DCSType<ICommon_Model_Finder_Item>) {
if(item.organization_id!==SessionStorage.get("organizationId")) {
Message.error("you should switch to the specific organization")
const {t}=i18n.global
Message.error(t("tip.switchToSpecificOrganization"))
return
}
switch (item.shortcut_type) {

View File

@ -1,225 +1,225 @@
<template>
<div style="width: 100%;padding-left: 5px;box-sizing: border-box">
<a-descriptions style="margin-top: 10px;" title="Info" :column="1" :value-style="{wordBreak:'break-all'}">
<a-descriptions style="margin-top: 10px;" :title="$t('util.info')" :column="1" :value-style="{wordBreak:'break-all'}">
<template v-if="!item || !item.id">
<a-descriptions-item label="name">Desktop</a-descriptions-item>
<a-descriptions-item :label="$t('util.name')">Desktop</a-descriptions-item>
</template>
<template v-else-if="item.type===ECommon_Model_Finder_Item_Type.FILE">
<a-descriptions-item label="name">{{fileInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<span style="color: blue">
File
{{$t("util.file")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="size">{{generateSizeFormat(fileInfo?.file.size)}}</a-descriptions-item>
<a-descriptions-item label="date">{{moment(fileInfo?.created_time).format("YYYY-MM-DD HH:mm:ss")}}</a-descriptions-item>
<a-descriptions-item label="path">
<a-descriptions-item :label="$t('util.size')">{{generateSizeFormat(fileInfo?.file.size)}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.date')">{{moment(fileInfo?.created_time).format("YYYY-MM-DD HH:mm:ss")}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.path')">
{{generatePathFormat(fileInfo?.parentFolderList)}}
</a-descriptions-item>
</template>
<template v-else-if="item.type===ECommon_Model_Finder_Item_Type.FOLDER">
<a-descriptions-item label="name">{{folderInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{folderInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Folder
{{$t("util.folder")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="date">{{moment(folderInfo?.created_time).format("YYYY-MM-DD HH:mm:ss")}}</a-descriptions-item>
<a-descriptions-item label="path">
<a-descriptions-item :label="$t('util.date')">{{moment(folderInfo?.created_time).format("YYYY-MM-DD HH:mm:ss")}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.path')">
{{generatePathFormat(folderInfo?.parentFolderList)}}
</a-descriptions-item>
</template>
<template v-else-if="item.type===ECommon_Model_Finder_Item_Type.SHORTCUT">
<template v-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.PROJECT">
<a-descriptions-item label="name">{{projectInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{projectInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item :label="$t('util.category')">
<span style="color: green">
Project
{{$t("util.project")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="key">{{projectInfo?.keyword}}</a-descriptions-item>
<a-descriptions-item label="description" v-if="projectInfo?.description">
<a-descriptions-item :label="$t('util.key')">{{projectInfo?.keyword}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.description')" v-if="projectInfo?.description">
<span style="line-clamp: 4;-webkit-box-orient: vertical;overflow: hidden;display: -webkit-box;-moz-box-orient: vertical;">
{{projectInfo?.description}}
</span>
</a-descriptions-item>
<a-descriptions-item label="create" v-if="projectInfo">
<a-descriptions-item :label="$t('util.create')" v-if="projectInfo">
<UserAvatar :organization-user-id="projectInfo?.created_by.organizationUserId" :name="projectInfo?.created_by.nickname" :photo="projectInfo?.created_by.photo" :organization-id="projectInfo?.organization_id"></UserAvatar>
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.PROJECT_ISSUE">
<a-descriptions-item label="name">{{projectIssueInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{projectIssueInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item :label="$t('util.category')">
<span style="color: green">
Project Issue
{{$t("util.projectIssue")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="key">{{projectIssueInfo?.project.keyword+"-"+projectIssueInfo?.unique_id}}</a-descriptions-item>
<a-descriptions-item label="priority" v-if="projectIssueInfo">
<a-descriptions-item :label="$t('util.key')">{{projectIssueInfo?.project.keyword+"-"+projectIssueInfo?.unique_id}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.priority')" v-if="projectIssueInfo">
<FieldPriority :priority="projectIssueInfo?.priority"></FieldPriority>
</a-descriptions-item>
<a-descriptions-item label="issue type">
<a-descriptions-item :label="$t('util.issueType')">
{{projectIssueInfo?.issueType.name}}
</a-descriptions-item>
<a-descriptions-item label="status">
<a-descriptions-item :label="$t('util.status')">
{{projectIssueInfo?.workflowNode.name}}
</a-descriptions-item>
<a-descriptions-item label="reporter" v-if="projectIssueInfo?.reporter_id">
<a-descriptions-item :label="$t('util.reporter')" v-if="projectIssueInfo?.reporter_id">
<UserAvatar :organization-user-id="projectIssueInfo?.reporter_id.organizationUserId" :name="projectIssueInfo?.reporter_id.nickname" :photo="projectIssueInfo?.reporter_id.photo" :organization-id="projectIssueInfo?.project.organization_id"></UserAvatar>
</a-descriptions-item>
<a-descriptions-item label="assigner" v-if="projectIssueInfo?.assigner_id">
<a-descriptions-item :label="$t('util.assigner')" v-if="projectIssueInfo?.assigner_id">
<UserAvatar :organization-user-id="projectIssueInfo?.assigner_id.organizationUserId" :name="projectIssueInfo?.assigner_id.nickname" :photo="projectIssueInfo?.assigner_id.photo" :organization-id="projectIssueInfo?.project.organization_id"></UserAvatar>
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.PROJECT_RELEASE">
<a-descriptions-item label="name">{{projectReleaseInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{projectReleaseInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item label="$t('util.category')">
<span style="color: green">
Project Release
{{$t("util.projectRelease")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="status">
<a-descriptions-item :label="$t('util.status')">
{{projectReleaseInfo?.status===ECommon_Model_Project_Release_Status.RELEASE?"Release":projectReleaseInfo?.status===ECommon_Model_Project_Release_Status.ARCHIVED?"Archived":"UnRelease"}}
</a-descriptions-item>
<a-descriptions-item label="start">
<a-descriptions-item :label="$t('util.start')">
{{moment(projectReleaseInfo?.created_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="release">
<a-descriptions-item :label="$t('util.release')">
{{moment(projectReleaseInfo?.release_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="project">
<a-descriptions-item :label="$t('util.project')">
{{projectReleaseInfo?.projectName}}
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.BOARD_SPRINT">
<a-descriptions-item label="name">{{sprintInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="issues">{{sprintInfo?.issues.length}}</a-descriptions-item>
<a-descriptions-item label="swimLanes">{{sprintInfo?.swimLanes.length}}</a-descriptions-item>
<a-descriptions-item label="start">
<a-descriptions-item :label="$t('util.name')">{{sprintInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.issues')">{{sprintInfo?.issues.length}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.swimLanes')">{{sprintInfo?.swimLanes.length}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.start')">
{{moment(sprintInfo?.start_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="end">
<a-descriptions-item :label="$t('util.end')">
{{moment(sprintInfo?.end_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="project">
<a-descriptions-item :label="$t('util.project')">
{{sprintInfo?.project.name}}
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.WIKI">
<a-descriptions-item label="name">{{wikiInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{wikiInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item :label="$t('util.category')">
<span style="color: green">
Wiki Project
{{$t("util.wikiProject")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="create" v-if="wikiInfo">
<a-descriptions-item :label="$t('util.create')" v-if="wikiInfo">
<UserAvatar :organization-user-id="wikiInfo?.created_by.organizationUserId" :name="wikiInfo?.created_by.nickname" :photo="wikiInfo?.created_by.photo" :organization-id="wikiInfo?.organization_id"></UserAvatar>
</a-descriptions-item>
<a-descriptions-item label="wiki count">
<a-descriptions-item :label="$t('util.wikiCount')">
{{wikiInfo?.data.length}}
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.WIKI_ITEM">
<a-descriptions-item label="name">{{wikiItemInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{wikiItemInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item :label="$t('util.category')">
<span style="color: green">
Wiki Item
{{$t("util.wikiItem")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="create" v-if="wikiItemInfo">
<a-descriptions-item :label="$t('util.create')" v-if="wikiItemInfo">
<UserAvatar :organization-user-id="wikiItemInfo?.created_by.organizationUserId" :name="wikiItemInfo?.created_by.nickname" :photo="wikiItemInfo?.created_by.photo" :organization-id="wikiItemInfo?.wiki.organization_id"></UserAvatar>
</a-descriptions-item>
<a-descriptions-item label="wiki">
<a-descriptions-item :label="$t('util.wiki')">
{{wikiItemInfo?.wiki.name}}
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.CALENDAR_EVENT">
<a-descriptions-item label="name">{{calendarEventInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{calendarEventInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item :label="$t('util.category')">
<span style="color: green">
Calendar Event
{{$t("util.calendarEvent")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="start">
<a-descriptions-item :label="$t('util.start')">
{{moment(calendarEventInfo?.start_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="end">
<a-descriptions-item :label="$t('util.end')">
{{moment(calendarEventInfo?.end_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="calendar">
<a-descriptions-item :label="$t('util.calendar')">
{{calendarEventInfo?.calendarName}}
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>
<template v-else-if="item.shortcut_type===ECommon_Model_Finder_Shortcut_Type.MEETING_ROOM">
<a-descriptions-item label="name">{{meetingRoomInfo?.name}}</a-descriptions-item>
<a-descriptions-item label="type">
<a-descriptions-item :label="$t('util.name')">{{meetingRoomInfo?.name}}</a-descriptions-item>
<a-descriptions-item :label="$t('util.type')">
<span style="color: blue">
Shortcut
{{$t("util.shortcut")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="category">
<a-descriptions-item :label="$t('util.category')">
<span style="color: green">
Meeting
{{$t("util.meeting")}}
</span>
</a-descriptions-item>
<a-descriptions-item label="start">
<a-descriptions-item :label="$t('util.start')">
{{moment(meetingRoomInfo?.start_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="end">
<a-descriptions-item :label="$t('util.end')">
{{moment(meetingRoomInfo?.end_time).format("YYYY-MM-DD HH:mm:ss")}}
</a-descriptions-item>
<a-descriptions-item label="organization" v-if="organizationInfo">
<a-descriptions-item :label="$t('util.organization')" v-if="organizationInfo">
{{organizationInfo.name}}
</a-descriptions-item>
</template>

View File

@ -22,7 +22,7 @@
</a-button>
<template #content>
<a-row style="flex-direction: column;align-items: center">
<a-input size="small" placeholder="type user name" v-model="searchUserKey"></a-input>
<a-input size="small" :placeholder="$t('placeholder.typeUserName')" v-model="searchUserKey"></a-input>
<a-table style="width: 100%;margin-top: 10px" row-key="id" :columns="columns" :data="teamMemberList.filter(item=>(item.id!==organizationUserId && item.name.includes(searchUserKey)))" :row-selection="rowSelection" v-model:selected-keys="selectKeys" :pagination="false">
<template #name="{record}">
<UserAvatar :organization-user-id="record.id" :name="record.name" :photo="record.photo"></UserAvatar>
@ -130,6 +130,7 @@ import {EClient_EVENTBUS_TYPE, eventBus} from "../../../common/event/event";
import {ECommon_Model_Organization_Member_Type} from "../../../../../../common/model/organization";
import {TableRowSelection} from "@arco-design/web-vue/es/table/interface";
import UserAvatar from "../../../common/component/userAvatar.vue";
import {useI18n} from "vue-i18n";
const root = ref()
const appContext=getCurrentInstance().appContext
@ -177,9 +178,10 @@ const rowSelection=ref<TableRowSelection>({
showCheckedAll:true,
onlyCurrent:false
})
const {t}=useI18n()
const columns = [
{
title: 'Name',
title: t("util.name"),
slotName: 'name',
}
]

View File

@ -43,11 +43,13 @@ import {ECommon_Socket_Type} from "../../../../../../common/socket/types";
import {SessionStorage} from "../../../common/storage/session";
import {Message} from "@arco-design/web-vue";
import {Dialog} from "../../../common/component/dialog/dialog";
import {useI18n} from "vue-i18n";
const appContext=getCurrentInstance().appContext
const contentRef = ref<HTMLDivElement>()
const messageList = ref<IClient_Chat_Message_Item[]>([])
const socket=SocketIOClient.get(ECommon_Socket_Type.IM)
const {t}=useI18n()
let myOrganizationUserId=SessionStorage.get("organizationUserId")
const onWheel = (event: WheelEvent) => {
let ele = event.currentTarget as HTMLDivElement
@ -88,10 +90,10 @@ const getMessageList=async (date?:string)=>{
}
const onFavoriteDelete=async (item:IClient_Chat_Message_Item)=>{
let ret=await Dialog.confirm(document.getElementById("imWindow"),appContext,"Do you want delete this favorite?")
let ret=await Dialog.confirm(document.getElementById("imWindow"),appContext,t("tip.deleteFavorite"))
if(ret) {
socket.getSocket().emit("im_favorite_message_delete",item.messageId)
Message.info("delete success")
Message.info(t("tip.deleteSuccess"))
messageList.value.splice(messageList.value.findIndex(obj=>{
if(obj.messageId===item.messageId) {
return true

View File

@ -2,8 +2,8 @@
<a-layout style="height: 100%" id="imWindow">
<a-layout-sider :resize-directions="['right']">
<div style="width: 100%;height: 100%;overflow-y: auto;padding: 5px;box-sizing: border-box">
<a-select style="width: 100%" placeholder="type user or team" allow-search allow-clear @change="onChange" @search="onSearch">
<a-optgroup label="Team" v-if="selectList && selectList.teams && selectList.teams.length>0">
<a-select style="width: 100%" :placeholder="$t('placeholder.typeUserOrTeam')" allow-search allow-clear @change="onChange" @search="onSearch">
<a-optgroup :label="$t('util.team')" v-if="selectList && selectList.teams && selectList.teams.length>0">
<a-option v-for="item in selectList.teams" :value="item.id">
<a-row style="align-items: center">
<a-avatar :image-url="item.photo" :size="24"></a-avatar>&nbsp;
@ -11,7 +11,7 @@
</a-row>
</a-option>
</a-optgroup>
<a-optgroup label="User" v-if="selectList && selectList.users && selectList.users.length>0">
<a-optgroup :label="$t('util.user')" v-if="selectList && selectList.users && selectList.users.length>0">
<a-option v-for="item in selectList.users" :value="item.id">
<a-row style="align-items: center">
<a-avatar :image-url="item.photo" :size="24"></a-avatar>&nbsp;
@ -25,16 +25,16 @@
<template #icon>
<icon-star></icon-star>
</template>
Favorites
{{$t("controller.app.im.im.favorites")}}
</a-menu-item>
<a-menu-item key="messages">
<template #icon>
<icon-search></icon-search>
</template>
Messages
{{$t("controller.app.im.im.messages")}}
</a-menu-item>
</a-menu>
<a-divider>Recent</a-divider>
<a-divider>{{$t("controller.app.im.im.recent")}}</a-divider>
<RecentList ref="recentListRef" @select="onSelectChat" :init-data="id?{id,type:chatType}:undefined"></RecentList>
</div>
</a-layout-sider>
@ -42,7 +42,7 @@
<Chat :data="messageList" :type="selectedChat.type" :info="selectedChat" @send="onSend" v-if="selectedChat && selectedMenuKeys.length==0" ref="chatRef" @update-more="onShowMore" @click-photo="onClickChatPhoto" @favorite="onFavorite" :is-search="!!locateInfo" :teamMemberList="teamMemberList">
<template #info v-if="selectedChat.type===ECommon_IM_Message_EntityType.TEAM">
<a-collapse :default-active-key="['members']">
<a-collapse-item header="Members" key="members">
<a-collapse-item :header="$t('util.members')" key="members">
<a-space wrap>
<UserAvatar v-for="item in teamMemberList" :organization-user-id="item.id" :name="item.name" :photo="item.photo"></UserAvatar>
</a-space>
@ -88,11 +88,13 @@ import {ECommon_Content_Line_Config_Type, ICommon_Content_Line} from "../../../.
import Favorite from "./favorite.vue";
import ImMessageSearch from "./imMessageSearch.vue";
import {ICommon_Model_IM_Team_Message} from "../../../../../../common/model/im_team_message";
import {useI18n} from "vue-i18n";
const props=defineProps<{
id?:string,
chatType?:ECommon_IM_Message_EntityType
}>()
const {t}=useI18n()
const recentListRef=ref<InstanceType<typeof RecentList>>()
const selectList=ref<ICommon_Route_Res_Organization_FilterUserAndTeam>()
const messageList=ref<IClient_Chat_Message_Item[]>([])
@ -408,7 +410,7 @@ const onClickFavorite=(key:string)=>{
const onFavorite=async (item:IClient_Chat_Message_Item,type: ECommon_IM_Message_EntityType)=>{
let myOrganizationUserId=SessionStorage.get("organizationUserId")
socket.getSocket().emit("im_favorite_message_add",myOrganizationUserId,type,item.messageId)
Message.info("favorite success")
Message.info(t("tip.favoriteSuccess"))
}
const handleUserInfo = (id: string, info: {

View File

@ -1,13 +1,13 @@
<template>
<div style="height: 100%">
<a-row style="width: 100%">
<a-input-search placeholder="type your message and at least two characters" v-model="keyword" @search="onSearch" search-button></a-input-search>
<a-input-search :placeholder="$t('placeholder.imMessageSearch')" v-model="keyword" @search="onSearch" search-button></a-input-search>
</a-row>
<a-divider></a-divider>
<a-row style="width: 100%;">
<a-spin :loading="loading" style="width: 100%;">
<a-collapse style="width: 100%" v-model:active-key="activeKeys">
<a-collapse-item header="User" key="user">
<a-collapse-item :header="$t('util.user')" key="user">
<a-collapse style="width: 100%" v-if="userInfoList.length>0" :bordered="false">
<a-collapse-item v-for="(value,key) in messageList.users" :key="key">
<template #header>
@ -42,7 +42,7 @@
</a-collapse>
<a-empty v-else></a-empty>
</a-collapse-item>
<a-collapse-item header="Team" key="team">
<a-collapse-item :header="$t('util.team')" key="team">
<a-collapse style="width: 100%" v-if="teamInfoList.length>0" :bordered="false">
<a-collapse-item v-for="(value,key) in messageList.teams" :key="key">
<template #header>

View File

@ -33,8 +33,8 @@
</a-badge>
</div>
<template #content>
<a-doption @click="onProfile(item)">Profile</a-doption>
<a-doption @click="onClose(item,index)">Close</a-doption>
<a-doption @click="onProfile(item)">{{$t("util.profile")}}</a-doption>
<a-doption @click="onClose(item,index)">{{$t("util.close")}}</a-doption>
</template>
</a-dropdown>
</a-menu-item>

View File

@ -1,18 +1,18 @@
<template>
<a-form auto-label-width :model="form" ref="formEle">
<a-form-item field="name" label="name" required>
<a-form-item field="name" :label="$t('util.name')" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item field="description" label="description">
<a-form-item field="description" :label="$t('util.description')">
<a-textarea v-model="form.description" allow-clear></a-textarea>
</a-form-item>
<a-form-item field="startTime" label="start date" required>
<a-form-item field="startTime" :label="$t('util.startDate')" required>
<a-date-picker show-time v-model="form.startTime"></a-date-picker>
</a-form-item>
<a-form-item field="endTime" label="end date" required>
<a-form-item field="endTime" :label="$t('util.endDate')" required>
<a-date-picker show-time v-model="form.endTime"></a-date-picker>
</a-form-item>
<a-form-item field="password" label="password" required>
<a-form-item field="password" :label="$t('util.password')" required>
<a-input v-model="form.password"></a-input>
</a-form-item>
</a-form>

View File

@ -4,22 +4,22 @@
<a-row style="height: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center">
<a-dropdown class="startMeeting" trigger="hover" position="top">
<a-button size="large" type="primary" style="width: 300px" status="success" @click="onStartMeeting">
Start Meeting
{{$t("controller.app.meeting.meeting.startMeeting")}}
</a-button>
<template #content>
<a-doption @click="onPersonalMeetingSetting">Person Meeting Setting</a-doption>
<a-doption @click="onPersonalMeetingSetting">{{$t("controller.app.meeting.meeting.personMeetingSetting")}}</a-doption>
</template>
</a-dropdown>
<a-button size="large" type="primary" style="margin-top: 30px;width: 300px" status="warning" @click="onJoinMeeting">Join Meeting</a-button>
<a-button size="large" type="primary" style="margin-top: 30px;width: 300px" @click="onScheduleMeeting">Schedule Meeting</a-button>
<a-button size="large" type="primary" style="margin-top: 30px;width: 300px" status="warning" @click="onJoinMeeting">{{$t("controller.app.meeting.meeting.joinMeeting")}}</a-button>
<a-button size="large" type="primary" style="margin-top: 30px;width: 300px" @click="onScheduleMeeting">{{$t("controller.app.meeting.meeting.scheduleMeeting")}}</a-button>
</a-row>
</a-layout-content>
<a-layout-sider :resize-directions="['left']" :width="300">
<a-row style="height: 100%;width: 100%;padding: 5px;box-sizing: border-box">
<a-row style="height: 30px;width: 100%;">
<a-space>
Meeting List:
<a-input-search search-button placeholder="type meeting name" size="mini" @search="onSearch" v-model="keyword"></a-input-search>
{{$t("controller.app.meeting.meeting.meetingList")}}:
<a-input-search search-button :placeholder="$t('placeholder.typeMeetingName')" size="mini" @search="onSearch" v-model="keyword"></a-input-search>
</a-space>
</a-row>
<a-row style="height: calc(100% - 30px);width: 100%;border-top: 1px solid lightgray;overflow-y: auto;flex-direction: column">
@ -40,12 +40,14 @@
</template>
</a-list-item-meta>
<template #actions>
<icon-video-camera style="color: red" @click="onStartScheduleMeeting(item)"></icon-video-camera>
<template v-if="item.type===ECommon_Model_Meeting_Room_Type.SCHEDULE">
<icon-edit @click="onEditMeeting(item)"></icon-edit>
<icon-delete @click="onDeleteMeeting(item)"></icon-delete>
</template>
<icon-calendar style="color: cornflowerblue" v-else-if="item.type===ECommon_Model_Meeting_Room_Type.CALENDAR" @click="onCalendarEvent(item)"></icon-calendar>
<a-space style="height: 100%">
<icon-video-camera style="color: red" @click="onStartScheduleMeeting(item)"></icon-video-camera>
<template v-if="item.type===ECommon_Model_Meeting_Room_Type.SCHEDULE">
<icon-edit @click="onEditMeeting(item)"></icon-edit>
<icon-delete style="color: red" @click="onDeleteMeeting(item)"></icon-delete>
</template>
<icon-calendar style="color: cornflowerblue" v-else-if="item.type===ECommon_Model_Meeting_Room_Type.CALENDAR" @click="onCalendarEvent(item)"></icon-calendar>
</a-space>
</template>
</a-list-item>
</a-list>
@ -76,9 +78,9 @@ import MeetingJoinInput from "./meetingJoinInput.vue";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../common/event/event";
import {useDesktopStore} from "../../desktop/store/desktop";
import {ECommon_User_Online_Status} from "../../../../../../common/types";
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../common/model/finder_item";
import {vDrag} from "../../../../teamOS/common/directive/drag";
import {ECommon_Model_Organization_Member_Type} from "../../../../../../common/model/organization";
import {useI18n} from "vue-i18n";
const props=defineProps<{
meetingInitInfo?:{
@ -93,6 +95,7 @@ const props=defineProps<{
const store=useDesktopStore()
const appContext=getCurrentInstance().appContext
const root=getRootNavigatorRef()
const {t}=useI18n()
const roomList=ref<DCSType<ICommon_Model_Meeting_Room>[]>([])
const pagination=reactive({
total:0,
@ -147,13 +150,13 @@ const onEditMeeting=async (item:DCSType<ICommon_Model_Meeting_Room>)=>{
}
const onDeleteMeeting=async (item:DCSType<ICommon_Model_Meeting_Room>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this meeting?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteMeeting"))
if(ret) {
let res=await apiMeeting.deleteRoom({
meetingRoomId:item.id
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
getMeetingList(pagination.current)
}
}

View File

@ -1,9 +1,9 @@
<template>
<a-form auto-label-width :model="form" ref="formEle">
<a-form-item field="id" label="meeting id" required>
<a-form-item field="id" :label="$t('util.meetingId')" required>
<a-input v-model="form.id"></a-input>
</a-form-item>
<a-form-item field="password" label="meeting password" required>
<a-form-item field="password" :label="$t('util.meetingPassword')" required>
<a-input v-model="form.password"></a-input>
</a-form-item>
</a-form>

View File

@ -22,7 +22,7 @@
</template>
</a-button>
<template #content>
<a-descriptions title="Meeting Info" :data="[
<a-descriptions :title="$t('controller.app.meeting.meetingOperation.meetingInfo')" :data="[
{
label:'Meeting Id',
value:currentMeeting.id
@ -34,9 +34,9 @@
]" v-if="currentMeeting"></a-descriptions>
<a-divider :margin="10"></a-divider>
<a-form :model="form" auto-label-width>
<a-form-item field="memberIds" label="Users" required>
<a-select style="width: 100%" placeholder="type user or team" multiple allow-search allow-clear v-model="form.memberIds" @search="onSearch">
<a-optgroup label="Team" v-if="selectList && selectList.teams && selectList.teams.length>0">
<a-form-item field="memberIds" :label="$t('util.users')" required>
<a-select style="width: 100%" :placeholder="$t('placeholder.typeUserOrTeam')" multiple allow-search allow-clear v-model="form.memberIds" @search="onSearch">
<a-optgroup :label="$t('util.team')" v-if="selectList && selectList.teams && selectList.teams.length>0">
<a-option v-for="item in selectList.teams" :value="item.id">
<a-row style="align-items: center">
<a-avatar :image-url="item.photo" :size="24"></a-avatar>&nbsp;
@ -44,7 +44,7 @@
</a-row>
</a-option>
</a-optgroup>
<a-optgroup label="User" v-if="selectList && selectList.users && selectList.users.length>0">
<a-optgroup :label="$t('util.user')" v-if="selectList && selectList.users && selectList.users.length>0">
<a-option v-for="item in selectList.users" :value="item.id">
<a-row style="align-items: center">
<a-avatar :image-url="item.photo" :size="24"></a-avatar>&nbsp;
@ -55,7 +55,7 @@
</a-select>
</a-form-item>
<a-form-item>
<a-button html-type="button" type="primary" @click="onInvite">Invite</a-button>
<a-button html-type="button" type="primary" @click="onInvite">{{$t("util.invite")}}</a-button>
</a-form-item>
</a-form>
</template>
@ -69,10 +69,10 @@
</a-space>
<a-space>
<a-button size="mini" type="primary" @click="onLeave">
Leave
{{$t("util.leave")}}
</a-button>
<a-button size="mini" type="primary" status="danger" v-if="me?.permission===ECommon_Meeting_Room_Permission.PRESENTER" @click="onEnd">
End
{{$t("util.end")}}
</a-button>
</a-space>
</a-row>
@ -92,6 +92,7 @@ import {SocketIOClient} from "../../../common/socket/socket";
import {ECommon_Socket_Type} from "../../../../../../common/socket/types";
import {ICommon_Route_Res_Organization_FilterUserAndTeam} from "../../../../../../common/routes/response";
import {ECommon_Model_Organization_Member_Type} from "../../../../../../common/model/organization";
import {useI18n} from "vue-i18n";
const props=defineProps<{
me:OrganizationUserItem,
@ -107,6 +108,7 @@ const root=getRootNavigatorRef()
const appContext=getCurrentInstance().appContext
const socket=SocketIOClient.getSocket(ECommon_Socket_Type.MEETING).getSocket()
let isScreen=ref(false)
const {t}=useI18n()
props.meetingClient.onScreenStopped=() => {
isScreen.value=false
}
@ -131,7 +133,7 @@ const onToggleVideo=()=>{
}
const onLeave=async ()=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you leave this meeting?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.leaveMeeting"))
if(ret) {
await props.meetingClient.leave()
navigator.pop()
@ -139,13 +141,13 @@ const onLeave=async ()=>{
}
const onEnd=async ()=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you end this meeting?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.endMeeting"))
if(ret) {
let res=await props.meetingClient.end()
if(res) {
navigator.pop()
} else {
Message.error("operation failed")
Message.error(t("tip.operationFailed"))
}
}
}
@ -179,7 +181,7 @@ const onToggleScreen=async ()=>{
if(!isScreen.value) {
let ret=await props.meetingClient.startShare()
if(ret===false) {
Message.error("can't share now")
Message.error(t("tip.cannotShare"))
} else if(ret===true) {
isScreen.value=true
}

View File

@ -26,7 +26,7 @@
</a-button>
<a-button size="mini" type="text" v-if="me.permission===ECommon_Meeting_Room_Permission.PRESENTER" @click="onTogglePresenter(item)">
<template #icon>
<sicon size="15" color="rgb(22, 93, 255)" name="Ant" type="admin" v-if="item.permission===ECommon_Meeting_Room_Permission.PRESENTER" title="presenter"></sicon>
<sicon size="15" color="rgb(22, 93, 255)" name="Ant" type="admin" v-if="item.permission===ECommon_Meeting_Room_Permission.PRESENTER" :title="$t('controller.app.meeting.meetingParticipant.presenter')"></sicon>
<sicon size="15" color="gray" name="Ant" type="user" v-else></sicon>
</template>
</a-button>
@ -34,7 +34,7 @@
<template #actions v-else>
<a-button size="mini" type="text" :disabled="true">
<template #icon>
<sicon size="15" color="rgb(22, 93, 255)" name="Ant" type="admin" v-if="me.permission===ECommon_Meeting_Room_Permission.PRESENTER" title="presenter"></sicon>
<sicon size="15" color="rgb(22, 93, 255)" name="Ant" type="admin" v-if="me.permission===ECommon_Meeting_Room_Permission.PRESENTER" :title="$t('controller.app.meeting.meetingParticipant.presenter')"></sicon>
<sicon size="15" color="gray" name="Ant" type="user" v-else></sicon>
</template>
</a-button>
@ -54,6 +54,7 @@ import {getCurrentInstance} from "vue";
import {MeetingClient} from "../../../common/component/meeting/client";
import {SocketIOClient} from "../../../common/socket/socket";
import {ECommon_Socket_Type} from "../../../../../../common/socket/types";
import {useI18n} from "vue-i18n";
const props=defineProps<{
organizationUserList:OrganizationUserItem[],
@ -64,9 +65,10 @@ const myOrganizationUserId=SessionStorage.get("organizationUserId")
const navigator=getCurrentNavigator()
const root=getRootNavigatorRef()
const appContext=getCurrentInstance().appContext
const {t}=useI18n()
const socket=SocketIOClient.getSocket(ECommon_Socket_Type.MEETING).getSocket()
const onKick=async (item:OrganizationUserItem)=>{
let ret=await Dialog.confirm(root.value,appContext,`Do you want to kick ${item.name}?`)
let ret=await Dialog.confirm(root.value,appContext,`${t("tip.kick")}${item.name}?`)
if(ret) {
props.meetingClient.kick(item.organizationUserId)
}
@ -74,7 +76,7 @@ const onKick=async (item:OrganizationUserItem)=>{
const onTogglePresenter=async (item:OrganizationUserItem)=>{
let promote=item.permission===ECommon_Meeting_Room_Permission.NORMAL;
let ret=await Dialog.confirm(root.value,appContext,`Do you want to ${promote?`promote ${item.name} to presenter`:`demote ${item.name} to normal member`}?`)
let ret=await Dialog.confirm(root.value,appContext,`${t("tip.doYouWant")}${promote?`${t("tip.promote")}${item.name}${t("tip.toPresenter")}`:`${t("tip.demote")}${item.name}${t("tip.toNormalMember")}`}?`)
if(ret) {
if(promote) {
let ret=await socket.emitWithAck("meeting_change_presenter",item.organizationUserId,ECommon_Meeting_Room_Permission.PRESENTER)

View File

@ -1,8 +1,8 @@
<template>
<a-form :model="form" ref="formEle" auto-label-width>
<a-form-item field="cameraId" label="select camera">
<a-form-item field="cameraId" :label="$t('util.selectCamera')">
<div style="width: 80%">
<a-select v-model="form.cameraId" placeholder="if you don't choose,we will pick up default">
<a-select v-model="form.cameraId" :placeholder="$t('placeholder.meetingPreview')">
<a-option v-for="item in cameraList" :value="item.id">{{item.name}}</a-option>
</a-select>
<div style="width: 100%;margin-top: 10px">
@ -10,10 +10,10 @@
</div>
</div>
</a-form-item>
<a-form-item field="enableVideo" label="video on">
<a-form-item field="enableVideo" :label="$t('util.videoOn')">
<a-switch v-model="form.enableVideo"></a-switch>
</a-form-item>
<a-form-item field="enableAudio" label="audio on">
<a-form-item field="enableAudio" :label="$t('util.audioOn')">
<a-switch v-model="form.enableAudio"></a-switch>
</a-form-item>
</a-form>

View File

@ -41,13 +41,13 @@
</a-layout-content>
<a-layout-sider :resize-directions="['left']" :width="250" id="meetingRight">
<a-tabs size="mini" v-model:active-key="tabValue" style="height: 100%">
<a-tab-pane title="participant" key="participant">
<a-tab-pane :title="$t('util.participant')" key="participant">
<MeetingParticipant :organization-user-list="organizationUserList" :me="me" :meeting-client="meetingClient"></MeetingParticipant>
</a-tab-pane>
<a-tab-pane key="chat">
<template #title>
<a-badge dot :count="unReadCount" :offset="[6,0]">
chat
{{$t("controller.app.meeting.meetingProfile.chat")}}
</a-badge>
</template>
<MeetingChat :meeting-client="meetingClient" @new-message="onNewMessage" ref="meetingChat"></MeetingChat>

View File

@ -1,10 +1,10 @@
<template>
<a-form :model="form" auto-label-width ref="formEle">
<a-form-item field="id" label="meeting id">
<a-form-item field="id" :label="$t('util.meetingId')">
{{form.id}}
</a-form-item>
<a-form-item field="password" label="meeting password" required>
<a-form-item field="password" :label="$t('util.meetingPassword')" required>
<a-input v-model="form.password"></a-input>
</a-form-item>
</a-form>

View File

@ -1,7 +1,7 @@
<template>
<div style="padding: 10px 20px">
<a-row>
<a-input-search placeholder="please type name" style="width: 400px" v-model="keyword" @search="onSearch"></a-input-search>
<a-input-search :placeholder="$t('placeholder.typeName')" style="width: 400px" v-model="keyword" @search="onSearch"></a-input-search>
</a-row>
<a-space wrap style="margin-top: 20px" size="large">
<CardItem v-for="item in userList" :name="item.organizationUser.nickname" :photo="item.user.photo" :description="item.organizationUser.job" @click="showProfile(item.organizationUser)"></CardItem>

View File

@ -67,7 +67,7 @@
</a-layout-sider>
<a-layout-content style="padding: 0px 10px">
<h3>
Recent Teams
{{$t("controller.app.people.peopleProfile.recentTeams")}}
</h3>
<a-list>
<a-list-item v-for="item in info.teamList" :key="item.id">
@ -78,15 +78,15 @@
</a-list-item-meta>
<template #actions>
<template v-if="organizationUserId===myOrganizationUserId">
<a-button type="outline" size="small" @click="onTeamProfile(item.id)">Profile</a-button>
<a-button type="outline" size="small" @click="onTeamProfile(item.id)">{{$t("util.profile")}}</a-button>
</template>
<template v-else>
<a-button type="outline" size="small" style="margin-left: 20px" @click="onTeamProfile(item.id)">Profile</a-button>
<a-button type="outline" size="small" style="margin-left: 20px" @click="onTeamProfile(item.id)">{{$t("util.profile")}}</a-button>
<a-button type="outline" size="small" style="margin-left: 20px;margin-top: 10px" @click="onMessage">
<template #icon>
<icon-message></icon-message>
</template>
Message
{{$t("util.message")}}
</a-button>
</template>
</template>

View File

@ -1,6 +1,6 @@
<template>
<a-form :model="form" ref="eleForm">
<a-form-item label="Issue Type" field="issueTypeIds" required>
<a-form-item :label="$t('util.issueType')" field="issueTypeIds" required>
<a-select v-model="form.issueTypeIds" multiple>
<a-option v-for="item in issueTypeList" :value="item.id" :label="item.name"></a-option>
</a-select>
@ -15,6 +15,7 @@ import {ICommon_Model_Issue_Type} from "../../../../../../../common/model/issue_
import {onDialogOk} from "@/business/common/component/dialog/dialog";
import {dialogFuncGenerator} from "@/business/common/util/helper";
import {Message} from "@arco-design/web-vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
boardId:string,
@ -22,6 +23,7 @@ const props=defineProps<{
const form=reactive({
issueTypeIds:[]
})
const {t}=useI18n()
const eleForm=ref(null)
const issueTypeList=ref<DCSType<ICommon_Model_Issue_Type>[]>([])
@ -41,7 +43,7 @@ onBeforeMount(()=>{
onDialogOk(dialogFuncGenerator({
func:()=>{
if(issueTypeList.value.length==0) {
Message.error("issue type can not be empty!")
Message.error(t("tip.issueTypeCannotBeEmpty"))
return false
}
return Promise.all(issueTypeList.value.map(item=>{

View File

@ -2,7 +2,7 @@
<div style="width: 100%;height: 100%">
<a-row style="width: 100%;height: 30px;padding-left: 10px">
<a-button type="primary" size="small" @click="onAddColumn">
Add Column
{{$t("controller.app.project.board.boardConfig.addColumn")}}
</a-button>
</a-row>
<div style="width: 100%;margin-top: 20px;overflow: auto;height: calc(100% - 90px)">
@ -40,7 +40,7 @@
</template>
<template #pinHeader>
<a-row style="height: 100%;display: flex;align-items: center;justify-content: space-between;padding: 0 5px;box-sizing: border-box;">
<span style="color: grey">Issue Type</span>
<span style="color: grey">{{$t("util.issueType")}}</span>
<a-space size="mini">
<a-button type="text" size="mini" @click="onAddIssueType">
<template #icon>
@ -88,6 +88,7 @@ import {ICommon_Route_Res_Board_Column_Workflow_Node_Item} from "../../../../../
import {Dialog} from "@/business/common/component/dialog/dialog";
import {getRootNavigatorRef} from "@/teamOS/common/component/navigator/navigator";
import BoardAddIssueType from "@/business/controller/app/project/board/boardAddIssueType.vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
boardId:string
@ -95,6 +96,7 @@ const props=defineProps<{
const root=getRootNavigatorRef()
const appContext=getCurrentInstance().appContext
const issueTypeList=ref<DCSType<ICommon_Model_Issue_Type>[]>([])
const {t}=useI18n()
const workflowUnSetNodeMap=ref<{
[issueTypeId:string]:ICommon_Model_Workflow_Node[]
}>()
@ -317,7 +319,7 @@ const onColumnChange=async (id:string,index:number)=>{
}
const onEditColumn=async (id:string,name:string)=>{
let ret=await Dialog.input(root.value,appContext,"Edit Column Name",name)
let ret=await Dialog.input(root.value,appContext,t("tip.editColumnName"),name)
if(ret) {
let res=await apiBoard.editColumn({
boardColumnId:id,
@ -332,7 +334,7 @@ const onEditColumn=async (id:string,name:string)=>{
}
const onDeleteColumn=async (id:string)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete column?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteColumn"))
if(ret) {
let res=await apiBoard.deleteColumn({
boardColumnId:id
@ -349,7 +351,7 @@ const onDeleteColumn=async (id:string)=>{
}
const onAddColumn=async ()=>{
let ret=await Dialog.input(root.value,appContext,"New Column Title")
let ret=await Dialog.input(root.value,appContext,t("tip.newColumnTitle"))
if(ret) {
let res=await apiBoard.addColumn({
name:ret,
@ -367,7 +369,7 @@ const onAddColumn=async ()=>{
}
const onDeleteIssueType=async (item:DCSType<ICommon_Model_Issue_Type>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this issue type?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.removeIssueType"))
if(ret) {
let res=await apiBoard.unbindIssueType({
boardId:props.boardId,

View File

@ -1,12 +1,12 @@
<template>
<a-form :model="form" ref="eleForm">
<a-form-item label="name" field="name" required>
<a-form-item :label="$t('util.name')" field="name" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="description" field="description">
<a-form-item :label="$t('util.description')" field="description">
<a-textarea v-model="form.description" allow-clear></a-textarea>
</a-form-item>
<a-form-item label="Issue Type" field="issueTypeIds" v-if="type=='add'">
<a-form-item :label="$t('util.issueType')" field="issueTypeIds" v-if="type=='add'">
<a-select v-model="form.issueTypeIds" multiple>
<a-option v-for="item in issueTypeList" :value="item.id" :label="item.name"></a-option>
</a-select>

View File

@ -1,13 +1,13 @@
<template>
<div style="padding: 0 10px">
<a-form :model="form" ref="eleForm" auto-label-width>
<a-form-item label="Action" field="actionId" required>
<a-form-item :label="$t('util.action')" field="actionId" required>
<a-select v-model="form.actionId" @change="onChange">
<a-option v-for="item in workflowActionList" :label="item.name" :value="item.id"></a-option>
</a-select>
</a-form-item>
<a-divider orientation="left" v-if="valueList.length>0">
Fields
{{$t("util.fields")}}
</a-divider>
<a-form-item v-for="value in valueList" :key="value.field.id" :label="value.field.name" :extra="value.field.description" :field="value.field.name" :required="!value.field.optional">
<FieldInput :item="value" :project-id="projectId"></FieldInput>

View File

@ -6,7 +6,7 @@
<a-option v-for="item in sprintList" :label="item.name" :value="item.id"></a-option>
</a-select>
<a-button type="primary" size="small" @click="onGo">
Go
{{$t("util.go")}}
</a-button>
</a-space>
</a-row>
@ -61,9 +61,9 @@
<template #pinHeader>
<a-row style="height: 100%;display: flex;align-items: center;justify-content: space-between;padding: 0 5px;box-sizing: border-box;">
<a-space>
<span style="color: grey">Swim Lane</span>
<span style="color: grey">{{$t("util.swimLane")}}</span>
<span :style="{color: sprintInfo.status!==ECommon_Model_Board_Sprint_Status.COMPLETED?'dodgerblue':'rgb(0,180,42)'}">
({{sprintInfo.status===ECommon_Model_Board_Sprint_Status.NOTSTART?"Not Start":sprintInfo.status===ECommon_Model_Board_Sprint_Status.STARTING?"Starting":"Completed"}})
({{sprintInfo.status===ECommon_Model_Board_Sprint_Status.NOTSTART?$t("util.notStart"):sprintInfo.status===ECommon_Model_Board_Sprint_Status.STARTING?$t("util.starting"):$t("util.completed")}})
</span>
</a-space>
<a-button size="mini" type="text" @click="onAddSwimLane" v-if="sprintInfo.status!==ECommon_Model_Board_Sprint_Status.COMPLETED">
@ -143,6 +143,7 @@ import ProjectIssueNext from "@/business/controller/app/project/issue/projectIss
import {EClient_EVENTBUS_TYPE, eventBus} from "@/business/common/event/event";
import {ECommon_Model_Workflow_Node_Status} from "../../../../../../../common/model/workflow_node";
import {ECommon_Model_Project_Issue_Approval_Type} from "../../../../../../../common/model/project_issue_approval";
import {useI18n} from "vue-i18n";
moment;
const props=defineProps<{
@ -154,6 +155,7 @@ const appContext=getCurrentInstance().appContext
const sprintId=ref("")
const sprintList=ref<DCSType<ICommon_Model_Board_Sprint>[]>([])
const sprintInfo=ref<DCSType<ICommon_Route_Res_Board_Sprint_Info>>()
const {t}=useI18n()
const cardData=ref<{
id:string,
name:string,
@ -196,7 +198,7 @@ const onSearch=async (keyword:string)=>{
const onGo=async ()=>{
if(!sprintId.value) {
Message.error("you should select a sprint!")
Message.error(t("tip.selectSprint"))
return
}
let [resSprintInfo,resListColumn]=await Promise.all([
@ -331,7 +333,7 @@ const onEditSwimLane=async (item:DCSType<ICommon_Model_Board_Sprint_SwimLane>)=>
}
const onDeleteSwimLane=async (item:DCSType<ICommon_Model_Board_Sprint_SwimLane>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this swim lane?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteSwimLane"))
if(ret) {
let res=await apiBoard.deleteSwimLane({
boardSprintSwimLaneId:item.id
@ -457,7 +459,7 @@ const onDrop=async (item:DCSType<ICommon_Model_Board_Sprint_SwimLane>,columnId:s
}
}
} else if(nextActionList.length==0) {
Message.error("this issue can not move to this column!")
Message.error(t("tip.notMoveToColumn"))
}
}
}
@ -520,7 +522,7 @@ const onAction=async (projectIssueId:string,item:ICommon_Model_Workflow_Action |
return
}
} else if(item.name==="Reject") {
let ret=await Dialog.inputRich(root.value,appContext,"Reject Reason")
let ret=await Dialog.inputRich(root.value,appContext,t("tip.rejectReason"))
if(ret) {
let res=await apiIssue.rejectApproval({
projectIssueId:projectIssueId,

View File

@ -2,8 +2,8 @@
<div>
<a-row>
<a-space wrap>
<a-input-search v-model="keyword" placeholder="please type board name" style="width: 250px" @search="onSearch"></a-input-search>
<a-button type="primary" @click="onCreate" v-if="checkPermission(permission,Permission_Types.Project.EDIT)">Create</a-button>
<a-input-search v-model="keyword" :placeholder="$t('placeholder.typeBoardName')" style="width: 250px" @search="onSearch"></a-input-search>
<a-button type="primary" @click="onCreate" v-if="checkPermission(permission,Permission_Types.Project.EDIT)">{{$t("util.create")}}</a-button>
</a-space>
</a-row>
<a-table style="margin-top: 10px" :columns="columns" :data="boardList" :pagination="pagination" @pageChange="onPageChange">
@ -15,8 +15,8 @@
</template>
<template #operation="{record}">
<a-space v-if="checkPermission(permission,Permission_Types.Project.EDIT)" wrap>
<a-button size="small" @click="onEdit(record)">Edit</a-button>
<a-button size="small" status="danger" @click="onDelete(record)">Delete</a-button>
<a-button size="small" @click="onEdit(record)">{{$t("util.edit")}}</a-button>
<a-button size="small" status="danger" @click="onDelete(record)">{{$t("util.delete")}}</a-button>
</a-space>
</template>
</a-table>
@ -38,22 +38,24 @@ import {
import {Message} from "@arco-design/web-vue";
import {ICommon_Model_Board} from "../../../../../../../common/model/board";
import BoardEdit from "@/business/controller/app/project/board/boardEdit.vue";
import {useI18n} from "vue-i18n";
const objInject=inject(injectProjectInfo)
const projectId=objInject.id
const permission=objInject.permission
const key=objInject.key
const {t}=useI18n()
const columns=[
{
title:"Name",
title:t("util.name"),
slotName:"name"
},
{
title:"Description",
title:t("util.description"),
slotName: "description"
},
{
title:"Operation",
title:t("util.operation"),
slotName: "operation"
}
]
@ -106,13 +108,13 @@ const onEdit=async (item:DCSType<ICommon_Model_Board>)=>{
}
}
const onDelete=async (item:DCSType<ICommon_Model_Board>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this board?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteBoard"))
if(ret) {
let res=await apiBoard.deleteBoard({
boardId:item.id
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
search(pagination.current)
}
}

View File

@ -3,20 +3,20 @@
<a-row style="width: 100%;font-size: 30px;align-items: center;justify-content: space-between;padding: 0px 10px;box-sizing: border-box;height: 35px">
{{info?.name}}
<a-button type="primary" size="small" @click="onEdit">
Edit
{{$t("util.edit")}}
</a-button>
</a-row>
<a-row style="width: 100%;margin-top: 20px;padding:0px 10px;box-sizing: border-box;height: 20px">
{{info?.description}}
</a-row>
<a-tabs style="width: 100%;margin-top: 20px;height: calc(100% - 95px);" @scroll="$event.currentTarget.scrollTop=0" :default-active-key="boardSprintId?'kanban':'sprint'">
<a-tab-pane key="sprint" title="Sprint">
<a-tab-pane key="sprint" :title="$t('util.sprint')">
<BoardSprintList :board-id="boardId"></BoardSprintList>
</a-tab-pane>
<a-tab-pane key="kanban" title="Kanban">
<a-tab-pane key="kanban" :title="$t('util.kanban')">
<BoardKanban :board-id="boardId" :board-sprint-id="boardSprintId"></BoardKanban>
</a-tab-pane>
<a-tab-pane key="config" title="Config">
<a-tab-pane key="config" :title="$t('util.config')">
<BoardConfig :board-id="boardId"></BoardConfig>
</a-tab-pane>
</a-tabs>

View File

@ -1,13 +1,13 @@
<template>
<a-form :model="form" ref="eleForm" auto-label-width>
<a-form-item label="Issue Types">
<a-form-item :label="$t('util.issueTypes')">
<a-space>
<a-tag v-for="item in issueTypeList">
{{item.name}}
</a-tag>
</a-space>
</a-form-item>
<a-form-item field="issues" label="Issues" required>
<a-form-item field="issues" :label="$t('util.issues')" required>
<a-select multiple allow-search v-model="form.issues" @search="onSearch">
<a-option v-for="item in issueList" :value="item.id">
{{item.project.keyword}}-{{item.unique_id}}&nbsp;{{item.name}}
@ -25,6 +25,7 @@ import {ICommon_Route_Res_Project_Issue_filter_Item} from "../../../../../../../
import {onDialogOk} from "@/business/common/component/dialog/dialog";
import {dialogFuncGenerator} from "@/business/common/util/helper";
import {Message} from "@arco-design/web-vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
boardSprintId:string,
@ -35,6 +36,7 @@ const form=reactive({
issues:[]
})
const eleForm=ref()
const {t}=useI18n()
const issueTypeList=ref<DCSType<ICommon_Model_Issue_Type>[]>([])
const issueList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item>[]>([])
const getIssueTypeList=async ()=>{
@ -69,7 +71,7 @@ onDialogOk(dialogFuncGenerator({
},
func:()=>{
if(form.issues.length==0) {
Message.error("issue should not be empty")
Message.error(t("tip.issueShouldNotBeEmpty"))
return false
}
return apiBoard.addSprintIssues({

View File

@ -1,10 +1,10 @@
<template>
<a-form :model="form" ref="eleForm">
<a-form-item label="name" field="name" required>
<a-form-item :label="$t('util.name')" field="name" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="dateRange" field="dateRange" required>
<a-range-picker v-model="form.dateRange" :placeholder="['Start Date','End Date']"></a-range-picker>
<a-form-item :label="$t('util.dateRange')" field="dateRange" required>
<a-range-picker v-model="form.dateRange" :placeholder="[$t('util.startDate'),$t('util.endDate')]"></a-range-picker>
</a-form-item>
</a-form>
</template>

View File

@ -2,14 +2,14 @@
<div>
<a-row style="width: 100%;">
<a-space>
Status:
{{$t("util.status")}}:
<a-select size="small" style="width: 100px;" v-model="status">
<a-option :value="-1">All</a-option>
<a-option :value="ECommon_Model_Board_Sprint_Status.NOTSTART">Not Start</a-option>
<a-option :value="ECommon_Model_Board_Sprint_Status.STARTING">Starting</a-option>
<a-option :value="ECommon_Model_Board_Sprint_Status.COMPLETED">Completed</a-option>
<a-option :value="-1">{{$t("util.all")}}</a-option>
<a-option :value="ECommon_Model_Board_Sprint_Status.NOTSTART">{{$t("controller.app.project.board.boardSprintList.notStart")}}</a-option>
<a-option :value="ECommon_Model_Board_Sprint_Status.STARTING">{{$t("controller.app.project.board.boardSprintList.starting")}}</a-option>
<a-option :value="ECommon_Model_Board_Sprint_Status.COMPLETED">{{$t("controller.app.project.board.boardSprintList.completed")}}</a-option>
</a-select>
<a-input-search size="small" style="width: 300px" v-model="keyword" @search="onSearch" search-button placeholder="please type sprint name"></a-input-search>
<a-input-search size="small" style="width: 300px" v-model="keyword" @search="onSearch" search-button :placeholder="$t('placeholder.typeSprintName')"></a-input-search>
<a-button size="small" type="primary" @click="onCreate">
Create
</a-button>
@ -33,10 +33,10 @@
</a-button>
<template #content>
<a-doption size="mini" type="primary" status="success" @click="onStartSprint(item,$event)" v-if="item.status!==ECommon_Model_Board_Sprint_Status.STARTING">
Start
{{$t("util.start")}}
</a-doption>
<a-doption size="mini" type="outline" status="success" @click="onCompleteSprint(item,$event)" v-else>
Complete
{{$t("util.complete")}}
</a-doption>
</template>
</a-dropdown>
@ -96,6 +96,7 @@ import {injectProjectInfo} from "@/business/common/util/symbol";
import BoardSprintAddIssue from "@/business/controller/app/project/board/boardSprintAddIssue.vue";
import {EClient_EVENTBUS_TYPE, eventBus} from "@/business/common/event/event";
import FieldPriority from "@/business/common/component/field/fieldPriority.vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
boardId:string
@ -115,6 +116,7 @@ const loading=ref(false)
const objInject=inject(injectProjectInfo)
const projectId=objInject.id
const key=objInject.key
const {t}=useI18n()
const search=async (page:number)=>{
let res=await apiBoard.listSprint({
boardId:props.boardId,
@ -193,7 +195,7 @@ const onEdit=async (item:DCSType<ICommon_Model_Board_Sprint>,event:MouseEvent)=>
const onDelete=async (item:DCSType<ICommon_Model_Board_Sprint>,event:MouseEvent)=>{
event.stopPropagation()
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this sprint?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteSprint"))
if(ret) {
let res=await apiBoard.deleteSprint({
boardSprintId:item.id
@ -206,7 +208,7 @@ const onDelete=async (item:DCSType<ICommon_Model_Board_Sprint>,event:MouseEvent)
const onStartSprint=async (item:DCSType<ICommon_Model_Board_Sprint>,event:MouseEvent)=>{
event.stopPropagation()
let ret=await Dialog.confirm(root.value,appContext,"Do you want to start this sprint?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.startSprint"))
if(ret) {
let res=await apiBoard.startSprint({
boardSprintId:item.id
@ -219,7 +221,7 @@ const onStartSprint=async (item:DCSType<ICommon_Model_Board_Sprint>,event:MouseE
const onCompleteSprint=async (item:DCSType<ICommon_Model_Board_Sprint>,event:MouseEvent)=>{
event.stopPropagation()
let ret=await Dialog.confirm(root.value,appContext,"Do you want to complete this sprint?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.completeSprint"))
if(ret) {
let res=await apiBoard.completeSprint({
boardSprintId:item.id
@ -231,7 +233,7 @@ const onCompleteSprint=async (item:DCSType<ICommon_Model_Board_Sprint>,event:Mou
}
const onRemoveIssue=async (issue:DCSType<ICommon_Route_Res_Board_Sprint_Issue_Item>,sprint:DCSType<ICommon_Model_Board_Sprint>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove this issue from this sprint?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.removeIssueFromSprint"))
if(ret) {
let res=await apiBoard.removeProjectIssue({
projectIssueId:issue.id

View File

@ -6,7 +6,7 @@
<a-row style="width: 100%;align-items: center">
{{info?.name}}&nbsp;&nbsp;
<span :style="{color: info?.status!==ECommon_Model_Board_Sprint_Status.COMPLETED?'dodgerblue':'rgb(0,180,42)'}">
{{info?.status===ECommon_Model_Board_Sprint_Status.NOTSTART?"Not Start":info?.status===ECommon_Model_Board_Sprint_Status.STARTING?"Starting":"Completed"}}
{{info?.status===ECommon_Model_Board_Sprint_Status.NOTSTART?$t("controller.app.project.board.boardSprintList.notStart"):info?.status===ECommon_Model_Board_Sprint_Status.STARTING?$t("controller.app.project.board.boardSprintList.starting"):$t("controller.app.project.board.boardSprintList.completed")}}
</span>
</a-row>
<a-row style="margin-top: 15px;">
@ -21,13 +21,13 @@
<a-row style="width: 100%;margin-top: 15px;justify-content: space-between;align-items: center">
<a-space style="color: dodgerblue">
<span>
Swim Lanes:{{info?.swimLanes.length}}
{{$t("controller.app.project.board.boardSprintList.swimLanes")}}:{{info?.swimLanes.length}}
</span>
<span>
Issues:{{info?.issues.length}}
{{$t("util.issues")}}:{{info?.issues.length}}
</span>
</a-space>
<a-button type="outline" size="mini" style="margin-left: 20px" @click="onProfile">Profile</a-button>
<a-button type="outline" size="mini" style="margin-left: 20px" @click="onProfile">{{$t("util.profile")}}</a-button>
</a-row>
</a-row>
</template>

View File

@ -1,6 +1,6 @@
<template>
<a-form :model="form" ref="eleForm" auto-label-width>
<a-form-item field="issues" label="Issues" required>
<a-form-item field="issues" :label="$t('util.issues')" required>
<a-select multiple allow-search v-model="form.issues" @search="onSearch">
<a-optgroup v-for="(_,swimLaneName) in optionMap" :label="swimLaneName">
<a-option v-for="item in optionMap[swimLaneName]" :value="item.id" :label="props.projectKey+'-'+item.unique_id">
@ -23,6 +23,7 @@ import {ICommon_Route_Res_Board_Sprint_Issue_Item} from "../../../../../../../co
import {onDialogOk} from "@/business/common/component/dialog/dialog";
import {dialogFuncGenerator} from "@/business/common/util/helper";
import {Message} from "@arco-design/web-vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
boardSprintSwimLaneId:string,
@ -34,6 +35,7 @@ const form=reactive({
issues:[]
})
const eleForm=ref()
const {t}=useI18n()
const issueMap=ref<{
[swimLaneName:string]:DCSType<ICommon_Route_Res_Board_Sprint_Issue_Item>[]
}>()
@ -87,7 +89,7 @@ onDialogOk(dialogFuncGenerator({
},
func:()=>{
if(form.issues.length==0) {
Message.error("issue should not be empty")
Message.error(t("tip.issueShouldNotBeEmpty"))
return false
}
return Promise.all(form.issues.map(item=>{

View File

@ -1,14 +1,14 @@
<template>
<a-form :model="form" ref="eleForm">
<a-form-item label="name" field="name" required>
<a-form-item :label="$t('util.name')" field="name" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="priority" field="priority" required>
<a-form-item :label="$t('util.priority')" field="priority" required>
<a-select v-model="form.priority">
<a-option :value="ECommon_Model_Project_Issue_Priority.LOW">Low</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.MEDIUM">MEDIUM</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.HIGH">HIGH</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.URGENT">URGENT</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.LOW">{{$t("util.low")}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.MEDIUM">{{$t("util.medium")}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.HIGH">{{$t("util.high")}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.URGENT">{{$t("util.urgent")}}</a-option>
</a-select>
</a-form-item>
</a-form>

View File

@ -26,16 +26,16 @@
<template #split>
|
</template>
<a-statistic title="Issue Total" :value="staticInfo?.issueCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.project.home.projectHome.issueTotal')" :value="staticInfo?.issueCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="UnResolved Issue Total" :value="staticInfo?.issueUnDoneCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.project.home.projectHome.unResolvedIssueTotal')" :value="staticInfo?.issueUnDoneCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="Release Total" :value="staticInfo?.releaseCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.project.home.projectHome.releaseTotal')" :value="staticInfo?.releaseCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="Sprint Total" :value="staticInfo?.sprintCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.project.home.projectHome.sprintTotal')" :value="staticInfo?.sprintCount" show-group-separator :value-style="{
color:'blue'
}"/>
</a-space>
@ -105,6 +105,7 @@ import FieldPriority from "@/business/common/component/field/fieldPriority.vue";
import {ICommon_Model_Project_Issue} from "../../../../../../../common/model/project_issue";
import {EClient_EVENTBUS_TYPE, eventBus} from "@/business/common/event/event";
import {ICommon_Model_Project_Release} from "../../../../../../../common/model/project_release";
import {useI18n} from "vue-i18n";
echarts.use([
TitleComponent,
@ -123,30 +124,31 @@ let userIssueListChart:EChartsType,userUnDoneIssueChart:EChartsType
const projectId=inject(injectProjectInfo).id
const key=inject(injectProjectInfo).key
const permission=inject(injectProjectInfo).permission
const {t}=useI18n()
const data = [
{
id: "statics",
name: "Statics",
name: t("controller.app.project.home.projectHome.statics"),
data: null
},
{
id: "myRecentIssueList",
name: "My Recent Working Issue List",
name: t("controller.app.project.home.projectHome.myRecentIssueList"),
data: null
},
{
id: "userIssueList",
name: "Users' Issue Chart",
name: t("controller.app.project.home.projectHome.userIssueList"),
data: null
},
{
id: "userUnDoneIssueList",
name: "User's UnResolved Issue Chart",
name: t("controller.app.project.home.projectHome.userUnDoneIssueList"),
data: null
},
{
id: "recentReleaseList",
name: "Recent Release List",
name: t("controller.app.project.home.projectHome.recentReleaseList"),
data: null
},
]
@ -174,6 +176,9 @@ const getProjectInfo=async ()=>{
const initCharts=()=>{
userIssueListChart=echarts.init(userIssueListEle.value)
userIssueListChart.setOption({
grid:{
left:60
},
dataset:{
source:[
["count","name"],
@ -189,7 +194,12 @@ const initCharts=()=>{
},
yAxis: {
name:"User",
type: 'category'
type: 'category',
axisLabel:{
show:true,
overflow:"breakAll",
width:40
}
},
series: [
{
@ -204,6 +214,9 @@ const initCharts=()=>{
})
userUnDoneIssueChart=echarts.init(userUnDoneIssueEle.value)
userUnDoneIssueChart.setOption({
grid:{
left:60
},
dataset:{
source:[
["count","name"],
@ -219,7 +232,12 @@ const initCharts=()=>{
},
yAxis: {
name:"User",
type: 'category'
type: 'category',
axisLabel:{
show:true,
overflow:"breakAll",
width:40
}
},
series: [
{

View File

@ -1,6 +1,6 @@
<template>
<a-form :model="form" ref="eleForm">
<a-form-item label="issue" field="issueId" required>
<a-form-item :label="$t('util.issue')" field="issueId" required>
<a-select allow-clear allow-search @search="onSearch" v-model="form.issueId">
<a-option v-for="item in issueList" :label="item.name" :value="item.id">
{{projectKey+"-"+item.unique_id+" "+item.name}}
@ -25,7 +25,7 @@ const eleForm=ref(null)
const form=reactive({
issueId:""
})
const issueList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item[]>>([])
const issueList=ref<DCSType<ICommon_Route_Res_Project_Issue_filter_Item>[]>([])
const onSearch=async (keyword:string)=>{
let res=await apiIssue.filter({
name:keyword,

View File

@ -7,7 +7,7 @@
</a-spin>
</template>
<template #actions>
<a-button type="primary" size="small" @click="onCommentAdd" style="margin-top: 10px">Save</a-button>
<a-button type="primary" size="small" @click="onCommentAdd" style="margin-top: 10px">{{$t("util.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')">
@ -71,6 +71,7 @@ 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";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectIssueId:string
@ -89,6 +90,7 @@ const objEditor=ref<InstanceType<typeof RichEditor>>()
const objEditorAdd=ref<InstanceType<typeof RichEditor>>()
const loading=ref(false)
const popMenuList=ref(RichEditorEventHandle.popMenuList)
const {t}=useI18n()
const getCommentList=async ()=>{
let res=await apiIssue.commentList({
projectIssueId:props.projectIssueId
@ -133,7 +135,7 @@ const onSave=async (item:DCSType<{
}
}))
if(value.length==0) {
Message.error("content can not be empty")
Message.error(t("tip.contentNotEmpty"))
return
}
let res=await apiIssue.commentEdit({
@ -147,7 +149,7 @@ const onSave=async (item:DCSType<{
}
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?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteComment"))
if(ret) {
let res=await apiIssue.commentRemove({
contentId:item.value.id

View File

@ -1,12 +1,12 @@
<template>
<div style="padding: 0 10px">
<a-form layout="vertical" :model="form" ref="eleForm">
<a-form-item label="Issue Type" field="issueTypeId" required>
<a-form-item :label="$t('util.issueType')" field="issueTypeId" required>
<a-select v-model="form.issueTypeId" @change="onIssueTypeChange">
<a-option v-for="item in issueTypeList" :label="item.name" :value="item.id"></a-option>
</a-select>
</a-form-item>
<a-divider orientation="left" v-if="valueList.length>0">Convert Fields</a-divider>
<a-divider orientation="left" v-if="valueList.length>0">{{$t("controller.app.project.issue.projectIssueConvert.convertFields")}}</a-divider>
<a-form-item v-for="value in valueList" :key="value.field.id" :extra="value.field.description" :field="value.field.name" :required="!value.field.optional">
<template #label>
{{value.field.name}}&nbsp;
@ -18,7 +18,7 @@
<a-list-item v-for="item in originValueList.filter(item=>item.nodeField.fieldType.type===value.fieldType.type)" :key="item.issueFieldValue.id">
{{item.nodeField.field.name}}&nbsp;&nbsp;
<template #actions>
<a-button type="primary" size="mini" @click="onImport(item,value)">Import</a-button>
<a-button type="primary" size="mini" @click="onImport(item,value)">{{$t("util.import")}}</a-button>
</template>
</a-list-item>
</a-list>

View File

@ -1,26 +1,26 @@
<template>
<div style="padding: 0 10px">
<a-form layout="vertical" :model="form" ref="eleForm">
<a-form-item label="Issue Type" field="issueTypeId" required>
<a-form-item :label="$t('util.issueType')" field="issueTypeId" required>
<a-select v-model="form.issueTypeId" @change="onIssueTypeChange">
<a-option v-for="item in issueTypeList" :label="item.name" :value="item.id"></a-option>
</a-select>
</a-form-item>
<a-form-item label="name" field="name" required>
<a-form-item :label="$t('util.name')" field="name" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="description" field="description">
<a-form-item :label="$t('util.description')" field="description">
<a-textarea v-model="form.description"></a-textarea>
</a-form-item>
<a-form-item label="priority" field="priority" required>
<a-form-item :label="$t('util.priority')" field="priority" required>
<a-select v-model="form.priority">
<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-option :value="ECommon_Model_Project_Issue_Priority.LOW">{{$t('util.low')}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.MEDIUM">{{$t('util.medium')}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.HIGH">{{$t('util.high')}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.URGENT">{{$t('util.urgent')}}</a-option>
</a-select>
</a-form-item>
<a-form-item label="assigner">
<a-form-item :label="$t('util.assigner')">
<a-select allow-search @search="onSearchAssigner" v-model="form.assigner">
<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>&nbsp;&nbsp;
@ -28,7 +28,7 @@
</a-option>
</a-select>
</a-form-item>
<a-form-item label="reporter">
<a-form-item :label="$t('util.reporter')">
<a-select allow-search @search="onSearchReporter" v-model="form.reporter">
<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>&nbsp;&nbsp;

View File

@ -1,35 +1,35 @@
<template>
<div class="issueProfileDetail">
<a-collapse :default-active-key="['detail']">
<a-collapse-item key="detail" header="Detail">
<a-collapse-item key="detail" :header="$t('util.detail')">
<a-form layout="vertical" :model="{}">
<a-form-item label="Issue Type">
<a-form-item :label="$t('util.issueType')">
{{info.issueType.name}}
</a-form-item>
<a-form-item label="Assigner">
<a-form-item :label="$t('util.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">
<a-form-item :label="$t('util.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">
<a-form-item :label="$t('util.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">
<a-form-item :label="$t('util.module')">
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.MODULE" :value="moduleList"></FieldEditBasic>
</a-form-item>
<a-form-item label="Label">
<a-form-item :label="$t('util.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">
<a-form-item :label="$t('util.fixVersions')">
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.FIXVERSIONS" :value="releaseList"></FieldEditBasic>
</a-form-item>
<a-form-item label="Sprint">
<a-form-item :label="$t('util.sprint')">
<FieldEditBasic :project-issue-id="info.id" :type="EClient_Field_Basic_Type.SPRINT" :value="sprintInfo"></FieldEditBasic>
</a-form-item>
</a-form>
</a-collapse-item>
<a-collapse-item key="more" header="More">
<a-collapse-item key="more" :header="$t('util.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>
@ -38,7 +38,7 @@
</a-collapse-item>
</a-collapse>
<a-row style="margin-top: 10px;color: grey;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')}}
{{$t("util.created")}} {{moment(info.created_time).format('YYYY-MM-DD HH:mm:ss')}}
</a-row>
</div>
</template>

View File

@ -6,35 +6,35 @@
<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>&nbsp;
created the issue&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.createdTheIssue")}}&nbsp;
<span style="color: grey">{{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>&nbsp;
resolved your approval&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.resolvedYourApproval")}}&nbsp;
<span style="color: grey">{{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>&nbsp;
rejected your approval&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.rejectedYourApproval")}}&nbsp;
<span style="color: grey">{{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>&nbsp;
updated the field&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.updatedTheField")}}&nbsp;
<span style="color: blue">
{{item.name}}
</span>&nbsp;
<span style="color: grey">{{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 :&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.newValue")}} :&nbsp;
<UserAvatar v-if="/\d{19,}/.test(item.value)" :organization-user-id="item.value"></UserAvatar>
<span v-else style="color: grey">{{item.value}}</span>
</div>
@ -42,20 +42,20 @@
<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>&nbsp;
updated the workflow&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.updatedTheWorkflow")}}&nbsp;
<span style="color: #544646">
{{item.name}}
</span>&nbsp;
<span style="color: grey">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
</div>
<div>
new workflow : <span style="color: grey">{{item.value}}</span>
{{$t("controller.app.project.issue.projectIssueHistory.newWorkflow")}} : <span style="color: grey">{{item.value}}</span>
</div>
</template>
<template v-else-if="item.type===ECommon_Model_Project_Issue_History_Type.ISSUE_TYPE_CONVERT">
<div style="width: 100%;align-items: center;display: flex">
<UserAvatar :organization-user-id="item.organization_user_id"></UserAvatar>&nbsp;
convert the issue&nbsp;
{{$t("controller.app.project.issue.projectIssueHistory.convertTheIssue")}}&nbsp;
<span style="color: grey">{{moment(item.created_time).format("YYYY-MM-DD HH:mm:ss")}}</span>
</div>
</template>

View File

@ -2,55 +2,55 @@
<div>
<a-row>
<a-space wrap>
Filter:
<a-input-search v-model="keyword" placeholder="please type name or unique id" style="width: 250px" @search="onSearchIssue"></a-input-search>
{{$t("util.filter")}}:
<a-input-search v-model="keyword" :placeholder="$t('placeholder.typeNameOrUniqueId')" style="width: 250px" @search="onSearchIssue"></a-input-search>
<a-select v-model="issueType">
<template #label="{data}">
<span>Issue Type:{{data?.label}}</span>
<span>{{$t("util.issueType")}}:{{data?.label}}</span>
</template>
<a-option value="all" label="All"></a-option>
<a-option value="all" :label="$t('util.all')"></a-option>
<a-option v-for="item in issueTypeList" :label="item.name" :value="item.id"></a-option>
</a-select>
<a-select style="width: 160px" v-model="priority">
<template #label="{data}">
<span>Priority:{{data?.label}}</span>
<span>{{$t("util.priority")}}:{{data?.label}}</span>
</template>
<a-option :value="-1" label="All"></a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.LOW" label="low"></a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.MEDIUM" label="medium"></a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.HIGH" label="high"></a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.URGENT" label="urgent"></a-option>
<a-option :value="-1" :label="$t('util.all')"></a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.LOW">{{$t('util.low')}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.MEDIUM">{{$t('util.medium')}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.HIGH">{{$t('util.high')}}</a-option>
<a-option :value="ECommon_Model_Project_Issue_Priority.URGENT">{{$t('util.urgent')}}</a-option>
</a-select>
<a-select style="width: 170px" v-model="status">
<template #label="{data}">
<span>Status:{{data?.label}}</span>
<span>{{$t("util.status")}}:{{data?.label}}</span>
</template>
<a-option :value="-1" label="All"></a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.NOTSTART" label="not start"></a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.INPROGRESS" label="in progress"></a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.DONE" label="done"></a-option>
<a-option :value="-1" :label="$t('util.all')"></a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.NOTSTART">{{$t('util.notStart')}}</a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.INPROGRESS">{{$t('util.inProgress')}}</a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.DONE">{{$t('util.done')}}</a-option>
</a-select>
<a-cascader v-model="module" :field-names="fields" :options="moduleList" placeholder="please select" :format-label="format" check-strictly></a-cascader>
Label:
<a-select v-model="label" @search="onSearchLabel" allow-search placeholder="please type label">
<a-option label="All" value="all"></a-option>
<a-cascader v-model="module" :field-names="fields" :options="moduleList" :placeholder="$t('placeholder.pleaseSelect')" :format-label="format" check-strictly></a-cascader>
{{$t("util.label")}}:
<a-select v-model="label" @search="onSearchLabel" allow-search :placeholder="$t('placeholder.typeLabel')">
<a-option :label="$t('util.all')" value="all"></a-option>
<a-option v-for="item in labelList" :label="item.name" :value="item.id"></a-option>
</a-select>
Assigner:
<a-select v-model="assignerId" @search="onSearchAssigner" allow-search placeholder="please type assigner">
<a-option label="All" value="all"></a-option>
{{$t("util.assigner")}}:
<a-select v-model="assignerId" @search="onSearchAssigner" allow-search :placeholder="$t('placeholder.typeAssigner')">
<a-option :label="$t('util.all')" value="all"></a-option>
<a-option v-for="item in assignerList" :label="item.organizationUser.nickname" :value="item.organizationUser.id"></a-option>
</a-select>
Reporter:
<a-select v-model="reporterId" @search="onSearchReporter" allow-search placeholder="please type reporter">
<a-option label="All" value="all"></a-option>
{{$t("util.reporter")}}:
<a-select v-model="reporterId" @search="onSearchReporter" allow-search :placeholder="$t('placeholder.typeReporter')">
<a-option :label="$t('util.all')" value="all"></a-option>
<a-option v-for="item in reporterList" :label="item.organizationUser.nickname" :value="item.organizationUser.id"></a-option>
</a-select>
<a-button type="primary" @click="onCreate" v-if="checkPermission(permission,Permission_Types.Project.EDIT)">Create</a-button>
<a-button type="primary" @click="onCreate" v-if="checkPermission(permission,Permission_Types.Project.EDIT)">{{$t("util.create")}}</a-button>
</a-space>
</a-row>
<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>
<span style="font-size: small;color: gray">{{$t("controller.app.project.issue.projectIssueList.remark")}}</span>
<a-table style="margin-top: 10px" :columns="columns" :data="issueList" :pagination="pagination" @pageChange="onPageChange">
<template #type="{record}">
{{record.issueType.name}}
@ -73,9 +73,9 @@
<FieldPriority :priority="record.priority"></FieldPriority>
</template>
<template #status="{record}">
<a-tag color="gray" v-if="record.status===ECommon_Model_Workflow_Node_Status.NOTSTART">Not Start</a-tag>
<a-tag color="blue" v-else-if="record.status===ECommon_Model_Workflow_Node_Status.INPROGRESS">InProgress</a-tag>
<a-tag color="green" v-else-if="record.status===ECommon_Model_Workflow_Node_Status.DONE">Done</a-tag>
<a-tag color="gray" v-if="record.status===ECommon_Model_Workflow_Node_Status.NOTSTART">{{$t("util.notStart")}}</a-tag>
<a-tag color="blue" v-else-if="record.status===ECommon_Model_Workflow_Node_Status.INPROGRESS">{{$t("util.inProgress")}}</a-tag>
<a-tag color="green" v-else-if="record.status===ECommon_Model_Workflow_Node_Status.DONE">{{$t("util.done")}}</a-tag>
</template>
</a-table>
</div>
@ -108,11 +108,13 @@ import {ICommon_Model_Issue_Type} from "../../../../../../../common/model/issue_
import ProjectIssueProfile from "./projectIssueProfile.vue";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
import {SessionStorage} from "../../../../common/storage/session";
import {useI18n} from "vue-i18n";
const objInject=inject(injectProjectInfo)
const projectId=objInject.id
const permission=objInject.permission
const key=objInject.key
const {t}=useI18n()
const fields={
label:"name",
value:"id",
@ -120,7 +122,7 @@ const fields={
}
const columns=[
{
title:"Type",
title:t("util.type"),
slotName:"type"
},
{
@ -128,7 +130,7 @@ const columns=[
slotName: "key"
},
{
title:"Name",
title:t("util.name"),
slotName: "name"
},
{
@ -140,11 +142,11 @@ const columns=[
slotName: "reporter"
},
{
title:"Priority",
title:t("util.priority"),
slotName: "priority"
},
{
title:"Status",
title:t("util.status"),
slotName: "status"
}
]

View File

@ -5,9 +5,9 @@
<a-row style="width: 300px;padding: 10px">
<a-row style="color: gray;width: 100%">
{{info?.project.keyword+"-"+info?.unique_id}}&nbsp;
<a-tag color="gray" v-if="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.NOTSTART">Not Start</a-tag>
<a-tag color="blue" v-else-if="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.INPROGRESS">InProgress</a-tag>
<a-tag color="green" v-else-if="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.DONE">Done</a-tag>
<a-tag color="gray" v-if="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.NOTSTART">{{$t("util.notStart")}}</a-tag>
<a-tag color="blue" v-else-if="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.INPROGRESS">{{$t("util.inProgress")}}</a-tag>
<a-tag color="green" v-else-if="info?.workflowNode.status===ECommon_Model_Workflow_Node_Status.DONE">{{$t("util.done")}}</a-tag>
</a-row>
<a-row style="font-weight: bold;width: 100%;margin-top: 10px">
{{info?.name}}
@ -15,14 +15,14 @@
<a-row style="width: 100%;margin-top: 15px">
<a-col :span="12">
<template v-if="info?.assigner_id">
Assigner&nbsp;&nbsp;
{{$t("util.assigner")}}&nbsp;&nbsp;
<a-avatar :image-url="info?.assigner_id.photo" :size="20"></a-avatar>&nbsp;
{{info?.assigner_id.nickname}}
</template>
</a-col>
<a-col :span="12">
<template v-if="info?.reporter_id">
Reporter&nbsp;&nbsp;
{{$t("util.reporter")}}&nbsp;&nbsp;
<a-avatar :image-url="info?.reporter_id.photo" :size="20"></a-avatar>&nbsp;
{{info?.reporter_id.nickname}}
</template>
@ -36,7 +36,7 @@
<FieldPriority :priority="info?.priority" v-if="info"></FieldPriority>
</a-col>
<a-col :span="8">
<a-button type="outline" size="mini" style="margin-left: 20px" @click="onProfile">Profile</a-button>
<a-button type="outline" size="mini" style="margin-left: 20px" @click="onProfile">{{$t("util.profile")}}</a-button>
</a-col>
</a-row>
</a-row>

View File

@ -13,7 +13,7 @@
</a-row>
<a-row v-if="info?.approval?.type===ECommon_Model_Project_Issue_Approval_Type.REJECTED" style="align-items: center;margin-top: 10px;">
<UserAvatar :organization-user-id="info.approval.approval_organization_user_id"></UserAvatar>
<span style="color: orange;font-weight: bold">&nbsp;rejected your approval</span>
<span style="color: orange;font-weight: bold">&nbsp;{{$t("controller.app.project.issue.projectIssueHistory.rejectedYourApproval")}}</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>
@ -31,17 +31,17 @@
</template>
</a-dropdown>
<a-button v-if="!parentIssue" @click="onCreateSubIssue">
Create Child Issue
{{$t("controller.app.project.issue.projectIssueProfile.createChildIssue")}}
</a-button>
<a-dropdown-button>
Link Issue
{{$t("controller.app.project.issue.projectIssueProfile.linkIssue")}}
<template #icon>
<icon-down />
</template>
<template #content>
<a-doption @click="onAddItem('related')">Related</a-doption>
<a-doption @click="onAddItem('child')">Child</a-doption>
<a-doption @click="onAddItem('parent')">Parent</a-doption>
<a-doption @click="onAddItem('related')">{{$t("controller.app.project.issue.projectIssueProfile.related")}}</a-doption>
<a-doption @click="onAddItem('child')">{{$t("controller.app.project.issue.projectIssueProfile.child")}}</a-doption>
<a-doption @click="onAddItem('parent')">{{$t("controller.app.project.issue.projectIssueProfile.parent")}}</a-doption>
</template>
</a-dropdown-button>
<a-dropdown>
@ -52,38 +52,38 @@
</a-button>
<template #content>
<a-popover trigger="hover" position="rt" @popup-visible-change="showQuickMeeting">
<a-doption>Quick Meeting</a-doption>
<a-doption>{{$t("controller.app.project.issue.projectIssueProfile.quickMeeting")}}</a-doption>
<template #content>
<a-row style="flex-direction: column;align-items: center">
<a-input size="small" placeholder="type user name" v-model="searchUserKey"></a-input>
<a-input size="small" :placeholder="$t('placeholder.typeUserName')" v-model="searchUserKey"></a-input>
<a-table style="width: 100%;margin-top: 10px" row-key="id" :columns="columns" :data="issueRelatedUserList.filter(item=>(item.id!==organizationUserId && item.name.includes(searchUserKey)))" :row-selection="rowSelection" v-model:selected-keys="selectKeys" :pagination="false">
<template #name="{record}">
<UserAvatar :organization-user-id="record.id" :name="record.name" :photo="record.photo"></UserAvatar>
</template>
</a-table>
<a-button type="primary" style="margin-top: 10px" size="small" @click="onMeeting">Invite</a-button>
<a-button type="primary" style="margin-top: 10px" size="small" @click="onMeeting">{{$t("util.invite")}}</a-button>
</a-row>
</template>
</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.EDIT)" @click="onConvert">Convert</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.EDIT)" @click="onCopy">{{$t("util.copy")}}</a-doption>
<a-doption v-if="checkPermission(permission,Permission_Types.Project.EDIT)" @click="onConvert">{{$t("util.convert")}}</a-doption>
<a-doption v-if="checkPermission(permission,Permission_Types.Project.ADMIN) || info?.created_by.id===store.userInfo.id" @click="onDelete" style="color: red">{{$t("util.delete")}}</a-doption>
</template>
</a-dropdown>
</a-space>
</a-row>
<a-row style="margin-top: 20px;font-weight: bold">
Description
{{$t("util.description")}}
</a-row>
<a-row style="margin-top: 10px">
<FieldEditBasic :project-issue-id="projectIssueId" :type="EClient_Field_Basic_Type.DESCRIPTION" :value="description" style="margin-right: 10px;box-sizing: border-box"></FieldEditBasic>
</a-row>
<ProjectIssueRelated :project-issue-id="projectIssueId" :child-issue-list="childIssueList" :parent-issue="parentIssue" :related-issue-list="relatedIssueList" @remove-parent="parentIssue=null"></ProjectIssueRelated>
<a-tabs type="rounded" style="margin-top: 50px;" lazy-load size="small">
<a-tab-pane key="comment" title="Comments">
<a-tab-pane key="comment" :title="$t('util.comments')">
<ProjectIssueComment style="margin-top: 10px" :project-issue-id="projectIssueId"></ProjectIssueComment>
</a-tab-pane>
<a-tab-pane key="history" title="History">
<a-tab-pane key="history" :title="$t('util.history')">
<ProjectIssueHistory :project-issue-id="projectIssueId"></ProjectIssueHistory>
</a-tab-pane>
</a-tabs>
@ -132,6 +132,7 @@ import {ECommon_Content_Line_Config_Type} from "../../../../../../../common/mode
import {RichEditorEventHandle} from "@/business/common/component/richEditorEventHandle";
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../../common/model/finder_item";
import ProjectIssueConvert from "@/business/controller/app/project/issue/projectIssueConvert.vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectIssueId:string
@ -168,9 +169,10 @@ const rowSelection=ref<TableRowSelection>({
showCheckedAll:true,
onlyCurrent:false
})
const {t}=useI18n()
const columns = [
{
title: 'Name',
title: t("util.name"),
slotName: 'name',
}
]
@ -261,13 +263,13 @@ const onAddItem=async (type:"parent"|"child"|"related")=>{
}
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,t("tip.deleteIssue"))
if(ret) {
let res=await apiIssue.remove({
projectIssueId:props.projectIssueId
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
navigator.pop()
}
}
@ -302,7 +304,7 @@ const onAction=async (item:ICommon_Model_Workflow_Action | {
return
}
} else if(item.name==="Reject") {
let ret=await Dialog.inputRich(root.value,appContext,"Reject Reason")
let ret=await Dialog.inputRich(root.value,appContext,t("tip.rejectReason"))
if(ret) {
let res=await apiIssue.rejectApproval({
projectIssueId:props.projectIssueId,
@ -367,7 +369,7 @@ const onMeeting=async ()=>{
}
const onCopy=async ()=>{
let ret=await Dialog.input(root.value,appContext,"type the issue's name")
let ret=await Dialog.input(root.value,appContext,t("tip.typeIssueName"))
if(ret) {
let res=await apiIssue.copy({
projectIssueId:props.projectIssueId,
@ -393,7 +395,7 @@ const onConvert=async ()=>{
}
const onCreateSubIssue=async ()=>{
let ret=await Dialog.input(root.value,appContext,"type the issue's name")
let ret=await Dialog.input(root.value,appContext,t("tip.typeIssueName"))
if(ret) {
let res=await apiIssue.createChildIssue({
projectIssueId:props.projectIssueId,

View File

@ -1,7 +1,7 @@
<template>
<div>
<template v-if="parentIssue">
<a-row style="margin-top: 20px;font-weight: bold">Parent Issue</a-row>
<a-row style="margin-top: 20px;font-weight: bold">{{$t("controller.app.project.issue.projectIssueRelated.parentIssue")}}</a-row>
<a-list style="margin-top: 10px;margin-right: 10px" size="small" hoverable>
<a-list-item>
<a-space size="large">
@ -20,7 +20,7 @@
</a-list>
</template>
<template v-if="childIssueList.length>0">
<a-row style="margin-top: 20px;font-weight: bold">Child Issues</a-row>
<a-row style="margin-top: 20px;font-weight: bold">{{$t("controller.app.project.issue.projectIssueRelated.childIssues")}}</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">
@ -39,7 +39,7 @@
</a-list>
</template>
<template v-if="relatedIssueList.length>0">
<a-row style="margin-top: 20px;font-weight: bold">Related Issues</a-row>
<a-row style="margin-top: 20px;font-weight: bold">{{$t("controller.app.project.issue.projectIssueRelated.relatedIssues")}}</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">
@ -70,6 +70,7 @@ 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";
import {useI18n} from "vue-i18n";
const props=defineProps<{
parentIssue?:DCSType<ICommon_Model_Project_Issue>,
@ -84,9 +85,10 @@ const key=inject(injectProjectInfo).key
const projectId=inject(injectProjectInfo).id
const root=getRootNavigatorRef()
const appContext=getCurrentInstance().appContext
const {t}=useI18n()
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?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteParentIssue"))
if(ret) {
let res=await apiIssue.removeParentIssue({
projectIssueId:props.projectIssueId,
@ -97,7 +99,7 @@ const onRemoveItem=async (type:"parent"|"child"|"related",index:number)=>{
}
}
} else if(type=="child") {
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove child issue?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteChildIssue"))
if(ret) {
let res=await apiIssue.removeChildIssue({
projectIssueId:props.projectIssueId,
@ -108,7 +110,7 @@ const onRemoveItem=async (type:"parent"|"child"|"related",index:number)=>{
}
}
} else if(type=="related") {
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove related issue?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteRelatedIssue"))
if(ret) {
let res=await apiIssue.removeRelatedIssue({
projectIssueId:props.projectIssueId,

View File

@ -1,8 +1,8 @@
<template>
<div style="height: 100%;overflow-y: auto;padding: 0px 10px" ref="root">
Your Work
{{$t("controller.app.project.project.yourWork")}}
<a-collapse :default-active-key="['recent','all']" style="margin-top: 10px">
<a-collapse-item header="Recent Project List" key="recent">
<a-collapse-item :header="$t('controller.app.project.project.recentProjectList')" key="recent">
<a-space wrap style="margin-top: 20px" size="large" v-if="recentList.length>0">
<ProjectItem v-for="item in recentList" style="background-color: white" done-title="my done issue" :done-count="item.done" open-title="my open issue" :open-count="item.notstart+item.inprogress" :name="item.name" :project-id="item.id" :photo="item.photo" @click="onClickProjectItem(item.id,item.name)" v-drag.shortcut="()=>({
shortcutType:ECommon_Model_Finder_Shortcut_Type.PROJECT,
@ -12,17 +12,17 @@
</a-space>
<a-empty v-else></a-empty>
</a-collapse-item>
<a-collapse-item header="All Project List" key="all">
<a-collapse-item :header="$t('controller.app.project.project.allProjectList')" key="all">
<a-row>
<a-space>
Type
{{$t("util.type")}}
<a-select v-model="type" style="width: 100px">
<a-option label="All" value="all"></a-option>
<a-option label="Created" value="created"></a-option>
<a-option label="Joined" value="joined"></a-option>
<a-option :label="$t('util.all')" value="all"></a-option>
<a-option :label="$t('util.created')" value="created"></a-option>
<a-option :label="$t('util.joined')" value="joined"></a-option>
</a-select>
<a-input-search style="width: 250px" v-model="keyword" placeholder="please type project name" @search="onSearch"></a-input-search>
<a-button type="primary" @click="onAddProject" v-if="checkPermission(storeOrganization.organizationPermission,Permission_Types.Organization.CREATE_PROJECT)">Create</a-button>
<a-input-search style="width: 250px" v-model="keyword" :placeholder="$t('placeholder.typeProjectName')" @search="onSearch"></a-input-search>
<a-button type="primary" @click="onAddProject" v-if="checkPermission(storeOrganization.organizationPermission,Permission_Types.Organization.CREATE_PROJECT)">{{$t("util.create")}}</a-button>
</a-space>
</a-row>
<a-space wrap style="margin-top: 20px" size="large" v-if="list.length>0">

View File

@ -2,11 +2,11 @@
<a-layout style="height: 100%">
<a-layout-sider :resize-directions="['right']">
<a-menu style="width: 100%" @menu-item-click="onSubMenuClick" v-model:selected-keys="menuKey">
<a-menu-item key="home">Home</a-menu-item>
<a-menu-item key="issue">Issue</a-menu-item>
<a-menu-item key="board">Board</a-menu-item>
<a-menu-item key="release">Release</a-menu-item>
<a-menu-item key="setting" v-if="checkPermission(permission,Permission_Types.Project.ADMIN)">Setting</a-menu-item>
<a-menu-item key="home">{{$t("util.home")}}</a-menu-item>
<a-menu-item key="issue">{{$t("util.issue")}}</a-menu-item>
<a-menu-item key="board">{{$t("util.board")}}</a-menu-item>
<a-menu-item key="release">{{$t("util.release")}}</a-menu-item>
<a-menu-item key="setting" v-if="checkPermission(permission,Permission_Types.Project.ADMIN)">{{$t("util.setting")}}</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout-content style="flex-direction: column;display: flex;padding: 10px;">

View File

@ -1,13 +1,13 @@
<template>
<a-form :model="form" ref="eleForm">
<a-form-item label="name" field="name" required>
<a-form-item :label="$t('util.name')" field="name" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="description" field="description">
<a-form-item :label="$t('util.description')" field="description">
<a-textarea v-model="form.description" allow-clear></a-textarea>
</a-form-item>
<a-form-item label="dateRange" field="dateRange" required>
<a-range-picker v-model="form.dateRange" :placeholder="['Start Date','Release Date']"></a-range-picker>
<a-form-item :label="$t('util.dateRange')" field="dateRange" required>
<a-range-picker v-model="form.dateRange" :placeholder="[$t('util.startDate'),$t('util.releaseDate')]"></a-range-picker>
</a-form-item>
</a-form>
</template>
@ -19,12 +19,14 @@ import {reactive, ref} from "vue";
import {onDialogOk} from "../../../../common/component/dialog/dialog";
import {dialogFuncGenerator} from "../../../../common/util/helper";
import {Message} from "@arco-design/web-vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
type:"add"|"edit",
projectId?:string,
item?:DCSType<ICommon_Route_Res_Release_Item>
}>()
const {t}=useI18n()
const form=reactive({
name:props.type=="edit"?props.item.name:"",
dateRange:props.type=="edit"?[props.item.start_time,props.item.release_time]:["",""],
@ -34,7 +36,7 @@ const eleForm=ref(null)
onDialogOk(dialogFuncGenerator({
func:()=>{
if(!form.dateRange[0] || !form.dateRange[1]) {
Message.error("you must select both date!")
Message.error(t("tip.selectBothDate"))
return false;
}
return props.type=="add"?apiRelease.create({

View File

@ -1,7 +1,7 @@
<template>
<div>
there are still <span style="font-weight: bold;color: blue">{{items.length}}</span> unresolved issues!<br><br>
<span style="font-weight: bold;color: red">Do you Still continue to Release?</span>
{{$t("controller.app.project.release.projectReleaseIfCan.thereAreStill")}} <span style="font-weight: bold;color: blue">{{items.length}}</span> {{$t("controller.app.project.release.projectReleaseIfCan.unresolvedIssues")}}!<br><br>
<span style="font-weight: bold;color: red">{{$t("controller.app.project.release.projectReleaseIfCan.continueToRelease")}}?</span>
<a-table style="margin-top: 15px" :data="items" :columns="columns">
<template #key="{record}">
{{projectKey+"-"+record.unique_id}}
@ -31,6 +31,7 @@ import {onDialogOk} from "../../../../common/component/dialog/dialog";
import {ECommon_Model_Project_Release_Status} from "../../../../../../../common/model/project_release";
import {Message} from "@arco-design/web-vue";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectReleaseId:string,
@ -38,17 +39,18 @@ const props=defineProps<{
projectKey:string,
projectId:string
}>()
const {t}=useI18n()
const columns=[
{
title:"Key",
slotName: "key"
},
{
title:"Name",
title:t("util.name"),
slotName:"name"
},
{
title:"Priority",
title:t("util.priority"),
slotName: "priority"
},
{
@ -69,7 +71,7 @@ onDialogOk(async ()=>{
status:ECommon_Model_Project_Release_Status.RELEASE
})
if(res?.code==0) {
Message.success("release success")
Message.success(t("tip.releaseSuccess"))
return true;
} else {
Message.error(res.msg)

View File

@ -2,17 +2,17 @@
<div>
<a-row>
<a-space wrap>
<a-input-search v-model="keyword" placeholder="please type release name" style="width: 250px" @search="onSearch"></a-input-search>
<a-input-search v-model="keyword" :placeholder="$t('placeholder.typeReleaseName')" style="width: 250px" @search="onSearch"></a-input-search>
<a-select v-model="status">
<template #label="{data}">
<span>Status:{{data?.label}}</span>
<span>{{$t("util.status")}}:{{data?.label}}</span>
</template>
<a-option :value="-1">ALL</a-option>
<a-option :value="ECommon_Model_Project_Release_Status.ARCHIVED">ARCHIVED</a-option>
<a-option :value="ECommon_Model_Project_Release_Status.RELEASE">RELEASED</a-option>
<a-option :value="ECommon_Model_Project_Release_Status.UNRELEASE">UNRELEASED</a-option>
<a-option :value="-1">{{$t("util.all")}}</a-option>
<a-option :value="ECommon_Model_Project_Release_Status.ARCHIVED">{{$t("util.archived")}}</a-option>
<a-option :value="ECommon_Model_Project_Release_Status.RELEASE">{{$t("util.released")}}</a-option>
<a-option :value="ECommon_Model_Project_Release_Status.UNRELEASE">{{$t("util.unReleased")}}</a-option>
</a-select>
<a-button type="primary" @click="onCreate" v-if="checkPermission(permission,Permission_Types.Project.EDIT)">Create</a-button>
<a-button type="primary" @click="onCreate" v-if="checkPermission(permission,Permission_Types.Project.EDIT)">{{$t("util.create")}}</a-button>
</a-space>
</a-row>
<a-table style="margin-top: 10px" :columns="columns" :data="releaseList" :pagination="pagination" @pageChange="onPageChange">
@ -20,13 +20,13 @@
<a-link href="javascript:void(0)" @click="onProfile(record,$event)">{{record.name}}</a-link>
</template>
<template #status="{record}">
<a-tag color="blue" v-if="record.status===ECommon_Model_Project_Release_Status.UNRELEASE">UNRELEASED</a-tag>
<a-tag color="green" v-else-if="record.status===ECommon_Model_Project_Release_Status.RELEASE">RELEASED</a-tag>
<a-tag v-else-if="record.status===ECommon_Model_Project_Release_Status.ARCHIVED">ARCHIVED</a-tag>
<a-tag color="blue" v-if="record.status===ECommon_Model_Project_Release_Status.UNRELEASE">{{$t("util.unReleased")}}</a-tag>
<a-tag color="green" v-else-if="record.status===ECommon_Model_Project_Release_Status.RELEASE">{{$t("util.released")}}</a-tag>
<a-tag v-else-if="record.status===ECommon_Model_Project_Release_Status.ARCHIVED">{{$t("util.archived")}}</a-tag>
</template>
<template #progress="{record}">
<span v-if="record.notstart+record.inprogress+record.done==0">
No Issues
{{$t("controller.app.project.release.projectReleaseList.noIssues")}}
</span>
<a-progress v-else :percent="record.done/(record.notstart+record.inprogress+record.done)" style="width: 180px" color="green"></a-progress>
</template>
@ -41,28 +41,28 @@
</template>
<template #operation="{record}">
<a-space v-if="checkPermission(permission,Permission_Types.Project.EDIT)" wrap>
<a-button size="small" @click="onEdit(record)">Edit</a-button>
<a-button size="small" @click="onEdit(record)">{{$t("util.edit")}}</a-button>
<a-dropdown-button size="small">
Action
{{$t("util.action")}}
<template #icon>
<icon-down />
</template>
<template #content>
<template v-if="record.status==ECommon_Model_Project_Release_Status.ARCHIVED">
<a-doption @click="onUnRelease(record)">UnRelease</a-doption>
<a-doption @click="onRelease(record)">Release</a-doption>
<a-doption @click="onUnRelease(record)">{{$t("util.unRelease")}}</a-doption>
<a-doption @click="onRelease(record)">{{$t("util.release")}}</a-doption>
</template>
<template v-else-if="record.status==ECommon_Model_Project_Release_Status.RELEASE">
<a-doption @click="onUnRelease(record)">UnRelease</a-doption>
<a-doption @click="onArchive(record)">Archive</a-doption>
<a-doption @click="onUnRelease(record)">{{$t("util.unRelease")}}</a-doption>
<a-doption @click="onArchive(record)">{{$t("util.archive")}}</a-doption>
</template>
<template v-if="record.status==ECommon_Model_Project_Release_Status.UNRELEASE">
<a-doption @click="onRelease(record)">Release</a-doption>
<a-doption @click="onArchive(record)">Archive</a-doption>
<a-doption @click="onRelease(record)">{{$t("util.release")}}</a-doption>
<a-doption @click="onArchive(record)">{{$t("util.archive")}}</a-doption>
</template>
</template>
</a-dropdown-button>
<a-button size="small" status="danger" @click="onDelete(record)">Delete</a-button>
<a-button size="small" status="danger" @click="onDelete(record)">{{$t("util.delete")}}</a-button>
</a-space>
</template>
</a-table>
@ -88,38 +88,40 @@ import {Message} from "@arco-design/web-vue";
import ProjectReleaseIfCan from "./projectReleaseIfCan.vue";
import ProjectReleaseProfile from "./projectReleaseProfile.vue";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
import {useI18n} from "vue-i18n";
const objInject=inject(injectProjectInfo)
const projectId=objInject.id
const permission=objInject.permission
const key=objInject.key
const {t}=useI18n()
const columns=[
{
title:"Name",
title:t("util.name"),
slotName:"name"
},
{
title:"Status",
title:t("util.status"),
slotName: "status"
},
{
title:"Progress",
title:t("util.progress"),
slotName: "progress"
},
{
title:"Start Date",
title:t("util.startDate"),
slotName: "startDate"
},
{
title:"Release Date",
title:t("util.releaseDate"),
slotName: "releaseDate"
},
{
title:"Description",
title:t("util.description"),
slotName: "description"
},
{
title:"Operation",
title:t("util.operation"),
slotName: "operation"
}
]
@ -177,13 +179,13 @@ const onEdit=async (item:DCSType<ICommon_Route_Res_Release_Item>)=>{
}
}
const onDelete=async (item:DCSType<ICommon_Route_Res_Release_Item>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this release?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteRelease"))
if(ret) {
let res=await apiRelease.remove({
projectReleaseId:item.id
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
search(pagination.current)
}
}
@ -209,7 +211,7 @@ const onRelease=async (item:DCSType<ICommon_Route_Res_Release_Item>)=>{
status:ECommon_Model_Project_Release_Status.RELEASE
})
if(res?.code==0) {
Message.success("release success")
Message.success(t("tip.releaseSuccess"))
search(pagination.current)
} else {
Message.error(res.msg)
@ -225,7 +227,7 @@ const onUnRelease=async (item:DCSType<ICommon_Route_Res_Release_Item>)=>{
status:ECommon_Model_Project_Release_Status.UNRELEASE
})
if(res?.code==0) {
Message.success("unrelease success")
Message.success(t("tip.unReleaseSuccess"))
search(pagination.current)
} else {
Message.error(res.msg)
@ -237,7 +239,7 @@ const onArchive=async (item:DCSType<ICommon_Route_Res_Release_Item>)=>{
status:ECommon_Model_Project_Release_Status.ARCHIVED
})
if(res?.code==0) {
Message.success("archive success")
Message.success(t("tip.archiveSuccess"))
search(pagination.current)
} else {
Message.error(res.msg)

View File

@ -8,9 +8,9 @@
<span style="font-weight: bold">
{{info?.name}}
</span>
<a-tag color="gray" v-if="info?.status===ECommon_Model_Project_Release_Status.ARCHIVED">ARCHIVED</a-tag>
<a-tag color="blue" v-else-if="info?.status===ECommon_Model_Project_Release_Status.UNRELEASE">UNRELEASED</a-tag>
<a-tag color="green" v-else-if="info?.status===ECommon_Model_Project_Release_Status.RELEASE">RELEASED</a-tag>
<a-tag color="gray" v-if="info?.status===ECommon_Model_Project_Release_Status.ARCHIVED">{{$t("util.archived")}}</a-tag>
<a-tag color="blue" v-else-if="info?.status===ECommon_Model_Project_Release_Status.UNRELEASE">{{$t("util.unReleased")}}</a-tag>
<a-tag color="green" v-else-if="info?.status===ECommon_Model_Project_Release_Status.RELEASE">{{$t("util.released")}}</a-tag>
</a-space>
</a-row>
<a-row style="width: 100%;margin-top: 10px">
@ -25,12 +25,12 @@
<a-row style="width: 100%;margin-top: 10px">
<a-col :span="16">
<span v-if="info?.notstart+info?.inprogress+info?.done==0">
No Issues
{{$t("controller.app.project.release.projectReleaseList.noIssues")}}
</span>
<a-progress v-else :percent="info?.done/(info?.notstart+info?.inprogress+info?.done)" style="width: 100%" color="green"></a-progress>
</a-col>
<a-col :span="8" style="text-align: center">
<a-button type="outline" size="mini" @click="onProfile">Profile</a-button>
<a-button type="outline" size="mini" @click="onProfile">{{$t("util.profile")}}</a-button>
</a-col>
</a-row>
</a-row>

View File

@ -9,33 +9,33 @@
})">
{{info?.name}}
</span>
<a-tag color="blue" v-if="info?.status===ECommon_Model_Project_Release_Status.UNRELEASE">UNRELEASED</a-tag>
<a-tag color="green" v-else-if="info?.status===ECommon_Model_Project_Release_Status.RELEASE">RELEASED</a-tag>
<a-tag v-else-if="info?.status===ECommon_Model_Project_Release_Status.ARCHIVED">ARCHIVED</a-tag>
<a-tag color="blue" v-if="info?.status===ECommon_Model_Project_Release_Status.UNRELEASE">{{$t("util.unReleased")}}</a-tag>
<a-tag color="green" v-else-if="info?.status===ECommon_Model_Project_Release_Status.RELEASE">{{$t("util.released")}}</a-tag>
<a-tag v-else-if="info?.status===ECommon_Model_Project_Release_Status.ARCHIVED">{{$t("util.archived")}}</a-tag>
</a-space>
<a-space>
<a-button size="small" @click="onEdit">Edit</a-button>
<a-button size="small" @click="onEdit">{{$t("util.edit")}}</a-button>
<a-dropdown-button size="small">
Action
{{$t("util.action")}}
<template #icon>
<icon-down />
</template>
<template #content>
<template v-if="info?.status==ECommon_Model_Project_Release_Status.ARCHIVED">
<a-doption @click="onUnRelease">UnRelease</a-doption>
<a-doption @click="onRelease">Release</a-doption>
<a-doption @click="onUnRelease">{{$t("util.unRelease")}}</a-doption>
<a-doption @click="onRelease">{{$t("util.release")}}</a-doption>
</template>
<template v-else-if="info?.status==ECommon_Model_Project_Release_Status.RELEASE">
<a-doption @click="onUnRelease">UnRelease</a-doption>
<a-doption @click="onArchive">Archive</a-doption>
<a-doption @click="onUnRelease">{{$t("util.unRelease")}}</a-doption>
<a-doption @click="onArchive">{{$t("util.archive")}}</a-doption>
</template>
<template v-if="info?.status==ECommon_Model_Project_Release_Status.UNRELEASE">
<a-doption @click="onRelease">Release</a-doption>
<a-doption @click="onArchive">Archive</a-doption>
<a-doption @click="onRelease">{{$t("util.release")}}</a-doption>
<a-doption @click="onArchive">{{$t("util.archive")}}</a-doption>
</template>
</template>
</a-dropdown-button>
<a-button size="small" status="danger" @click="onDelete">Delete</a-button>
<a-button size="small" status="danger" @click="onDelete">{{$t("util.delete")}}</a-button>
</a-space>
</a-row>
<a-row style="margin-top: 20px">
@ -51,8 +51,8 @@
{{info?.description}}
</a-row>
<a-row style="justify-content: space-between;margin-top: 30px">
<span style="font-weight: bold">Issues</span>
<a-button type="primary" size="small" @click="onAddIssue">Add Issue</a-button>
<span style="font-weight: bold">{{$t("util.issues")}}</span>
<a-button type="primary" size="small" @click="onAddIssue">{{$t("controller.app.project.release.projectReleaseProfile.addIssue")}}</a-button>
</a-row>
<a-table style="margin-top: 10px" :data="info?.issueList" :columns="columns">
<template #key="{record}">
@ -74,9 +74,9 @@
<UserAvatar :organization-user-id="record.reporter_id.organizationUserId" :name="record.reporter_id.nickname" :photo="record.reporter_id.photo" v-if="record.reporter_id"></UserAvatar>
</template>
<template #status="{record}">
<a-tag color="gray" v-if="record.workflowNode.status===ECommon_Model_Workflow_Node_Status.NOTSTART">Not Start</a-tag>
<a-tag color="blue" v-else-if="record.workflowNode.status===ECommon_Model_Workflow_Node_Status.INPROGRESS">InProgress</a-tag>
<a-tag color="green" v-else-if="record.workflowNode.status===ECommon_Model_Workflow_Node_Status.DONE">Done</a-tag>
<a-tag color="gray" v-if="record.workflowNode.status===ECommon_Model_Workflow_Node_Status.NOTSTART">{{$t("util.notstart")}}</a-tag>
<a-tag color="blue" v-else-if="record.workflowNode.status===ECommon_Model_Workflow_Node_Status.INPROGRESS">{{$t("util.inProgress")}}</a-tag>
<a-tag color="green" v-else-if="record.workflowNode.status===ECommon_Model_Workflow_Node_Status.DONE">{{$t("util.done")}}</a-tag>
</template>
<template #operation="{record}">
<a-button type="text" @click="onRemoveIssue(record)">
@ -110,25 +110,27 @@ import ProjectIssueBind from "../issue/projectIssueBind.vue";
import {EClient_EVENTBUS_TYPE, eventBus} from "../../../../common/event/event";
import {vDrag} from "../../../../../teamOS/common/directive/drag";
import {ECommon_Model_Finder_Shortcut_Type} from "../../../../../../../common/model/finder_item";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectReleaseId:string
}>()
const {t}=useI18n()
const columns=[
{
title:"Key",
slotName:"key"
},
{
title:"Name",
title:t("util.name"),
slotName: "name"
},
{
title:"Issue Type",
title:t("util.issueType"),
slotName: "issueType"
},
{
title:"Priority",
title:t("util.priority"),
slotName: "priority"
},
{
@ -140,11 +142,11 @@ const columns=[
slotName: "reporter"
},
{
title:"Status",
title:t("util.status"),
slotName: "status"
},
{
title:"Operation",
title:t("util.operation"),
slotName: "operation"
},
]
@ -164,14 +166,14 @@ const getInfo=async ()=>{
}
}
const onRemoveIssue=async (item:DCSType<ICommon_Route_Res_Release_Info_Issue_Item>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to remove this issue?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.removeIssue"))
if(ret) {
let res=await apiRelease.removeIssue({
projectReleaseId:props.projectReleaseId,
projectIssueId:item.id
})
if(res?.code==0) {
Message.success("remove success")
Message.success(t("tip.deleteSuccess"))
getInfo()
}
}
@ -186,13 +188,13 @@ const onEdit=async ()=>{
}
}
const onDelete=async ()=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this release?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteRelease"))
if(ret) {
let res=await apiRelease.remove({
projectReleaseId:info.value.id
})
if(res?.code==0) {
Message.success("delete success")
Message.success(t("tip.deleteSuccess"))
navigator.pop()
}
}
@ -218,7 +220,7 @@ const onRelease=async ()=>{
status:ECommon_Model_Project_Release_Status.RELEASE
})
if(res?.code==0) {
Message.success("release success")
Message.success(t("tip.releaseSuccess"))
getInfo()
} else {
Message.error(res.msg)
@ -234,7 +236,7 @@ const onUnRelease=async ()=>{
status:ECommon_Model_Project_Release_Status.UNRELEASE
})
if(res?.code==0) {
Message.success("unrelease success")
Message.success(t("tip.unReleaseSuccess"))
getInfo()
} else {
Message.error(res.msg)
@ -246,7 +248,7 @@ const onArchive=async ()=>{
status:ECommon_Model_Project_Release_Status.ARCHIVED
})
if(res?.code==0) {
Message.success("archive success")
Message.success(t("tip.archiveSuccess"))
getInfo()
} else {
Message.error(res.msg)
@ -263,7 +265,7 @@ const onAddIssue=async ()=>{
projectIssueId:ret as string
})
if(res?.code==0) {
Message.success("add success")
Message.success(t("tip.addSuccess"))
getInfo()
}
}

View File

@ -1,21 +1,21 @@
<template>
<a-collapse :default-active-key="['basic']" accordion>
<a-collapse-item header="Basic" key="basic">
<a-collapse-item :header="$t('util.basic')" key="basic">
<ProjectSettingBasic :project-id="projectId"></ProjectSettingBasic>
</a-collapse-item>
<a-collapse-item header="Module" key="module">
<a-collapse-item :header="$t('util.module')" key="module">
<ModuleList :project-id="projectId"></ModuleList>
</a-collapse-item>
<a-collapse-item header="Tag" key="tag">
<a-collapse-item :header="$t('util.tag')" key="tag">
<LabelList :project-id="projectId"></LabelList>
</a-collapse-item>
<a-collapse-item header="Access" key="access">
<a-collapse-item :header="$t('util.access')" key="access">
<EditProjectAccess :project-id="projectId"></EditProjectAccess>
</a-collapse-item>
<a-collapse-item header="Role" key="role">
<a-collapse-item :header="$t('util.role')" key="role">
<ProjectSettingRole :project-id="projectId"></ProjectSettingRole>
</a-collapse-item>
<a-collapse-item header="Issue Solution" key="solution">
<a-collapse-item :header="$t('util.issueSolution')" key="solution">
<ProjectSettingIssueSolution :project-id="projectId"></ProjectSettingIssueSolution>
</a-collapse-item>
</a-collapse>
@ -30,6 +30,7 @@ import LabelList from "../../setting/project/labelList.vue";
import EditProjectAccess from "../../setting/project/editProjectAccess.vue";
import ProjectSettingRole from "./projectSettingRole.vue";
import ProjectSettingIssueSolution from "./projectSettingIssueSolution.vue";
import {Err} from "../../../../../../../common/status/error";
const projectId=inject(injectProjectInfo).id;

View File

@ -1,19 +1,19 @@
<template>
<a-form ref="eleForm" style="width: 80%" :model="form" @submitSuccess="onSubmit">
<a-form-item field="name" label="name" required>
<a-form-item field="name" :label="$t('util.name')" required>
{{form.name}}
</a-form-item>
<a-form-item field="keyword" label="keyword" required>
<a-form-item field="keyword" :label="$t('util.keyword')" required>
{{form.keyword}}
</a-form-item>
<a-form-item field="description" label="description">
<a-form-item field="description" :label="$t('util.description')">
<a-textarea v-model="form.description" allow-clear></a-textarea>
</a-form-item>
<a-form-item label="logo">
<a-form-item :label="$t('util.logo')">
<Upload types=".png,.jpg,.jpeg,.gif,.bmp,.svg" :default-uri="photo" @upload="onUpload"></Upload>
</a-form-item>
<a-form-item>
<a-button html-type="submit" type="primary">Save</a-button>
<a-button html-type="submit" type="primary">{{$t("util.save")}}</a-button>
</a-form-item>
</a-form>
</template>
@ -24,6 +24,7 @@ import Upload from "../../../../common/component/upload.vue";
import {getCurrentInstance, onBeforeMount, reactive, ref} from "vue";
import {apiProject} from "../../../../common/request/request";
import {Message} from "@arco-design/web-vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectId:string
@ -35,6 +36,7 @@ const form = reactive({
description: "",
})
const uploadUriId=ref("")
const {t}=useI18n()
const onUpload=(id:string)=> {
uploadUriId.value=id
}
@ -63,7 +65,7 @@ const onSubmit=async ()=>{
})
})
if(res?.code==0) {
Message.success("save success")
Message.success(t("tip.saveSuccess"))
} else {
Message.error(res.msg)
}

View File

@ -1,12 +1,12 @@
<template>
<a-form layout="inline" :model="form" @submitSuccess="onSubmit">
<a-form-item label="issue type solution" field="issueTypeSolutionId" required>
<a-form-item :label="$t('util.issueSolution')" field="issueTypeSolutionId" required>
<a-select v-model="form.issueTypeSolutionId" allow-search>
<a-option v-for="item in issueSolutionList" :label="item.name" :value="item.id"></a-option>
</a-select>
</a-form-item>
<a-form-item>
<a-button html-type="submit" type="primary">Save</a-button>
<a-button html-type="submit" type="primary">{{$t("util.save")}}</a-button>
</a-form-item>
</a-form>
</template>
@ -20,6 +20,7 @@ import {getRootNavigatorRef} from "../../../../../teamOS/common/component/naviga
import {Message} from "@arco-design/web-vue";
import ProjectSettingIssueSolutionConvert
from "@/business/controller/app/project/setting/projectSettingIssueSolutionConvert.vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectId:string
@ -30,9 +31,10 @@ const form=reactive({
const currentIssueTypeSolutionId=ref("")
const appContext=getCurrentInstance().appContext
const root=getRootNavigatorRef()
const {t}=useI18n()
const issueSolutionList=ref<DCSType<ICommon_Model_Issue_Type_Solution>[]>([])
const onSubmit=async ()=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to switch to this issue type solution?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.switchIssueSolution"))
if(ret) {
let res=await apiIssue.count({
projectId:props.projectId
@ -44,7 +46,7 @@ const onSubmit=async ()=>{
issueTypeSolutionId:form.issueTypeSolutionId
})
if(res?.code==0) {
Message.success("bind success")
Message.success(t("tip.bindSuccess"))
currentIssueTypeSolutionId.value=form.issueTypeSolutionId
} else {
Message.error(res.msg)

View File

@ -1,6 +1,6 @@
<template>
<div>
<a-button @click="onAddRole" type="primary" style="margin-bottom: 10px">Add</a-button>
<a-button @click="onAddRole" type="primary" style="margin-bottom: 10px">{{$t("util.add")}}</a-button>
<a-table :columns="columns" :data="roleList" :pagination="false">
<template #description="{record}">
{{record.description}}
@ -17,8 +17,8 @@
<template #operation="{record}">
<template v-if="!record.global">
<a-space wrap>
<a-button type="primary" size="small" @click="onEditRole(record)">manage</a-button>
<a-button status="danger" size="small" @click="onDeleteRole(record)">delete</a-button>
<a-button type="primary" size="small" @click="onEditRole(record)">{{$t("util.manage")}}</a-button>
<a-button status="danger" size="small" @click="onDeleteRole(record)">{{$t("util.delete")}}</a-button>
</a-space>
</template>
</template>
@ -34,6 +34,7 @@ import {apiProject} from "../../../../common/request/request";
import {Message} from "@arco-design/web-vue";
import {getRootNavigatorRef} from "../../../../../teamOS/common/component/navigator/navigator";
import EditProjectRole from "../../setting/role/project/editProjectRole.vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
projectId:string
@ -49,25 +50,26 @@ type RoleItem={
global:boolean,
permissions:Permission_Base[]
}
const {t}=useI18n()
const columns=[
{
title:"name",
title:t("util.name"),
dataIndex:"name"
},
{
title:"description",
title:t("util.description"),
slotName:"description"
},
{
title:"permission",
title:t("util.permission"),
slotName:"permission"
},
{
title:"global",
title:t("util.global"),
slotName: "global"
},
{
title:"operation",
title:t("util.operation"),
slotName: "operation"
}
]
@ -103,13 +105,13 @@ const onEditRole=async (item:RoleItem) =>{
}
}
const onDeleteRole=async (item:RoleItem)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to delete this role?")
let ret=await Dialog.confirm(root.value,appContext,t("tip.deleteRole"))
if(ret) {
let res=await apiProject.removeRole({
roleId:item.id
})
if(res?.code==0) {
Message.success("remove success")
Message.success(t("tip.deleteSuccess"))
listRole()
} else {
Message.error(res.msg);

View File

@ -15,22 +15,22 @@
<template #split>
|
</template>
<a-statistic title="Project Total" :value="staticInfo?.projectCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.setting.home.settingHome.projectTotal')" :value="staticInfo?.projectCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="Issue Total" :value="staticInfo?.issueCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.setting.home.settingHome.issueTotal')" :value="staticInfo?.issueCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="Wiki Space Total" :value="staticInfo?.wikiSpaceCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.setting.home.settingHome.wikiSpaceTotal')" :value="staticInfo?.wikiSpaceCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="Wiki Item Total" :value="staticInfo?.wikiItemCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.setting.home.settingHome.wikiItemTotal')" :value="staticInfo?.wikiItemCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="User Total" :value="staticInfo?.userCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.setting.home.settingHome.userTotal')" :value="staticInfo?.userCount" show-group-separator :value-style="{
color:'blue'
}"/>
<a-statistic title="Team Total" :value="staticInfo?.teamCount" show-group-separator :value-style="{
<a-statistic :title="$t('controller.app.setting.home.settingHome.teamTotal')" :value="staticInfo?.teamCount" show-group-separator :value-style="{
color:'blue'
}"/>
</a-space>
@ -74,6 +74,7 @@ import {
} from 'echarts/components';
import {LabelLayout, UniversalTransition} from 'echarts/features';
import {CanvasRenderer} from 'echarts/renderers';
import {useI18n} from "vue-i18n";
echarts.use([
TitleComponent,
@ -89,30 +90,31 @@ echarts.use([
const projectWithIssueEle=ref(),projectWithUnDoneIssueEle=ref(),wikiSpaceWithWikiItemEle=ref(),teamWithUserEle=ref()
let projectWithIssueChart:EChartsType,projectWithUnDoneIssueChart:EChartsType,wikiSpaceWithWikiItemChart:EChartsType,teamWithUserChart:EChartsType
const {t}=useI18n()
const data = [
{
id: "statics",
name: "Statics",
name: t("controller.app.setting.home.settingHome.statics"),
data: null
},
{
id: "projectWithIssueList",
name: "Projects With Issues Chart",
name: t("controller.app.setting.home.settingHome.projectWithIssueList"),
data: null
},
{
id: "projectWithUnDoneIssueList",
name: "Project With UnResolved Issues Chart",
name: t("controller.app.setting.home.settingHome.projectWithUnDoneIssueList"),
data: null
},
{
id: "wikiSpaceWithWikiItemList",
name: "Wiki Space Chart",
name: t("controller.app.setting.home.settingHome.wikiSpaceWithWikiItemList"),
data: null
},
{
id: "teamWithUserList",
name: "Team Chart",
name: t("controller.app.setting.home.settingHome.teamWithUserList"),
data: null
},
]
@ -128,6 +130,9 @@ const getInfo=async ()=>{
const initCharts=()=>{
projectWithIssueChart=echarts.init(projectWithIssueEle.value)
projectWithIssueChart.setOption({
grid:{
left:60
},
dataset:{
source:[
["count","name"],
@ -143,7 +148,12 @@ const initCharts=()=>{
},
yAxis: {
name:"Project",
type: 'category'
type: 'category',
axisLabel:{
show:true,
overflow:"breakAll",
width:40
}
},
series: [
{
@ -158,6 +168,9 @@ const initCharts=()=>{
})
projectWithUnDoneIssueChart=echarts.init(projectWithUnDoneIssueEle.value)
projectWithUnDoneIssueChart.setOption({
grid:{
left:60
},
dataset:{
source:[
["count","name"],
@ -173,7 +186,12 @@ const initCharts=()=>{
},
yAxis: {
name:"Project",
type: 'category'
type: 'category',
axisLabel:{
show:true,
overflow:"breakAll",
width:40
}
},
series: [
{
@ -188,6 +206,9 @@ const initCharts=()=>{
})
wikiSpaceWithWikiItemChart=echarts.init(wikiSpaceWithWikiItemEle.value)
wikiSpaceWithWikiItemChart.setOption({
grid:{
left:60
},
dataset:{
source:[
["count","name"],
@ -203,7 +224,12 @@ const initCharts=()=>{
},
yAxis: {
name:"Wiki Space",
type: 'category'
type: 'category',
axisLabel:{
show:true,
overflow:"breakAll",
width:40
}
},
series: [
{
@ -218,6 +244,9 @@ const initCharts=()=>{
})
teamWithUserChart=echarts.init(teamWithUserEle.value)
teamWithUserChart.setOption({
grid:{
left:60
},
dataset:{
source:[
["count","name"],
@ -233,7 +262,12 @@ const initCharts=()=>{
},
yAxis: {
name:"Team",
type: 'category'
type: 'category',
axisLabel:{
show:true,
overflow:"breakAll",
width:50
}
},
series: [
{

View File

@ -1,7 +1,7 @@
<template>
<a-form :model="form" style="width: 80%" ref="eleForm">
<a-form-item field="workflowNodeId" label="issue type" required>
<a-cascader :options="data" v-model="form.workflowNodeId" :field-names="fields" placeholder="please select" allow-search></a-cascader>
<a-form-item field="workflowNodeId" :label="$t('util.issueType')" required>
<a-cascader :options="data" v-model="form.workflowNodeId" :field-names="fields" :placeholder="$t('placeholder.pleaseSelect')" allow-search></a-cascader>
</a-form-item>
</a-form>
</template>

View File

@ -1,6 +1,6 @@
<template>
<a-form :model="form" style="width: 80%" ref="eleForm">
<a-form-item label="fieldTypeId" required>
<a-form-item filed="fieldTypeId" :label="$t('util.fieldType')" required>
<a-select v-model="form.fieldTypeId">
<a-option label="Switch" :value="ECommon_Field_Type.SWITCH"></a-option>
<a-option label="Multi Select" :value="ECommon_Field_Type.MULTISELECT"></a-option>
@ -13,10 +13,10 @@
<a-option label="Date" :value="ECommon_Field_Type.DATE"></a-option>
</a-select>
</a-form-item>
<a-form-item label="name" required>
<a-form-item field="name" :label="$t('util.name')" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item label="description">
<a-form-item field="description" :label="$t('util.description')">
<a-textarea v-model="form.description"></a-textarea>
</a-form-item>
</a-form>

View File

@ -1,15 +1,15 @@
<template>
<a-form style="width: 80%" :model="form" ref="eleForm">
<a-form-item field="status" label="type" required>
<a-form-item field="status" :label="$t('util.type')" required>
<a-select v-model="form.status">
<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.INPROGRESS">{{$t("util.inProgress")}}</a-option>
<a-option :value="ECommon_Model_Workflow_Node_Status.DONE">{{$t("util.done")}}</a-option>
</a-select>
</a-form-item>
<a-form-item field="name" label="name" required>
<a-form-item field="name" :label="$t('util.name')" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item field="description" label="description" required>
<a-form-item field="description" :label="$t('util.description')" required>
<a-textarea v-model="form.description" allow-clear></a-textarea>
</a-form-item>
</a-form>

View File

@ -1,12 +1,12 @@
<template>
<div ref="root">
<a-space>
<a-input-search @search="onSearch" v-model="keyword" style="width: 300px" search-button placeholder="please type project name"></a-input-search>
<a-button type="primary" @click="onBind">Bind</a-button>
<a-input-search @search="onSearch" v-model="keyword" style="width: 300px" search-button :placeholder="$t('placeholder.typeProjectName')"></a-input-search>
<a-button type="primary" @click="onBind">{{$t("util.bind")}}</a-button>
</a-space>
<a-table style="margin-top: 10px" :columns="columns" :data="data" :pagination="pagination" @pageChange="onPageChange">
<template #operation="{record}" v-if="!reserved">
<a-button size="small" type="primary" status="danger" @click="onUnBind(record)">Revoke</a-button>
<a-button size="small" type="primary" status="danger" @click="onUnBind(record)">{{$t("util.revoke")}}</a-button>
</template>
</a-table>
</div>
@ -21,23 +21,24 @@ import {ICommon_Model_Project} from "../../../../../../../common/model/project";
import EditBindProject from "./editBindProject.vue";
import ProjectSettingIssueSolutionConvert
from "@/business/controller/app/project/setting/projectSettingIssueSolutionConvert.vue";
import {useI18n} from "vue-i18n";
const props=defineProps<{
issueTypeSolutionId:string,
reserved:number
}>()
const {t}=useI18n()
const columns=[
{
title:"name",
title:t("util.name"),
dataIndex:"name"
},
{
title:"description",
title:t("util.description"),
dataIndex:"description"
},
{
title:"operation",
title:t("util.operation"),
slotName: "operation"
}
]
@ -80,7 +81,7 @@ const onBind=async ()=>{
}
}
const onUnBind=async (item:DCSType<ICommon_Model_Project>)=>{
let ret=await Dialog.confirm(root.value,appContext,"Do you want to unbind this project with this issue type solution")
let ret=await Dialog.confirm(root.value,appContext,t("tip.unbindProjectFromIssueSolution"))
if(ret) {
let res=await apiIssue.count({
projectId:item.id
@ -91,7 +92,7 @@ const onUnBind=async (item:DCSType<ICommon_Model_Project>)=>{
projectId:item.id
})
if(res?.code==0) {
Message.success("remove success")
Message.success(t("tip.deleteSuccess"))
search(pagination.current)
}
} else {

View File

@ -1,6 +1,6 @@
<template>
<a-form :model="form" ref="eleForm" style="width: 80%" auto-label-width>
<a-form-item field="projectId" label="project" required>
<a-form-item field="projectId" :label="$t('util.project')" required>
<a-select @search="onSearch" v-model="form.projectId" allow-search @change="onChange">
<a-option v-for="item in projectList" :value="item.id" :label="item.name"></a-option>
</a-select>

View File

@ -1,9 +1,9 @@
<template>
<a-form ref="eleForm" :model="form" style="width: 80%">
<a-form-item field="name" label="name" required>
<a-form-item field="name" :label="$t('util.name')" required>
<a-input v-model="form.name"></a-input>
</a-form-item>
<a-form-item field="description" label="description">
<a-form-item field="description" :label="$t('util.description')">
<a-textarea v-model="form.description" allow-clear></a-textarea>
</a-form-item>
</a-form>

Some files were not shown because too many files have changed in this diff Show More