feat: 应用、知识库、函数库增加创建者

--story=1016834 --user=王孝刚 应用、知识库、函数增加创建者,可以按创建用户查看资源 #1304 https://www.tapd.cn/57709429/s/1605886
This commit is contained in:
wxg0103 2024-11-05 11:52:56 +08:00 committed by wxg0103
parent 81b8e522e6
commit f318f2da40
14 changed files with 323 additions and 66 deletions

View File

@ -19,8 +19,10 @@ from django.conf import settings
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.core import cache, validators from django.core import cache, validators
from django.core import signing from django.core import signing
from django.core.paginator import Paginator
from django.db import transaction, models from django.db import transaction, models
from django.db.models import QuerySet from django.db.models import QuerySet, Q
from django.forms import CharField
from django.http import HttpResponse from django.http import HttpResponse
from django.template import Template, Context from django.template import Template, Context
from rest_framework import serializers from rest_framework import serializers
@ -44,7 +46,7 @@ from dataset.models import DataSet, Document, Image
from dataset.serializers.common_serializers import list_paragraph, get_embedding_model_by_dataset_id_list from dataset.serializers.common_serializers import list_paragraph, get_embedding_model_by_dataset_id_list
from embedding.models import SearchMode from embedding.models import SearchMode
from function_lib.serializers.function_lib_serializer import FunctionLibSerializer from function_lib.serializers.function_lib_serializer import FunctionLibSerializer
from setting.models import AuthOperate from setting.models import AuthOperate, TeamMember, TeamMemberPermission
from setting.models.model_management import Model from setting.models.model_management import Model
from setting.models_provider import get_model_credential from setting.models_provider import get_model_credential
from setting.models_provider.constants.model_provider_constants import ModelProvideConstants from setting.models_provider.constants.model_provider_constants import ModelProvideConstants
@ -559,17 +561,22 @@ class ApplicationSerializer(serializers.Serializer):
desc = serializers.CharField(required=False, error_messages=ErrMessage.char("应用描述")) desc = serializers.CharField(required=False, error_messages=ErrMessage.char("应用描述"))
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id")) user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))
select_user_id = serializers.UUIDField(required=False, error_messages=ErrMessage.uuid("选择用户id"))
def get_query_set(self): def get_query_set(self):
user_id = self.data.get("user_id") user_id = self.data.get("user_id")
query_set_dict = {} query_set_dict = {}
query_set = QuerySet(model=get_dynamics_model( query_set = QuerySet(model=get_dynamics_model(
{'temp_application.name': models.CharField(), 'temp_application.desc': models.CharField(), {'temp_application.name': models.CharField(), 'temp_application.desc': models.CharField(),
'temp_application.create_time': models.DateTimeField()})) 'temp_application.create_time': models.DateTimeField(),
'temp_application.user_id': models.CharField(), }))
if "desc" in self.data and self.data.get('desc') is not None: if "desc" in self.data and self.data.get('desc') is not None:
query_set = query_set.filter(**{'temp_application.desc__icontains': self.data.get("desc")}) query_set = query_set.filter(**{'temp_application.desc__icontains': self.data.get("desc")})
if "name" in self.data and self.data.get('name') is not None: if "name" in self.data and self.data.get('name') is not None:
query_set = query_set.filter(**{'temp_application.name__icontains': self.data.get("name")}) query_set = query_set.filter(**{'temp_application.name__icontains': self.data.get("name")})
if 'select_user_id' in self.data and self.data.get('select_user_id') is not None and self.data.get(
'select_user_id') != 'all':
query_set = query_set.filter(**{'temp_application.user_id__exact': self.data.get('select_user_id')})
query_set = query_set.order_by("-temp_application.create_time") query_set = query_set.order_by("-temp_application.create_time")
query_set_dict['default_sql'] = query_set query_set_dict['default_sql'] = query_set

View File

@ -129,17 +129,21 @@ class DataSetSerializers(serializers.ModelSerializer):
) )
user_id = serializers.CharField(required=True) user_id = serializers.CharField(required=True)
select_user_id = serializers.CharField(required=False)
def get_query_set(self): def get_query_set(self):
user_id = self.data.get("user_id") user_id = self.data.get("user_id")
query_set_dict = {} query_set_dict = {}
query_set = QuerySet(model=get_dynamics_model( query_set = QuerySet(model=get_dynamics_model(
{'temp.name': models.CharField(), 'temp.desc': models.CharField(), {'temp.name': models.CharField(), 'temp.desc': models.CharField(),
"document_temp.char_length": models.IntegerField(), 'temp.create_time': models.DateTimeField()})) "document_temp.char_length": models.IntegerField(), 'temp.create_time': models.DateTimeField(),
'temp.user_id': models.CharField(), }))
if "desc" in self.data and self.data.get('desc') is not None: if "desc" in self.data and self.data.get('desc') is not None:
query_set = query_set.filter(**{'temp.desc__icontains': self.data.get("desc")}) query_set = query_set.filter(**{'temp.desc__icontains': self.data.get("desc")})
if "name" in self.data and self.data.get('name') is not None: if "name" in self.data and self.data.get('name') is not None:
query_set = query_set.filter(**{'temp.name__icontains': self.data.get("name")}) query_set = query_set.filter(**{'temp.name__icontains': self.data.get("name")})
if "select_user_id" in self.data and self.data.get('select_user_id') is not None:
query_set = query_set.filter(**{'temp.user_id__exact': self.data.get("select_user_id")})
query_set = query_set.order_by("-temp.create_time") query_set = query_set.order_by("-temp.create_time")
query_set_dict['default_sql'] = query_set query_set_dict['default_sql'] = query_set

View File

@ -221,7 +221,7 @@ class Dataset(APIView):
def get(self, request: Request, current_page, page_size): def get(self, request: Request, current_page, page_size):
d = DataSetSerializers.Query( d = DataSetSerializers.Query(
data={'name': request.query_params.get('name', None), 'desc': request.query_params.get("desc", None), data={'name': request.query_params.get('name', None), 'desc': request.query_params.get("desc", None),
'user_id': str(request.user.id)}) 'user_id': str(request.user.id), 'select_user_id': request.query_params.get('select_user_id', None)})
d.is_valid() d.is_valid()
return result.success(d.page(current_page, page_size)) return result.success(d.page(current_page, page_size))

View File

@ -98,6 +98,7 @@ class FunctionLibSerializer(serializers.Serializer):
is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char("是否可用")) is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char("是否可用"))
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id")) user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))
select_user_id = serializers.CharField(required=False, allow_null=True, allow_blank=True)
def get_query_set(self): def get_query_set(self):
query_set = QuerySet(FunctionLib).filter( query_set = QuerySet(FunctionLib).filter(
@ -108,6 +109,8 @@ class FunctionLibSerializer(serializers.Serializer):
query_set = query_set.filter(desc__contains=self.data.get('desc')) query_set = query_set.filter(desc__contains=self.data.get('desc'))
if self.data.get('is_active') is not None: if self.data.get('is_active') is not None:
query_set = query_set.filter(is_active=self.data.get('is_active')) query_set = query_set.filter(is_active=self.data.get('is_active'))
if self.data.get('select_user_id') is not None:
query_set = query_set.filter(user_id=self.data.get('select_user_id'))
query_set = query_set.order_by("-create_time") query_set = query_set.order_by("-create_time")
return query_set return query_set

View File

@ -105,5 +105,6 @@ class FunctionLibView(APIView):
FunctionLibSerializer.Query( FunctionLibSerializer.Query(
data={'name': request.query_params.get('name'), data={'name': request.query_params.get('name'),
'desc': request.query_params.get('desc'), 'desc': request.query_params.get('desc'),
'user_id': request.user.id}).page( 'user_id': request.user.id,
'select_user_id': request.query_params.get('select_user_id')}).page(
current_page, page_size)) current_page, page_size))

View File

@ -17,7 +17,7 @@ from django.core import validators, signing, cache
from django.core.mail import send_mail from django.core.mail import send_mail
from django.core.mail.backends.smtp import EmailBackend from django.core.mail.backends.smtp import EmailBackend
from django.db import transaction from django.db import transaction
from django.db.models import Q, QuerySet from django.db.models import Q, QuerySet, Prefetch
from drf_yasg import openapi from drf_yasg import openapi
from rest_framework import serializers from rest_framework import serializers
@ -35,6 +35,7 @@ from common.util.field_message import ErrMessage
from common.util.lock import lock from common.util.lock import lock
from dataset.models import DataSet, Document, Paragraph, Problem, ProblemParagraphMapping from dataset.models import DataSet, Document, Paragraph, Problem, ProblemParagraphMapping
from embedding.task import delete_embedding_by_dataset_id_list from embedding.task import delete_embedding_by_dataset_id_list
from function_lib.models.function import FunctionLib
from setting.models import Team, SystemSetting, SettingType, Model, TeamMember, TeamMemberPermission from setting.models import Team, SystemSetting, SettingType, Model, TeamMember, TeamMemberPermission
from smartdoc.conf import PROJECT_DIR from smartdoc.conf import PROJECT_DIR
from users.models.user import User, password_encrypt, get_user_dynamics_permission from users.models.user import User, password_encrypt, get_user_dynamics_permission
@ -495,6 +496,40 @@ class UserSerializer(ApiMixin, serializers.ModelSerializer):
return [{'id': user_model.id, 'username': user_model.username, 'email': user_model.email} for user_model in return [{'id': user_model.id, 'username': user_model.username, 'email': user_model.email} for user_model in
QuerySet(User).filter(Q(username=email_or_username) | Q(email=email_or_username))] QuerySet(User).filter(Q(username=email_or_username) | Q(email=email_or_username))]
def listByType(self, type, user_id):
teamIds = TeamMember.objects.filter(user_id=user_id).values_list('id', flat=True)
targets = TeamMemberPermission.objects.filter(
member_id__in=teamIds,
auth_target_type=type,
operate__contains=['USE']
).values_list('target', flat=True)
prefetch_users = Prefetch('user', queryset=User.objects.only('id', 'username'))
user_list = []
if type == 'DATASET':
user_list = DataSet.objects.filter(
Q(id__in=targets) | Q(user_id=user_id)
).prefetch_related(prefetch_users).distinct('user_id')
elif type == 'APPLICATION':
user_list = Application.objects.filter(
Q(id__in=targets) | Q(user_id=user_id)
).prefetch_related(prefetch_users).distinct('user_id')
elif type == 'FUNCTION':
user_list = FunctionLib.objects.filter(
Q(permission_type='PUBLIC') | Q(user_id=user_id)
).prefetch_related(prefetch_users).distinct('user_id')
other_users = [
{'id': app.user.id, 'username': app.user.username}
for app in user_list if app.user.id != user_id
]
users = [
{'id': 'all', 'username': '全部'},
{'id': user_id, 'username': '我的'}
]
users.extend(other_users)
return users
class UserInstanceSerializer(ApiMixin, serializers.ModelSerializer): class UserInstanceSerializer(ApiMixin, serializers.ModelSerializer):
class Meta: class Meta:

View File

@ -21,4 +21,5 @@ urlpatterns = [
name="user_manage_re_password"), name="user_manage_re_password"),
path("user_manage/<int:current_page>/<int:page_size>", views.UserManage.Page.as_view(), path("user_manage/<int:current_page>/<int:page_size>", views.UserManage.Page.as_view(),
name="user_manage_re_password"), name="user_manage_re_password"),
path('user/list/<str:type>', views.UserListView.as_view()),
] ]

View File

@ -301,3 +301,16 @@ class UserManage(APIView):
def put(self, request: Request, user_id): def put(self, request: Request, user_id):
return result.success( return result.success(
UserManageSerializer.Operate(data={'id': user_id}).edit(request.data, with_valid=True)) UserManageSerializer.Operate(data={'id': user_id}).edit(request.data, with_valid=True))
class UserListView(APIView):
authentication_classes = [TokenAuth]
@swagger_auto_schema(operation_summary="通过类型获取用户列表",
operation_id="通过类型获取用户列表",
manual_parameters=UserSerializer.Query.get_request_params_api(),
responses=result.get_api_array_response(UserSerializer.Query.get_response_body_api()),
tags=['用户'])
@has_permissions(PermissionConstants.USER_READ)
def get(self, request: Request, type):
return result.success(UserSerializer().listByType(type, request.user.id))

View File

@ -456,6 +456,13 @@ const putWorkFlowVersion: (
) )
} }
const getUserList: (type: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
type,
loading
) => {
return get(`/user/list/${type}`, undefined, loading)
}
export default { export default {
getAllAppilcation, getAllAppilcation,
getApplication, getApplication,
@ -492,5 +499,6 @@ export default {
getWorkFlowVersion, getWorkFlowVersion,
getWorkFlowVersionDetail, getWorkFlowVersionDetail,
putWorkFlowVersion, putWorkFlowVersion,
playDemoText playDemoText,
getUserList
} }

View File

@ -8,9 +8,19 @@
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" /> <img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar> </AppAvatar>
</slot> </slot>
<auto-tooltip :content="title" style="width: 65%"> <div>
<auto-tooltip :content="title" style="width: 65%; height: 22px">
{{ title }} {{ title }}
</auto-tooltip> </auto-tooltip>
<span class="lighter mr-8">
<auto-tooltip
:content="username"
style="display: inline-block; width: 100%; font-size: 12px; height: 20px"
>
创建人: {{ username }}
</auto-tooltip></span
>
</div>
</div> </div>
</slot> </slot>
</div> </div>
@ -49,6 +59,7 @@ const props = withDefaults(
* 是否展示icon * 是否展示icon
*/ */
showIcon?: boolean showIcon?: boolean
username?: string
}>(), }>(),
{ title: '标题', description: '', showIcon: true, border: true } { title: '标题', description: '', showIcon: true, border: true }
) )
@ -62,13 +73,12 @@ function cardEnter() {
} }
function cardLeave() { function cardLeave() {
show.value = subHovered.value; show.value = subHovered.value
} }
function subHoveredEnter() { function subHoveredEnter() {
subHovered.value = true subHovered.value = true
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.card-box { .card-box {

View File

@ -34,7 +34,7 @@
/** card */ /** card */
--card-width: 330px; --card-width: 330px;
--card-min-height: 160px; --card-min-height: 166px;
--card-min-width: 220px; --card-min-width: 220px;
/** setting */ /** setting */

View File

@ -2,6 +2,15 @@
<div class="application-list-container p-24" style="padding-top: 16px"> <div class="application-list-container p-24" style="padding-top: 16px">
<div class="flex-between mb-16"> <div class="flex-between mb-16">
<h4>{{ $t('views.application.applicationList.title') }}</h4> <h4>{{ $t('views.application.applicationList.title') }}</h4>
<div class="flex-between">
<el-select v-model="selectUserId" class="mr-12 w-120" @change="searchHandle">
<el-option
v-for="item in userOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input <el-input
v-model="searchValue" v-model="searchValue"
@change="searchHandle" @change="searchHandle"
@ -11,6 +20,7 @@
clearable clearable
/> />
</div> </div>
</div>
<div v-loading.fullscreen.lock="paginationConfig.current_page === 1 && loading"> <div v-loading.fullscreen.lock="paginationConfig.current_page === 1 && loading">
<InfiniteScroll <InfiniteScroll
:size="applicationList.length" :size="applicationList.length"
@ -39,6 +49,7 @@
> >
<CardBox <CardBox
:title="item.name" :title="item.name"
:username="item.username"
:description="item.desc" :description="item.desc"
class="application-card cursor" class="application-card cursor"
@click="router.push({ path: `/application/${item.id}/${item.type}/overview` })" @click="router.push({ path: `/application/${item.id}/${item.type}/overview` })"
@ -63,8 +74,10 @@
/> />
</template> </template>
<div class="status-tag"> <div class="status-tag">
<el-tag type="warning" v-if="isWorkFlow(item.type)">高级编排</el-tag> <el-tag type="warning" v-if="isWorkFlow(item.type)" style="height: 22px"
<el-tag class="blue-tag" v-else>简单配置</el-tag> >高级编排</el-tag
>
<el-tag class="blue-tag" v-else style="height: 22px">简单配置</el-tag>
</div> </div>
<template #footer> <template #footer>
@ -149,6 +162,14 @@ const paginationConfig = reactive({
page_size: 20, page_size: 20,
total: 0 total: 0
}) })
interface UserOption {
label: string
value: string
}
const userOptions = ref<UserOption[]>([])
const selectUserId = ref('all')
const searchValue = ref('') const searchValue = ref('')
@ -175,7 +196,7 @@ function openCreateDialog() {
} else { } else {
MsgConfirm(`提示`, '社区版最多支持 5 个应用,如需拥有更多应用,请升级为专业版。', { MsgConfirm(`提示`, '社区版最多支持 5 个应用,如需拥有更多应用,请升级为专业版。', {
cancelButtonText: '确定', cancelButtonText: '确定',
confirmButtonText: '购买专业版', confirmButtonText: '购买专业版'
}) })
.then(() => { .then(() => {
window.open('https://maxkb.cn/pricing.html', '_blank') window.open('https://maxkb.cn/pricing.html', '_blank')
@ -193,6 +214,9 @@ function openCreateDialog() {
} }
function searchHandle() { function searchHandle() {
if (user.userInfo) {
localStorage.setItem(user.userInfo.id + 'application', selectUserId.value)
}
paginationConfig.total = 0 paginationConfig.total = 0
paginationConfig.current_page = 1 paginationConfig.current_page = 1
applicationList.value = [] applicationList.value = []
@ -226,16 +250,45 @@ function deleteApplication(row: any) {
} }
function getList() { function getList() {
applicationApi const params = {
.getApplication(paginationConfig, searchValue.value && { name: searchValue.value }, loading) ...(searchValue.value && { name: searchValue.value }),
.then((res) => { ...(selectUserId.value &&
selectUserId.value !== 'all' && { select_user_id: selectUserId.value })
}
applicationApi.getApplication(paginationConfig, params, loading).then((res) => {
res.data.records.forEach((item: any) => {
if (user.userInfo && item.user_id === user.userInfo.id) {
item.username = user.userInfo.username
} else {
item.username = userOptions.value.find((v) => v.value === item.user_id)?.label
}
})
applicationList.value = [...applicationList.value, ...res.data.records] applicationList.value = [...applicationList.value, ...res.data.records]
paginationConfig.total = res.data.total paginationConfig.total = res.data.total
}) })
} }
function getUserList() {
applicationApi.getUserList('APPLICATION', loading).then((res) => {
if (res.data) {
userOptions.value = res.data.map((item: any) => {
return {
label: item.username,
value: item.id
}
})
if (user.userInfo) {
const selectUserIdValue = localStorage.getItem(user.userInfo.id + 'application')
if (selectUserIdValue && userOptions.value.find((v) => v.value === selectUserIdValue)) {
selectUserId.value = selectUserIdValue
}
}
getList()
}
})
}
onMounted(() => { onMounted(() => {
getList() getUserList()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -243,7 +296,7 @@ onMounted(() => {
.status-tag { .status-tag {
position: absolute; position: absolute;
right: 16px; right: 16px;
top: 13px; top: 3px;
} }
} }
.dropdown-custom-switch { .dropdown-custom-switch {

View File

@ -2,15 +2,25 @@
<div class="dataset-list-container p-24" style="padding-top: 16px"> <div class="dataset-list-container p-24" style="padding-top: 16px">
<div class="flex-between mb-16"> <div class="flex-between mb-16">
<h4>知识库</h4> <h4>知识库</h4>
<div class="flex-between">
<el-select v-model="selectUserId" class="mr-12 w-120" @change="searchHandle">
<el-option
v-for="item in userOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input <el-input
v-model="searchValue" v-model="searchValue"
@change="searchHandle" @change="searchHandle"
placeholder="按名称搜索" :placeholder="$t('views.application.applicationList.searchBar.placeholder')"
prefix-icon="Search" prefix-icon="Search"
class="w-240" class="w-240"
clearable clearable
/> />
</div> </div>
</div>
<div v-loading.fullscreen.lock="paginationConfig.current_page === 1 && loading"> <div v-loading.fullscreen.lock="paginationConfig.current_page === 1 && loading">
<InfiniteScroll <InfiniteScroll
:size="datasetList.length" :size="datasetList.length"
@ -28,6 +38,7 @@
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb-16"> <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb-16">
<CardBox <CardBox
:title="item.name" :title="item.name"
:username="item.username"
:description="item.desc" :description="item.desc"
class="cursor" class="cursor"
@click="router.push({ path: `/dataset/${item.id}/document` })" @click="router.push({ path: `/dataset/${item.id}/document` })"
@ -46,8 +57,14 @@
</AppAvatar> </AppAvatar>
</template> </template>
<div class="delete-button"> <div class="delete-button">
<el-tag class="blue-tag" v-if="item.type === '0'">通用型</el-tag> <el-tag class="blue-tag" v-if="item.type === '0'" style="height: 22px"
<el-tag class="purple-tag" v-else-if="item.type === '1'" type="warning" >通用型</el-tag
>
<el-tag
class="purple-tag"
v-else-if="item.type === '1'"
type="warning"
style="height: 22px"
>Web 站点</el-tag >Web 站点</el-tag
> >
</div> </div>
@ -120,6 +137,7 @@ import { useRouter } from 'vue-router'
import { numberFormat } from '@/utils/utils' import { numberFormat } from '@/utils/utils'
import { ValidType, ValidCount } from '@/enums/common' import { ValidType, ValidCount } from '@/enums/common'
import useStore from '@/stores' import useStore from '@/stores'
import applicationApi from '@/api/application'
const { user, common } = useStore() const { user, common } = useStore()
const router = useRouter() const router = useRouter()
@ -136,6 +154,15 @@ const paginationConfig = reactive({
const searchValue = ref('') const searchValue = ref('')
interface UserOption {
label: string
value: string
}
const userOptions = ref<UserOption[]>([])
const selectUserId = ref('all')
function openCreateDialog() { function openCreateDialog() {
if (user.isEnterprise()) { if (user.isEnterprise()) {
CreateDatasetDialogRef.value.open() CreateDatasetDialogRef.value.open()
@ -174,6 +201,9 @@ function syncDataset(row: any) {
} }
function searchHandle() { function searchHandle() {
if (user.userInfo) {
localStorage.setItem(user.userInfo.id + 'dataset', selectUserId.value)
}
paginationConfig.current_page = 1 paginationConfig.current_page = 1
datasetList.value = [] datasetList.value = []
getList() getList()
@ -204,16 +234,46 @@ function deleteDataset(row: any) {
} }
function getList() { function getList() {
datasetApi const params = {
.getDataset(paginationConfig, searchValue.value && { name: searchValue.value }, loading) ...(searchValue.value && { name: searchValue.value }),
.then((res) => { ...(selectUserId.value &&
selectUserId.value !== 'all' && { select_user_id: selectUserId.value })
}
datasetApi.getDataset(paginationConfig, params, loading).then((res) => {
res.data.records.forEach((item: any) => {
if (user.userInfo && item.user_id === user.userInfo.id) {
item.username = user.userInfo.username
} else {
item.username = userOptions.value.find((v) => v.value === item.user_id)?.label
}
})
paginationConfig.total = res.data.total paginationConfig.total = res.data.total
datasetList.value = [...datasetList.value, ...res.data.records] datasetList.value = [...datasetList.value, ...res.data.records]
}) })
} }
onMounted(() => { function getUserList() {
applicationApi.getUserList('DATASET', loading).then((res) => {
if (res.data) {
userOptions.value = res.data.map((item: any) => {
return {
label: item.username,
value: item.id
}
})
if (user.userInfo) {
const selectUserIdValue = localStorage.getItem(user.userInfo.id + 'dataset')
if (selectUserIdValue && userOptions.value.find((v) => v.value === selectUserIdValue)) {
selectUserId.value = selectUserIdValue
}
}
getList() getList()
}
})
}
onMounted(() => {
getUserList()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -221,7 +281,7 @@ onMounted(() => {
.delete-button { .delete-button {
position: absolute; position: absolute;
right: 12px; right: 12px;
top: 13px; top: 3px;
height: auto; height: auto;
} }
.footer-content { .footer-content {

View File

@ -2,6 +2,15 @@
<div class="function-lib-list-container p-24" style="padding-top: 16px"> <div class="function-lib-list-container p-24" style="padding-top: 16px">
<div class="flex-between mb-16"> <div class="flex-between mb-16">
<h4>函数库</h4> <h4>函数库</h4>
<div class="flex-between">
<el-select v-model="selectUserId" class="mr-12 w-120" @change="searchHandle">
<el-option
v-for="item in userOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input <el-input
v-model="searchValue" v-model="searchValue"
@change="searchHandle" @change="searchHandle"
@ -11,6 +20,7 @@
clearable clearable
/> />
</div> </div>
</div>
<div <div
v-loading.fullscreen.lock=" v-loading.fullscreen.lock="
(paginationConfig.current_page === 1 && loading) || changeStateloading (paginationConfig.current_page === 1 && loading) || changeStateloading
@ -41,6 +51,7 @@
<CardBox <CardBox
:title="item.name" :title="item.name"
:description="item.desc" :description="item.desc"
:username="item.username"
class="function-lib-card" class="function-lib-card"
@click="openCreateDialog(item)" @click="openCreateDialog(item)"
:class="item.permission_type === 'PUBLIC' && !canEdit(item) ? '' : 'cursor'" :class="item.permission_type === 'PUBLIC' && !canEdit(item) ? '' : 'cursor'"
@ -51,8 +62,16 @@
</AppAvatar> </AppAvatar>
</template> </template>
<div class="status-button"> <div class="status-button">
<el-tag class="info-tag" v-if="item.permission_type === 'PUBLIC'">公用</el-tag> <el-tag
<el-tag class="danger-tag" v-else-if="item.permission_type === 'PRIVATE'" class="info-tag"
v-if="item.permission_type === 'PUBLIC'"
style="height: 22px"
>公用</el-tag
>
<el-tag
class="danger-tag"
v-else-if="item.permission_type === 'PRIVATE'"
style="height: 22px"
>私有</el-tag >私有</el-tag
> >
</div> </div>
@ -100,6 +119,7 @@ import functionLibApi from '@/api/function-lib'
import FunctionFormDrawer from './component/FunctionFormDrawer.vue' import FunctionFormDrawer from './component/FunctionFormDrawer.vue'
import { MsgSuccess, MsgConfirm } from '@/utils/message' import { MsgSuccess, MsgConfirm } from '@/utils/message'
import useStore from '@/stores' import useStore from '@/stores'
import applicationApi from '@/api/application'
const { user } = useStore() const { user } = useStore()
const loading = ref(false) const loading = ref(false)
@ -118,6 +138,15 @@ const searchValue = ref('')
const title = ref('') const title = ref('')
const changeStateloading = ref(false) const changeStateloading = ref(false)
interface UserOption {
label: string
value: string
}
const userOptions = ref<UserOption[]>([])
const selectUserId = ref('all')
const canEdit = (row: any) => { const canEdit = (row: any) => {
return user.userInfo?.id === row?.user_id return user.userInfo?.id === row?.user_id
} }
@ -134,6 +163,9 @@ function openCreateDialog(data?: any) {
} }
function searchHandle() { function searchHandle() {
if (user.userInfo) {
localStorage.setItem(user.userInfo.id + 'function', selectUserId.value)
}
paginationConfig.total = 0 paginationConfig.total = 0
paginationConfig.current_page = 1 paginationConfig.current_page = 1
functionLibList.value = [] functionLibList.value = []
@ -196,9 +228,19 @@ function copyFunctionLib(row: any) {
} }
function getList() { function getList() {
functionLibApi const params = {
.getFunctionLib(paginationConfig, searchValue.value && { name: searchValue.value }, loading) ...(searchValue.value && { name: searchValue.value }),
.then((res: any) => { ...(selectUserId.value &&
selectUserId.value !== 'all' && { select_user_id: selectUserId.value })
}
functionLibApi.getFunctionLib(paginationConfig, params, loading).then((res: any) => {
res.data.records.forEach((item: any) => {
if (user.userInfo && item.user_id === user.userInfo.id) {
item.username = user.userInfo.username
} else {
item.username = userOptions.value.find((v) => v.value === item.user_id)?.label
}
})
functionLibList.value = [...functionLibList.value, ...res.data.records] functionLibList.value = [...functionLibList.value, ...res.data.records]
paginationConfig.total = res.data.total paginationConfig.total = res.data.total
}) })
@ -216,8 +258,28 @@ function refresh(data: any) {
} }
} }
onMounted(() => { function getUserList() {
applicationApi.getUserList('FUNCTION', loading).then((res) => {
if (res.data) {
userOptions.value = res.data.map((item: any) => {
return {
label: item.username,
value: item.id
}
})
if (user.userInfo) {
const selectUserIdValue = localStorage.getItem(user.userInfo.id + 'function')
if (selectUserIdValue && userOptions.value.find((v) => v.value === selectUserIdValue)) {
selectUserId.value = selectUserIdValue
}
}
getList() getList()
}
})
}
onMounted(() => {
getUserList()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -225,7 +287,7 @@ onMounted(() => {
.status-button { .status-button {
position: absolute; position: absolute;
right: 12px; right: 12px;
top: 13px; top: 3px;
height: auto; height: auto;
} }
} }