feat: workflow

This commit is contained in:
wangdan-fit2cloud 2025-07-01 21:22:21 +08:00
parent 3e3c40de76
commit c7214a6e56
6 changed files with 205 additions and 153 deletions

View File

@ -86,10 +86,10 @@ const ApplicationDetailRouter = {
path: 'chat-user',
name: 'applicationChatUser',
meta: {
icon: 'app-document',
iconActive: 'app-document-active',
icon: 'app-user-chat',
iconActive: 'app-user-chat',
title: 'views.chatUser.title',
active: 'chat-log',
active: 'chat-user',
parentPath: '/application/:id/:type',
parentName: 'ApplicationDetail',
resourceType: SourceTypeEnum.APPLICATION,

View File

@ -75,8 +75,8 @@ const DocumentRouter = {
path: 'chat-user',
name: 'KnowledgeChatUser',
meta: {
icon: 'app-document',
iconActive: 'app-document-active',
icon: 'app-user-chat',
iconActive: 'app-user-chat',
title: 'views.chatUser.title',
active: 'chat-log',
parentPath: '/knowledge/:id/:folderId',
@ -98,14 +98,19 @@ const DocumentRouter = {
if (to.params.folderId == 'shared') {
return PermissionConst.SHARED_KNOWLEDGE_CHAT_USER_READ
} else {
return PermissionConst.KNOWLEDGE_CHAT_USER_READ.getKnowledgeWorkspaceResourcePermission(to ? to.params.id : '',)
return PermissionConst.KNOWLEDGE_CHAT_USER_READ.getKnowledgeWorkspaceResourcePermission(
to ? to.params.id : '',
)
}
},
() => {
const to: any = get_next_route()
if (to.params.folder_id == 'shared') {
return RoleConst.ADMIN
} else { return PermissionConst.KNOWLEDGE_CHAT_USER_READ.getWorkspacePermissionWorkspaceManageRole }
} else {
return PermissionConst.KNOWLEDGE_CHAT_USER_READ
.getWorkspacePermissionWorkspaceManageRole
}
},
],
},

View File

@ -507,6 +507,16 @@ h5 {
border: none !important;
}
/*
图标旋转90度
*/
.rotate-90 {
transform: rotateZ(90deg);
}
.rotate-180 {
transform: rotateZ(180deg);
}
/*
内容部分 自适应高度
*/

View File

@ -1,9 +1,12 @@
<template>
<div v-show="show" class="workflow-dropdown-menu border border-r-6">
<el-tabs v-model="activeName" class="workflow-dropdown-tabs">
<div style="display: flex; width: 100%; justify-content: center;" class="mb-12">
<el-input v-model="search_text" class="mr-12 ml-12"
:placeholder="$t('views.applicationWorkflow.searchBar.placeholder')">
<div style="display: flex; width: 100%; justify-content: center" class="mb-12">
<el-input
v-model="search_text"
class="mr-12 ml-12"
:placeholder="$t('views.applicationWorkflow.searchBar.placeholder')"
>
<template #suffix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
@ -14,23 +17,39 @@
<el-scrollbar height="400">
<div v-if="filter_menu_nodes.length > 0">
<template v-for="(node, index) in filter_menu_nodes" :key="index">
<el-text type="info" size="small" class="color-secondary ml-12">{{ node.label }}</el-text>
<el-text type="info" size="small" class="color-secondary ml-12">{{
node.label
}}</el-text>
<div class="flex-wrap mt-8">
<template v-for="(item, index) in node.list" :key="index">
<el-popover placement="right" :width="280">
<template #reference>
<div class="flex align-center border border-r-6 mb-12 p-8-12 cursor ml-12" style="width: 39%; " @click.stop="clickNodes(item)"
@mousedown.stop="onmousedown(item)">
<component :is="iconComponent(`${item.type}-icon`)" class="mr-8" :size="32" />
<div
class="flex align-center border border-r-6 mb-12 p-8-12 cursor ml-12"
style="width: 39%"
@click.stop="clickNodes(item)"
@mousedown.stop="onmousedown(item)"
>
<component
:is="iconComponent(`${item.type}-icon`)"
class="mr-8"
:size="32"
/>
<div class="lighter">{{ item.label }}</div>
</div>
</template>
<template #default>
<div class="flex align-center mb-8">
<component :is="iconComponent(`${item.type}-icon`)" class="mr-8" :size="32" />
<component
:is="iconComponent(`${item.type}-icon`)"
class="mr-8"
:size="32"
/>
<div class="lighter color-text-primary">{{ item.label }}</div>
</div>
<el-text type="info" size="small" class="color-secondary lighter">{{ item.text }}</el-text>
<el-text type="info" size="small" class="color-secondary lighter">{{
item.text
}}</el-text>
</template>
</el-popover>
</template>
@ -174,21 +193,21 @@ const filter_application_list = computed(() => {
})
const filter_menu_nodes = computed(() => {
if (!search_text.value) return menuNodes;
const searchTerm = search_text.value.toLowerCase();
if (!search_text.value) return menuNodes
const searchTerm = search_text.value.toLowerCase()
return menuNodes.reduce((result: any[], item) => {
const filteredList = item.list.filter(listItem =>
listItem.label.toLowerCase().includes(searchTerm)
);
const filteredList = item.list.filter((listItem) =>
listItem.label.toLowerCase().includes(searchTerm),
)
if (filteredList.length) {
result.push({ ...item, list: filteredList });
result.push({ ...item, list: filteredList })
}
return result;
}, []);
});
return result
}, [])
})
function clickNodes(item: any, data?: any, type?: string) {
if (data) {
item['properties']['stepName'] = data.name
@ -215,10 +234,10 @@ function clickNodes(item: any, data?: any, type?: string) {
...(!fileUploadSetting
? {}
: {
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
}
} else {
item['properties']['node_data'] = {
@ -260,10 +279,10 @@ function onmousedown(item: any, data?: any, type?: string) {
...(!fileUploadSetting
? {}
: {
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
}
} else {
item['properties']['node_data'] = {
@ -301,7 +320,7 @@ onMounted(() => {
user-select: none; /* CSS3属性 */
position: absolute;
top: 49px;
right: 122px;
right: 16px;
z-index: 99;
width: 400px;
box-shadow: 0px 4px 8px 0px var(--app-text-color-light-1);

View File

@ -1,31 +1,30 @@
<template>
<ContentContainer>
<template #header>
<div>
<h2>{{ $t('views.chatUser.title') }}</h2>
<div class="color-secondary">
{{
resource.resource_type === SourceTypeEnum.APPLICATION
? $t('views.chatUser.applicationTitleTip')
: $t('views.chatUser.knowledgeTitleTip')
}}
</div>
<div class="group p-16-24">
<div class="mb-16">
<h2>{{ $t('views.chatUser.title') }}</h2>
<div class="color-secondary">
{{
resource.resource_type === SourceTypeEnum.APPLICATION
? $t('views.chatUser.applicationTitleTip')
: $t('views.chatUser.knowledgeTitleTip')
}}
</div>
</template>
<el-card style="--el-card-padding: 0" class="user-card">
<div class="flex h-full">
</div>
<el-card style="--el-card-padding: 0">
<div class="flex">
<div class="user-left border-r p-16">
<div class="user-left_title">
<div class="p-8 pb-0 mb-12">
<h4 class="medium">{{ $t('views.chatUser.group.title') }}</h4>
</div>
<div class="p-8">
<el-input
v-model="filterText"
:placeholder="$t('common.search')"
prefix-icon="Search"
clearable
/>
</div>
<el-input
v-model="filterText"
:placeholder="$t('common.search')"
prefix-icon="Search"
clearable
class="mb-8"
/>
<div class="list-height-left">
<el-scrollbar v-loading="loading">
<common-list :data="filterList" @click="clickUserGroup" :default-active="current?.id">
@ -46,11 +45,8 @@
<div class="flex align-center">
<h4 class="medium">{{ current?.name }}</h4>
<el-divider direction="vertical" class="mr-8 ml-8" />
<AppIcon
iconName="app-workspace"
style="font-size: 16px"
class="color-input-placeholder"
></AppIcon>
<el-icon class="color-input-placeholder"><UserFilled /></el-icon>
<span class="color-input-placeholder ml-4">
{{ paginationConfig.total }}
</span>
@ -162,13 +158,12 @@
</div>
</div>
</el-card>
</ContentContainer>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch, reactive, computed } from 'vue'
import ChatUserApi from '@/api/chat-user/chat-user'
import SharedChatUserApi from '@/api/system-shared/chat-user'
import { t } from '@/locales'
import type { ChatUserGroupItem, ChatUserGroupUserItem } from '@/api/type/workspaceChatUser'
import { useRoute } from 'vue-router'
@ -367,38 +362,13 @@ async function handleSave() {
</script>
<style lang="scss" scoped>
.content-container {
height: 100%;
display: flex;
flex-direction: column;
:deep(.content-container__main) {
flex: 1;
overflow: hidden;
}
}
:deep(.user-card) {
height: 100%;
overflow: hidden;
}
.user-left {
box-sizing: border-box;
width: var(--setting-left-width);
min-width: var(--setting-left-width);
.user-left_title {
padding: 8px;
}
.list-height-left {
height: calc(100vh - 271px);
:deep(.common-list li) {
padding-right: 4px;
padding-left: 8px;
}
}
}

View File

@ -24,11 +24,17 @@
v-hasPermission="
new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[PermissionConst.WORKSPACE_USER_GROUP_CREATE, PermissionConst.USER_GROUP_CREATE],
[],'OR',)"
[
PermissionConst.WORKSPACE_USER_GROUP_CREATE,
PermissionConst.USER_GROUP_CREATE,
],
[],
'OR',
)
"
>
<el-icon :size="18">
<Plus/>
<Plus />
</el-icon>
</el-button>
</el-tooltip>
@ -59,7 +65,7 @@
<el-dropdown :teleported="false">
<el-button text>
<el-icon class="color-secondary">
<MoreFilled/>
<MoreFilled />
</el-icon>
</el-button>
<template #dropdown>
@ -67,26 +73,46 @@
<el-dropdown-item
@click.stop="createOrUpdate(row)"
class="p-8"
v-if="hasPermission(new ComplexPermission(
v-if="
hasPermission(
new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[PermissionConst.WORKSPACE_USER_GROUP_EDIT, PermissionConst.USER_GROUP_EDIT],
[],'OR',),'OR',)"
[
PermissionConst.WORKSPACE_USER_GROUP_EDIT,
PermissionConst.USER_GROUP_EDIT,
],
[],
'OR',
),
'OR',
)
"
>
<el-icon>
<EditPen/>
<EditPen />
</el-icon>
{{ $t('common.rename') }}
</el-dropdown-item>
<el-dropdown-item
@click.stop="deleteGroup(row)"
class="border-t p-8"
v-if="hasPermission(new ComplexPermission(
v-if="
hasPermission(
new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[PermissionConst.WORKSPACE_USER_GROUP_DELETE, PermissionConst.USER_GROUP_DELETE],
[],'OR',),'OR',)"
[
PermissionConst.WORKSPACE_USER_GROUP_DELETE,
PermissionConst.USER_GROUP_DELETE,
],
[],
'OR',
),
'OR',
)
"
>
<el-icon>
<Delete/>
<Delete />
</el-icon>
{{ $t('common.delete') }}
</el-dropdown-item>
@ -108,7 +134,7 @@
<div class="user-right" v-loading="rightLoading">
<div class="flex align-center">
<h4 class="medium">{{ current?.name }}</h4>
<el-divider direction="vertical" class="mr-8 ml-8"/>
<el-divider direction="vertical" class="mr-8 ml-8" />
<AppIcon
iconName="app-workspace"
style="font-size: 16px"
@ -127,8 +153,14 @@
v-hasPermission="
new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[PermissionConst.WORKSPACE_USER_GROUP_ADD_MEMBER, PermissionConst.USER_GROUP_ADD_MEMBER],
[],'OR',)"
[
PermissionConst.WORKSPACE_USER_GROUP_ADD_MEMBER,
PermissionConst.USER_GROUP_ADD_MEMBER,
],
[],
'OR',
)
"
>
{{ t('views.role.member.add') }}
</el-button>
@ -138,17 +170,25 @@
v-hasPermission="
new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[PermissionConst.WORKSPACE_USER_GROUP_REMOVE_MEMBER, PermissionConst.USER_GROUP_REMOVE_MEMBER],
[],'OR',)"
[
PermissionConst.WORKSPACE_USER_GROUP_REMOVE_MEMBER,
PermissionConst.USER_GROUP_REMOVE_MEMBER,
],
[],
'OR',
)
"
>
{{ $t('common.remove') }}
</el-button>
</div>
<div class="flex-between complex-search">
<el-select class="complex-search__left" v-model="searchType" style="width: 120px">
<el-option :label="$t('views.login.loginForm.username.label')" value="username"/>
<el-option :label="$t('views.userManage.userForm.nick_name.label')"
value="nick_name"/>
<el-option :label="$t('views.login.loginForm.username.label')" value="username" />
<el-option
:label="$t('views.userManage.userForm.nick_name.label')"
value="nick_name"
/>
</el-select>
<el-input
v-if="searchType === 'username'"
@ -176,12 +216,12 @@
@changePage="getList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55"/>
<el-table-column type="selection" width="55" />
<el-table-column
prop="nick_name"
:label="$t('views.userManage.userForm.nick_name.label')"
/>
<el-table-column prop="username" :label="$t('views.login.loginForm.username.label')"/>
<el-table-column prop="username" :label="$t('views.login.loginForm.username.label')" />
<el-table-column prop="source" :label="$t('views.userManage.source.label')">
<template #default="{ row }">
{{
@ -209,11 +249,17 @@
v-hasPermission="
new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[PermissionConst.WORKSPACE_USER_GROUP_REMOVE_MEMBER, PermissionConst.USER_GROUP_REMOVE_MEMBER],
[],'OR',)"
[
PermissionConst.WORKSPACE_USER_GROUP_REMOVE_MEMBER,
PermissionConst.USER_GROUP_REMOVE_MEMBER,
],
[],
'OR',
)
"
>
<el-icon>
<EditPen/>
<EditPen />
</el-icon>
</el-button>
</el-tooltip>
@ -224,24 +270,24 @@
</div>
</el-card>
<CreateOrUpdateGroupDialog ref="createOrUpdateGroupDialogRef" @refresh="refresh"/>
<CreateGroupUserDialog ref="createGroupUserDialogRef" @refresh="getList"/>
<CreateOrUpdateGroupDialog ref="createOrUpdateGroupDialogRef" @refresh="refresh" />
<CreateGroupUserDialog ref="createGroupUserDialogRef" @refresh="getList" />
</div>
</template>
<script lang="ts" setup>
import {onMounted, ref, watch, reactive} from 'vue'
import { onMounted, ref, watch, reactive } from 'vue'
import SystemGroupApi from '@/api/system/user-group'
import {t} from '@/locales'
import type {ChatUserGroupUserItem} from '@/api/type/systemChatUser'
import { t } from '@/locales'
import type { ChatUserGroupUserItem } from '@/api/type/systemChatUser'
import CreateOrUpdateGroupDialog from './component/CreateOrUpdateGroupDialog.vue'
import CreateGroupUserDialog from './component/CreateGroupUserDialog.vue'
import type {ListItem} from '@/api/type/common'
import {MsgSuccess, MsgConfirm} from '@/utils/message'
import {PermissionConst, RoleConst} from '@/utils/permission/data'
import {ComplexPermission} from '@/utils/permission/type'
import {hasPermission} from '@/utils/permission/index'
import {loadPermissionApi} from "@/utils/dynamics-api/permission-api.ts";
import type { ListItem } from '@/api/type/common'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { PermissionConst, RoleConst } from '@/utils/permission/data'
import { ComplexPermission } from '@/utils/permission/type'
import { hasPermission } from '@/utils/permission/index'
import { loadPermissionApi } from '@/utils/dynamics-api/permission-api.ts'
const filterText = ref('')
const loading = ref(false)
@ -295,23 +341,24 @@ function deleteGroup(item: ListItem) {
},
)
.then(() => {
loadPermissionApi('userGroup').delUserGroup(item.id as string, loading).then(async () => {
MsgSuccess(t('common.deleteSuccess'))
await getUserGroupList()
current.value = item.id === current.value?.id ? list.value[0] : current.value
})
})
.catch(() => {
loadPermissionApi('userGroup')
.delUserGroup(item.id as string, loading)
.then(async () => {
MsgSuccess(t('common.deleteSuccess'))
await getUserGroupList()
current.value = item.id === current.value?.id ? list.value[0] : current.value
})
})
.catch(() => {})
}
async function refresh(group?: ListItem) {
await getUserGroupList()
//
if (group) {
if (group) {
current.value = group
} else {
current.value = list.value.find(item => item.id === current.value?.id)
current.value = list.value.find((item) => item.id === current.value?.id)
}
}
@ -377,7 +424,7 @@ function handleDeleteUser(item?: ChatUserGroupUserItem) {
MsgConfirm(
item
? `${t('views.workspace.member.delete.confirmTitle')}${item.nick_name} ?`
: t('views.chatUser.group.batchDeleteMember', {count: multipleSelection.value.length}),
: t('views.chatUser.group.batchDeleteMember', { count: multipleSelection.value.length }),
'',
{
confirmButtonText: t('common.confirm'),
@ -385,21 +432,22 @@ function handleDeleteUser(item?: ChatUserGroupUserItem) {
},
)
.then(() => {
loadPermissionApi('userGroup').postRemoveMember(
current.value?.id as string,
{
group_relation_ids: item
? [item.user_group_relation_id]
: multipleSelection.value.map((item) => item.user_group_relation_id),
},
loading,
).then(async () => {
MsgSuccess(t('common.removeSuccess'))
await getList()
})
})
.catch(() => {
loadPermissionApi('userGroup')
.postRemoveMember(
current.value?.id as string,
{
group_relation_ids: item
? [item.user_group_relation_id]
: multipleSelection.value.map((item) => item.user_group_relation_id),
},
loading,
)
.then(async () => {
MsgSuccess(t('common.removeSuccess'))
await getList()
})
})
.catch(() => {})
}
const mouseId = ref('')