fix(all): 修复bugs

This commit is contained in:
baiqi 2024-04-17 15:33:04 +08:00 committed by 刘瑞斌
parent e3864bf760
commit 5714a1275a
27 changed files with 289 additions and 202 deletions

View File

@ -2,6 +2,8 @@ import { Message, Modal } from '@arco-design/web-vue';
import { useI18n } from '@/hooks/useI18n';
import useUser from '@/hooks/useUser';
import router from '@/router';
import { NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
import type { ErrorMessageMode } from '#/axios';
@ -22,7 +24,9 @@ export default function checkStatus(status: number, msg: string, errorMessageMod
break;
}
case 403:
errMessage = msg || t('api.errMsg403');
if (router.currentRoute.value.name !== NO_RESOURCE_ROUTE_NAME) {
router.push({ name: NO_RESOURCE_ROUTE_NAME });
}
break;
// 404请求不存在
case 404:

View File

@ -424,6 +424,9 @@
@apply hidden;
}
}
.arco-icon-hover::before {
@apply hidden;
}
}
.arco-checkbox-indeterminate .arco-checkbox-icon {
border: 1px solid rgba(var(--primary-7)) !important;

View File

@ -76,6 +76,7 @@
:max-tag-count="1"
:size="props.inputSize"
readonly
no-tooltip
>
<template v-if="alreadyDeleteFiles.length > 0" #prefix>
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />

View File

@ -363,9 +363,9 @@
import { TableColumnData, TableData } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import { EQUAL, statusCodeOptions } from '@/components/pure/ms-advance-filter';
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import { TableOperationColumn } from '../../ms-user-group-comp/authTable.vue';
import { TableOperationColumn } from '@/components/business/ms-user-group-comp/authTable.vue';
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';

View File

@ -206,6 +206,7 @@ export default defineComponent(
typeof props.optionLabelRender === 'function'
? props.optionLabelRender(item)
: item[props.labelKey || 'label'],
class: 'one-line-text',
});
};
@ -276,7 +277,7 @@ export default defineComponent(
const _slots: MsSearchSelectSlots = {
default: () =>
filterOptions.value.map((item) => (
<a-tooltip content={item.tooltipContent} mouse-enter-delay={500}>
<a-tooltip content={item.tooltipContent} mouse-enter-delay={500} position="bl">
<a-option
key={item[props.valueKey || 'value']}
value={props.objectValue ? item : item[props.valueKey || 'value']}

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="flex h-full flex-col gap-[24px] overflow-hidden">
<div class="group-auth-table">
<a-table
:span-method="dataSpanMethod"
@ -77,7 +77,6 @@
saveOrgUSetting,
} from '@/api/modules/setting/usergroup';
import { useI18n } from '@/hooks/useI18n';
import { useUserStore } from '@/store';
import {
type AuthScopeType,
@ -117,12 +116,11 @@
scroll() {
return {
x: '800px',
y: 'calc(100vh - 264px)',
y: '100%',
};
},
}
);
const userStore = useUserStore();
const systemType = inject<AuthScopeEnum>('systemType');
const loading = ref(false);
@ -406,8 +404,9 @@
//
const initData = async (id: string) => {
try {
let res: UserGroupAuthSetting[] = [];
loading.value = true;
tableData.value = []; // 使
let res: UserGroupAuthSetting[] = [];
if (systemType === AuthScopeEnum.SYSTEM) {
res = await getGlobalUSetting(id);
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
@ -415,7 +414,6 @@
} else {
res = await getAuthByUserGroup(id);
}
tableData.value = transformData(res);
handleAllChange(true);
} catch (error) {
@ -488,16 +486,20 @@
<style scoped lang="less">
.group-auth-table {
position: relative;
padding: 24px;
@apply flex-1 overflow-hidden;
padding: 0 24px;
:deep(.arco-table-container) {
border-top: 1px solid var(--color-text-n8) !important;
border-right: 1px solid var(--color-text-n8) !important;
border-left: 1px solid var(--color-text-n8) !important;
}
:deep(.arco-table-th-title) {
width: 100%;
}
:deep(.arco-table-th) {
background-color: var(--color-text-n9);
line-height: normal;
}
:deep(.arco-checkbox-indeterminate) {
.arco-checkbox-icon {
border-color: rgb(var(--primary-5));
@ -506,8 +508,6 @@
}
}
.footer {
@apply absolute bottom-0 left-0 w-full;
display: flex;
justify-content: flex-end;
padding: 24px;

View File

@ -70,6 +70,13 @@
>
</a-tooltip>
<div
v-if="
element.type === systemType ||
(isSystemShowAll &&
!element.internal &&
(element.scopeId !== 'global' || !isGlobalDisable) &&
systemMoreAction.length > 0)
"
class="list-item-action flex flex-row items-center gap-[8px] opacity-0"
:class="{ '!opacity-100': element.id === currentId }"
>
@ -83,7 +90,12 @@
/>
</div>
<MsMoreAction
v-if="isSystemShowAll && !element.internal && (element.scopeId !== 'global' || !isGlobalDisable)"
v-if="
isSystemShowAll &&
!element.internal &&
(element.scopeId !== 'global' || !isGlobalDisable) &&
systemMoreAction.length > 0
"
:list="systemMoreAction"
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.SYSTEM)"
>
@ -160,6 +172,13 @@
>
</a-tooltip>
<div
v-if="
element.type === systemType ||
(isOrdShowAll &&
!element.internal &&
(element.scopeId !== 'global' || !isGlobalDisable) &&
orgMoreAction.length > 0)
"
class="list-item-action flex flex-row items-center gap-[8px] opacity-0"
:class="{ '!opacity-100': element.id === currentId }"
>
@ -173,7 +192,12 @@
/>
</div>
<MsMoreAction
v-if="isOrdShowAll && !element.internal && (element.scopeId !== 'global' || !isGlobalDisable)"
v-if="
isOrdShowAll &&
!element.internal &&
(element.scopeId !== 'global' || !isGlobalDisable) &&
orgMoreAction.length > 0
"
:list="orgMoreAction"
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.ORGANIZATION)"
>
@ -250,6 +274,13 @@
>
</a-tooltip>
<div
v-if="
element.type === systemType ||
(isProjectShowAll &&
!element.internal &&
(element.scopeId !== 'global' || !isGlobalDisable) &&
projectMoreAction.length > 0)
"
class="list-item-action flex flex-row items-center gap-[8px] opacity-0"
:class="{ '!opacity-100': element.id === currentId }"
>
@ -263,7 +294,12 @@
/>
</div>
<MsMoreAction
v-if="isProjectShowAll && !element.internal && (element.scopeId !== 'global' || !isGlobalDisable)"
v-if="
isProjectShowAll &&
!element.internal &&
(element.scopeId !== 'global' || !isGlobalDisable) &&
projectMoreAction.length > 0
"
:list="projectMoreAction"
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.PROJECT)"
>
@ -335,7 +371,6 @@
const currentItem = ref<CurrentUserGroupItem>({ id: '', name: '', internal: false, type: AuthScopeEnum.SYSTEM });
const currentId = ref('');
const currentName = computed(() => currentItem.value.name);
const userModalVisible = ref(false);

View File

@ -1,6 +1,6 @@
<template>
<div class="px-[24px]">
<MsBaseTable class="mt-[16px]" v-bind="propsRes" v-on="propsEvent">
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
<template v-if="hasAnyPermission(props.updatePermission || [])" #quickCreate>
<MsConfirmUserSelector :ok-loading="okLoading" v-bind="userSelectorProps" @confirm="handleAddMember" />
</template>

View File

@ -1,5 +1,9 @@
<template>
<a-tooltip :content="allTagText" :disabled="(innerModelValue || []).length === 0" :mouse-enter-delay="300">
<a-tooltip
:content="allTagText"
:disabled="props.noTooltip || (innerModelValue || []).length === 0"
:mouse-enter-delay="300"
>
<div :class="`flex w-full items-center ${props.class}`">
<a-input-tag
v-model:model-value="innerModelValue"
@ -59,6 +63,7 @@
inputClass?: string;
size?: 'small' | 'large' | 'medium' | 'mini';
disabled?: boolean;
noTooltip?: boolean;
}>(),
{
retainInputValue: true,
@ -68,6 +73,7 @@
class: '',
inputClass: '',
size: 'medium',
noTooltip: false,
}
);
const emit = defineEmits(['update:modelValue', 'update:inputValue', 'change', 'clear', 'blur', 'click']);

View File

@ -88,7 +88,7 @@ export default function useSelect(config: UseSelectOption) {
onMounted(() => {
if (config.selectRef.value) {
selectWidth.value = config.selectRef.value.$el.nextElementSibling.getBoundingClientRect().width;
selectWidth.value = config.selectRef.value.$el.nextElementSibling.clientWidth;
selectViewInner.value = config.selectRef.value.$el.nextElementSibling.querySelector('.arco-select-view-inner');
}
});

View File

@ -728,6 +728,7 @@ interface ParsedCurlOptions {
url?: string;
queryParameters?: { key: string; value: string }[];
headers?: { key: string; value: string }[];
method?: string;
}
/**
* curl
@ -740,16 +741,21 @@ export function parseCurlScript(curlScript: string): ParsedCurlOptions {
const [_, url] = curlScript.match(/curl\s+'([^']+)'/) || [];
if (url) {
options.url = url;
// 提取 query 参数
const queryParams = url
.split('?')[1]
?.split('&')
.map((param) => {
const [key, value] = param.split('=');
return { key, value };
});
options.queryParameters = queryParams || [];
}
// 提取 query 参数
const queryMatch = curlScript.match(/\?(.*?)'/);
if (queryMatch) {
const queryParams = queryMatch[1].split('&').map((param) => {
const [key, value] = param.split('=');
return { key, value };
});
options.queryParameters = queryParams;
// 提取请求方式
const [, method] = curlScript.match(/-X\s+'([^']+)'/) || [];
if (method) {
options.method = method;
}
// 提取 header

View File

@ -821,9 +821,11 @@
() => props.params,
(arr) => {
if (arr.length > 0) {
let hasNoIdItem = false;
paramsData.value = arr.map((item, i) => {
if (!item) {
// undefined
hasNoIdItem = true;
return {
...cloneDeep(props.defaultParamItem),
id: new Date().getTime() + i,
@ -831,6 +833,7 @@
}
if (!item.id) {
// id
hasNoIdItem = true;
return {
...item,
id: new Date().getTime() + i,
@ -839,8 +842,10 @@
return item;
});
const lastTwoIsSame =
arr.length >= 2 && filterKeyValParams([arr[arr.length - 2]], arr[arr.length - 1]).lastDataIsDefault;
arr.length === 1 ||
(arr.length >= 2 && filterKeyValParams([arr[arr.length - 2]], arr[arr.length - 1]).lastDataIsDefault);
if (
hasNoIdItem &&
!filterKeyValParams(arr, props.defaultParamItem).lastDataIsDefault &&
!props.isTreeTable &&
!lastTwoIsSame //

View File

@ -274,9 +274,10 @@
}
function handleCurlImportConfirm() {
const { url, headers, queryParameters } = parseCurlScript(curlCode.value);
const { url, headers, queryParameters, method } = parseCurlScript(curlCode.value);
addDebugTab({
url,
method: method?.toUpperCase() || RequestMethods.GET,
headers:
headers?.map((e) => ({
contentType: RequestContentTypeEnum.TEXT,
@ -348,6 +349,9 @@
[activeDebug.value] = debugTabs.value;
}
}
if (debugTabs.value.length === 0) {
addDebugTab();
}
}
onMounted(() => {

View File

@ -116,7 +116,7 @@
import type { ApiCaseDetail, ApiDefinitionDetail } from '@/models/apiTest/management';
import type { ApiScenarioTableItem } from '@/models/apiTest/scenario';
import { ScenarioStepRefType } from '@/enums/apiEnum';
import { ScenarioStepRefType, ScenarioStepType } from '@/enums/apiEnum';
export interface ImportData {
api: MsTableDataItem<ApiDefinitionDetail>[];
@ -261,11 +261,25 @@
// uniqueIdcopyFromStepId
fullScenarioArr = mapTree<MsTableDataItem<ApiScenarioTableItem>>(fullScenarioArr, (node) => {
const id = getGenerateId();
if (
node.parent &&
node.parent.stepType === ScenarioStepType.API_SCENARIO &&
[ScenarioStepRefType.REF, ScenarioStepRefType.PARTIAL_REF].includes(node.parent.refType)
) {
//
node.isQuoteScenarioStep = true; //
node.isRefScenarioStep = node.parent.refType === ScenarioStepRefType.REF; //
node.draggable = false; //
} else if (node.parent) {
//
node.isQuoteScenarioStep = node.parent.isQuoteScenarioStep; //
node.isRefScenarioStep = node.parent.isRefScenarioStep; //
}
return {
...node,
copyFromStepId: node.id,
originProjectId: node.projectId,
id,
id: node.stepType === ScenarioStepType.API_SCENARIO ? id : node.id, // id
uniqueId: id,
};
});

View File

@ -407,7 +407,13 @@
<a-button type="secondary" :disabled="scheduleModalLoading" @click="cancelScheduleModal">
{{ t('common.cancel') }}
</a-button>
<a-button class="ml-3" type="primary" :loading="scheduleModalLoading" @click="saveScheduleModal">
<a-button
v-permission="['PROJECT_API_SCENARIO:READ+EXECUTE']"
class="ml-3"
type="primary"
:loading="scheduleModalLoading"
@click="saveScheduleModal"
>
{{ t('common.save') }}
</a-button>
</div>

View File

@ -711,6 +711,9 @@
function setStepMoreAction(items: ActionsItem[], node: MsTreeNodeData) {
const _stepType = getStepType(node as ScenarioStepItem);
if ((node as ScenarioStepItem).isQuoteScenarioStep) {
return [];
}
if ((node as ScenarioStepItem).stepType === ScenarioStepType.CUSTOM_REQUEST) {
//
return [
@ -746,9 +749,6 @@
},
];
}
if ((node as ScenarioStepItem).isQuoteScenarioStep) {
return [];
}
if (_stepType.isQuoteApi || _stepType.isCopyApi) {
return [
{
@ -2096,6 +2096,8 @@
}
.ms-tree-node-extra {
@apply !visible !w-auto;
margin-right: 24px;
}
}
.ms-form {

View File

@ -105,10 +105,11 @@
:field-config="{
field: detail.name,
placeholder: t('project.fileManagement.fileNamePlaceholder'),
NotNullTip: t('project.fileManagement.fileNameNotNull'),
}"
:node-id="detail.id"
:all-names="[]"
@rename-finish="detailDrawerRef?.initDetail"
@rename-finish="() => detailDrawerRef?.initDetail()"
>
<MsButton class="!mr-0 ml-[8px]">
{{ t('common.rename') }}
@ -132,12 +133,13 @@
:field-config="{
field: detail.desc,
placeholder: t('project.fileManagement.descPlaceholder'),
maxLength: 250,
maxLength: 1000,
isTextArea: true,
}"
:node-id="detail.id"
:all-names="[]"
@update-desc-finish="detailDrawerRef?.initDetail"
no-rule
@update-desc-finish="() => detailDrawerRef?.initDetail()"
>
<MsButton class="ml-[8px]"> <MsIcon type="icon-icon_edit_outlined" /></MsButton>
</popConfirm>
@ -170,7 +172,6 @@
v-bind="caseTableProps"
:data="caseList"
no-disable
:action-config="caseBatchActions"
v-on="caseTableEvent"
>
<template #id="{ record }">
@ -403,8 +404,7 @@
title: 'project.fileManagement.caseType',
dataIndex: 'sourceType',
slotName: 'sourceType',
width: 100,
showTooltip: true,
width: 120,
},
{
title: 'project.fileManagement.caseFileVersion',
@ -428,20 +428,20 @@
scroll: { x: 800 },
columns: caseColumns,
heightUsed: 200,
selectable: true,
showSelectAll: true,
selectable: false,
showSelectAll: false,
showPagination: false,
});
const caseBatchActions = {
baseAction: [
{
label: 'project.fileManagement.updateCaseFile',
eventTag: 'updateCaseFile',
permission: ['PROJECT_FILE_MANAGEMENT:READ+UPDATE'],
},
],
};
// const caseBatchActions = {
// baseAction: [
// {
// label: 'project.fileManagement.updateCaseFile',
// eventTag: 'updateCaseFile',
// permission: ['PROJECT_FILE_MANAGEMENT:READ+UPDATE'],
// },
// ],
// };
const keyword = ref('');
const caseList = computed(() => caseTableProps.value.data.filter((item) => item.sourceName.includes(keyword.value)));

View File

@ -20,7 +20,14 @@
<a-form-item
class="hidden-item"
field="field"
:rules="[{ required: true, message: t('project.fileManagement.nameNotNull') }, { validator: validateName }]"
:rules="
props.noRule
? []
: [
{ required: true, message: props.fieldConfig?.NotNullTip || t('project.fileManagement.nameNotNull') },
{ validator: validateName },
]
"
>
<a-textarea
v-if="props.fieldConfig?.isTextArea"
@ -68,6 +75,7 @@
placeholder?: string;
maxLength?: number;
isTextArea?: boolean;
NotNullTip?: string;
}
const props = defineProps<{
@ -79,6 +87,7 @@
fieldConfig?: FieldConfig;
parentId?: string; // id
nodeId?: string; // id
noRule?: boolean;
}>();
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);

View File

@ -227,7 +227,13 @@
},
});
} else {
initModulesCount(tableFilterParams.value);
initModulesCount({
...tableFilterParams.value,
combine: {
...tableFilterParams.value.combine,
storage: 'minio',
},
});
}
}

View File

@ -8,6 +8,7 @@ export default {
'project.fileManagement.addStorage': 'Add repository',
'project.fileManagement.rename': 'Rename',
'project.fileManagement.nameNotNull': 'Module name cannot be empty',
'project.fileManagement.fileNameNotNull': 'File name cannot be empty',
'project.fileManagement.namePlaceholder': 'Please enter the module name and press Enter to save',
'project.fileManagement.renameSuccess': 'Rename successful',
'project.fileManagement.updateDescSuccess': 'File description updated successfully',

View File

@ -8,6 +8,7 @@ export default {
'project.fileManagement.addStorage': '添加存储库',
'project.fileManagement.rename': '重命名',
'project.fileManagement.nameNotNull': '模块名称不能为空',
'project.fileManagement.fileNameNotNull': '文件名称不能为空',
'project.fileManagement.namePlaceholder': '请输入模块名称,按回车键保存',
'project.fileManagement.renameSuccess': '重命名成功',
'project.fileManagement.updateDescSuccess': '文件描述更新成功',

View File

@ -1,52 +1,81 @@
<template>
<MsBaseTable
v-bind="propsRes"
:action-config="tableBatchActions"
@selected-change="handleTableSelect"
v-on="propsEvent"
@batch-action="handleTableBatch"
>
<template #userRole="{ record }">
<MsTagGroup
v-if="!record.showUserSelect"
:tag-list="record.userRoles || []"
type="primary"
theme="outline"
@click="changeUser(record)"
/>
<a-select
v-else
v-model="record.selectUserList"
:popup-visible="record.showUserSelect"
multiple
class="w-[260px]"
:max-tag-count="2"
@popup-visible-change="(value) => userGroupChange(value, record)"
>
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
</template>
<template #enable="{ record }">
<div v-if="record.enable" class="flex items-center">
<icon-check-circle-fill class="mr-[2px] text-[rgb(var(--success-6))]" />
{{ t('organization.member.statusEnable') }}
<div>
<div class="mb-4 grid grid-cols-4 gap-2">
<div class="col-span-2">
<a-button v-permission="['PROJECT_USER:READ+ADD']" class="mr-3" type="primary" @click="addMember">
{{ t('project.member.addMember') }}
</a-button>
</div>
<div v-else class="flex items-center text-[var(--color-text-4)]">
<MsIcon type="icon-icon_disable" class="mr-[2px]" />
{{ t('organization.member.statusDisable') }}
<div>
<a-select v-model="roleIds" @change="changeSelect">
<a-option v-for="item of userGroupAll" :key="item.id" :value="item.id">{{ t(item.name) }}</a-option>
<template #prefix>
<span>{{ t('project.member.tableColumnUserGroup') }}</span>
</template>
</a-select>
</div>
</template>
<template #operation="{ record }">
<MsRemoveButton
v-permission="['PROJECT_USER:READ+DELETE']"
position="br"
:title="t('project.member.deleteMemberTip', { name: characterLimit(record.name) })"
:sub-title-tip="t('project.member.subTitle')"
:loading="deleteLoading"
@ok="removeMember(record)"
/>
</template>
</MsBaseTable>
<div>
<a-input-search
v-model="keyword"
:max-length="255"
:placeholder="t('project.member.searchMember')"
allow-clear
@search="searchHandler"
@press-enter="searchHandler"
@clear="searchHandler"
>
</a-input-search>
</div>
</div>
<MsBaseTable
v-bind="propsRes"
:action-config="tableBatchActions"
@selected-change="handleTableSelect"
v-on="propsEvent"
@batch-action="handleTableBatch"
>
<template #userRole="{ record }">
<MsTagGroup
v-if="!record.showUserSelect"
:tag-list="record.userRoles || []"
type="primary"
theme="outline"
@click="changeUser(record)"
/>
<a-select
v-else
v-model="record.selectUserList"
:popup-visible="record.showUserSelect"
multiple
class="w-[260px]"
:max-tag-count="2"
@popup-visible-change="(value) => userGroupChange(value, record)"
>
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
</template>
<template #enable="{ record }">
<div v-if="record.enable" class="flex items-center">
<icon-check-circle-fill class="mr-[2px] text-[rgb(var(--success-6))]" />
{{ t('organization.member.statusEnable') }}
</div>
<div v-else class="flex items-center text-[var(--color-text-4)]">
<MsIcon type="icon-icon_disable" class="mr-[2px]" />
{{ t('organization.member.statusDisable') }}
</div>
</template>
<template #operation="{ record }">
<MsRemoveButton
v-permission="['PROJECT_USER:READ+DELETE']"
position="br"
:title="t('project.member.deleteMemberTip', { name: characterLimit(record.name) })"
:sub-title-tip="t('project.member.subTitle')"
:loading="deleteLoading"
@ok="removeMember(record)"
/>
</template>
</MsBaseTable>
</div>
<AddMemberModal
ref="projectMemberRef"
v-model:visible="addMemberVisible"
@ -95,12 +124,6 @@
} from '@/models/projectManagement/projectAndPermission';
import { TableKeyEnum } from '@/enums/tableEnum';
const props = defineProps<{
roleIds: string;
userGroupOptions: ProjectUserOption[];
keyword: string;
}>();
const appStore = useAppStore();
const { t } = useI18n();
const { openModal } = useModal();
@ -193,18 +216,43 @@
}
);
const userGroupAll = ref<ProjectUserOption[]>([]);
const userGroupOptions = ref<ProjectUserOption[]>([]);
const initOptions = async () => {
userGroupOptions.value = await getProjectUserGroup(appStore.currentProjectId);
userGroupAll.value = [
{
id: '',
name: '全部',
},
...userGroupOptions.value,
];
};
const roleIds = ref<string>('');
const keyword = ref<string>('');
const initData = async () => {
await nextTick();
setLoadListParams({
filter: {
roleIds: props.roleIds ? [props.roleIds] : [],
roleIds: roleIds.value ? [roleIds.value] : [],
},
projectId: lastProjectId.value,
keyword: props.keyword,
keyword: keyword.value,
});
await loadList();
};
const searchHandler = () => {
initData();
};
const changeSelect = () => {
initData();
};
//
const selectData = ref<string[] | undefined>([]);
@ -250,6 +298,7 @@
resetSelector();
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
deleteLoading.value = false;
@ -276,9 +325,9 @@
selectAll: !!selectAll,
excludeIds: excludeIds || [],
selectIds: selectedIds || [],
keyword: props.keyword,
keyword: keyword.value,
condition: {
keyword: props.keyword,
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
@ -288,6 +337,7 @@
initData();
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};
@ -328,6 +378,7 @@
record.showUserSelect = false;
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};
@ -360,15 +411,11 @@
editProjectMember(record);
};
onBeforeMount(() => {
onBeforeMount(async () => {
await initOptions();
initData();
});
defineExpose({
initData,
addMember,
});
await tableStore.initColumn(TableKeyEnum.PROJECT_MEMBER, columns, 'drawer');
</script>

View File

@ -1,87 +1,12 @@
<template>
<div class="mb-4 grid grid-cols-4 gap-2">
<div class="col-span-2">
<a-button v-permission="['PROJECT_USER:READ+ADD']" class="mr-3" type="primary" @click="addMember">
{{ t('project.member.addMember') }}
</a-button>
</div>
<div>
<a-select v-model="roleIds" @change="changeSelect">
<a-option v-for="item of userGroupAll" :key="item.id" :value="item.id">{{ t(item.name) }}</a-option>
<template #prefix
><span>{{ t('project.member.tableColumnUserGroup') }}</span></template
>
</a-select></div
>
<div>
<a-input-search
v-model="keyword"
:max-length="255"
:placeholder="t('project.member.searchMember')"
allow-clear
@search="searchHandler"
@press-enter="searchHandler"
@clear="searchHandler"
></a-input-search
></div>
</div>
<memberTable
v-if="isMounted"
ref="memberTableRef"
:keyword="keyword"
:role-ids="roleIds"
:user-group-options="userGroupOptions"
/>
<memberTable v-if="isMounted" />
</template>
<script setup lang="ts">
import { getProjectUserGroup } from '@/api/modules/project-management/projectMember';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import { ProjectUserOption } from '@/models/projectManagement/projectAndPermission';
const memberTable = defineAsyncComponent(() => import('./components/memberTable.vue'));
/**
* @description 项目管理-项目与权限-成员
*/
const appStore = useAppStore();
const { t } = useI18n();
const userGroupAll = ref<ProjectUserOption[]>([]);
const userGroupOptions = ref<ProjectUserOption[]>([]);
const initOptions = async () => {
userGroupOptions.value = await getProjectUserGroup(appStore.currentProjectId);
userGroupAll.value = [
{
id: '',
name: '全部',
},
...userGroupOptions.value,
];
};
initOptions();
const memberTableRef = ref<InstanceType<typeof memberTable> | null>(null);
const roleIds = ref<string>('');
const keyword = ref<string>('');
const initData = async () => {
memberTableRef.value?.initData();
};
const searchHandler = () => {
initData();
};
const changeSelect = () => {
initData();
};
function addMember() {
memberTableRef.value?.addMember();
}
const memberTable = defineAsyncComponent(() => import('./components/memberTable.vue'));
const isMounted = ref(false);

View File

@ -34,6 +34,14 @@
></a-textarea>
</a-form-item>
<a-form-item :label="t('system.resourcePool.serverUrl')" field="serverUrl" class="form-item">
<template #label>
<div class="flex items-center">
{{ t('system.resourcePool.serverUrl') }}
<a-tooltip :content="t('system.resourcePool.serverUrlTip')" position="tl" mini>
<icon-question-circle class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-6))]" />
</a-tooltip>
</div>
</template>
<a-input
v-model:model-value="form.serverUrl"
:placeholder="t('system.resourcePool.rootUrlPlaceholder')"

View File

@ -26,7 +26,7 @@ export default {
'system.resourcePool.deletePoolCancel': 'Cancel',
'system.resourcePool.deletePoolSuccess': 'Deleted successfully',
'system.resourcePool.detailDesc': 'Description',
'system.resourcePool.detailUrl': 'Current site URL',
'system.resourcePool.detailUrl': 'Intranet URL',
'system.resourcePool.detailRange': 'Applied organization',
'system.resourcePool.detailUse': 'Use',
'system.resourcePool.detailMirror': 'Mirror',
@ -41,7 +41,9 @@ export default {
'system.resourcePool.namePlaceholder': 'Please enter a resource pool name',
'system.resourcePool.desc': 'Description',
'system.resourcePool.descPlaceholder': 'Please describe the resource pool',
'system.resourcePool.serverUrl': 'Current site URL',
'system.resourcePool.serverUrl': 'Intranet URL',
'system.resourcePool.serverUrlTip':
'When the resource pool is deployed on the intranet, the intranet address can be used',
'system.resourcePool.rootUrlPlaceholder': 'MS deployment address',
'system.resourcePool.orgRange': 'Applied organization',
'system.resourcePool.orgAll': 'All organization',

View File

@ -25,7 +25,7 @@ export default {
'system.resourcePool.deletePoolCancel': '取消',
'system.resourcePool.deletePoolSuccess': '删除成功',
'system.resourcePool.detailDesc': '描述',
'system.resourcePool.detailUrl': '当前站点 URL',
'system.resourcePool.detailUrl': '内网 URL',
'system.resourcePool.detailRange': '应用组织',
'system.resourcePool.detailUse': '用途',
'system.resourcePool.detailMirror': '镜像',
@ -40,7 +40,8 @@ export default {
'system.resourcePool.namePlaceholder': '请输入资源池名称',
'system.resourcePool.desc': '描述',
'system.resourcePool.descPlaceholder': '请对该资源池进行描述',
'system.resourcePool.serverUrl': '当前站点 URL',
'system.resourcePool.serverUrl': '内网 URL',
'system.resourcePool.serverUrlTip': '资源池部署在内网时,可走内网地址',
'system.resourcePool.rootUrlPlaceholder': 'MS的部署地址',
'system.resourcePool.orgRange': '应用组织',
'system.resourcePool.orgAll': '全部组织',

View File

@ -12,7 +12,7 @@
/>
</template>
<template #second>
<div class="h-full pt-[24px]">
<div class="flex h-full flex-col gap-[16px] overflow-hidden pt-[24px]">
<div class="flex flex-row items-center justify-between px-[24px]">
<a-tooltip :content="currentUserGroupItem.name">
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
@ -38,7 +38,7 @@
</a-radio-group>
</div>
</div>
<div class="mt-[16px]">
<div class="flex-1 overflow-hidden">
<UserTable
v-if="currentTable === 'user' && couldShowUser"
ref="userRef"