fix(all): 修复bugs
This commit is contained in:
parent
e3864bf760
commit
5714a1275a
|
@ -2,6 +2,8 @@ import { Message, Modal } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useUser from '@/hooks/useUser';
|
import useUser from '@/hooks/useUser';
|
||||||
|
import router from '@/router';
|
||||||
|
import { NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
|
||||||
|
|
||||||
import type { ErrorMessageMode } from '#/axios';
|
import type { ErrorMessageMode } from '#/axios';
|
||||||
|
|
||||||
|
@ -22,7 +24,9 @@ export default function checkStatus(status: number, msg: string, errorMessageMod
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 403:
|
case 403:
|
||||||
errMessage = msg || t('api.errMsg403');
|
if (router.currentRoute.value.name !== NO_RESOURCE_ROUTE_NAME) {
|
||||||
|
router.push({ name: NO_RESOURCE_ROUTE_NAME });
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// 404请求不存在
|
// 404请求不存在
|
||||||
case 404:
|
case 404:
|
||||||
|
|
|
@ -424,6 +424,9 @@
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.arco-icon-hover::before {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.arco-checkbox-indeterminate .arco-checkbox-icon {
|
.arco-checkbox-indeterminate .arco-checkbox-icon {
|
||||||
border: 1px solid rgba(var(--primary-7)) !important;
|
border: 1px solid rgba(var(--primary-7)) !important;
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
:max-tag-count="1"
|
:max-tag-count="1"
|
||||||
:size="props.inputSize"
|
:size="props.inputSize"
|
||||||
readonly
|
readonly
|
||||||
|
no-tooltip
|
||||||
>
|
>
|
||||||
<template v-if="alreadyDeleteFiles.length > 0" #prefix>
|
<template v-if="alreadyDeleteFiles.length > 0" #prefix>
|
||||||
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
||||||
|
|
|
@ -363,9 +363,9 @@
|
||||||
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
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 { 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 fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
|
||||||
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
|
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
|
||||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||||
|
|
|
@ -206,6 +206,7 @@ export default defineComponent(
|
||||||
typeof props.optionLabelRender === 'function'
|
typeof props.optionLabelRender === 'function'
|
||||||
? props.optionLabelRender(item)
|
? props.optionLabelRender(item)
|
||||||
: item[props.labelKey || 'label'],
|
: item[props.labelKey || 'label'],
|
||||||
|
class: 'one-line-text',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -276,7 +277,7 @@ export default defineComponent(
|
||||||
const _slots: MsSearchSelectSlots = {
|
const _slots: MsSearchSelectSlots = {
|
||||||
default: () =>
|
default: () =>
|
||||||
filterOptions.value.map((item) => (
|
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
|
<a-option
|
||||||
key={item[props.valueKey || 'value']}
|
key={item[props.valueKey || 'value']}
|
||||||
value={props.objectValue ? item : item[props.valueKey || 'value']}
|
value={props.objectValue ? item : item[props.valueKey || 'value']}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="flex h-full flex-col gap-[24px] overflow-hidden">
|
||||||
<div class="group-auth-table">
|
<div class="group-auth-table">
|
||||||
<a-table
|
<a-table
|
||||||
:span-method="dataSpanMethod"
|
:span-method="dataSpanMethod"
|
||||||
|
@ -77,7 +77,6 @@
|
||||||
saveOrgUSetting,
|
saveOrgUSetting,
|
||||||
} from '@/api/modules/setting/usergroup';
|
} from '@/api/modules/setting/usergroup';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useUserStore } from '@/store';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type AuthScopeType,
|
type AuthScopeType,
|
||||||
|
@ -117,12 +116,11 @@
|
||||||
scroll() {
|
scroll() {
|
||||||
return {
|
return {
|
||||||
x: '800px',
|
x: '800px',
|
||||||
y: 'calc(100vh - 264px)',
|
y: '100%',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const userStore = useUserStore();
|
|
||||||
const systemType = inject<AuthScopeEnum>('systemType');
|
const systemType = inject<AuthScopeEnum>('systemType');
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
@ -406,8 +404,9 @@
|
||||||
// 初始化数据
|
// 初始化数据
|
||||||
const initData = async (id: string) => {
|
const initData = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
let res: UserGroupAuthSetting[] = [];
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
tableData.value = []; // 重置数据,可以使表格滚动条重新计算
|
||||||
|
let res: UserGroupAuthSetting[] = [];
|
||||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||||
res = await getGlobalUSetting(id);
|
res = await getGlobalUSetting(id);
|
||||||
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||||
|
@ -415,7 +414,6 @@
|
||||||
} else {
|
} else {
|
||||||
res = await getAuthByUserGroup(id);
|
res = await getAuthByUserGroup(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
tableData.value = transformData(res);
|
tableData.value = transformData(res);
|
||||||
handleAllChange(true);
|
handleAllChange(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -488,16 +486,20 @@
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.group-auth-table {
|
.group-auth-table {
|
||||||
position: relative;
|
@apply flex-1 overflow-hidden;
|
||||||
padding: 24px;
|
|
||||||
|
padding: 0 24px;
|
||||||
:deep(.arco-table-container) {
|
:deep(.arco-table-container) {
|
||||||
border-top: 1px solid var(--color-text-n8) !important;
|
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;
|
border-left: 1px solid var(--color-text-n8) !important;
|
||||||
}
|
}
|
||||||
:deep(.arco-table-th-title) {
|
:deep(.arco-table-th-title) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
:deep(.arco-table-th) {
|
||||||
|
background-color: var(--color-text-n9);
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
:deep(.arco-checkbox-indeterminate) {
|
:deep(.arco-checkbox-indeterminate) {
|
||||||
.arco-checkbox-icon {
|
.arco-checkbox-icon {
|
||||||
border-color: rgb(var(--primary-5));
|
border-color: rgb(var(--primary-5));
|
||||||
|
@ -506,8 +508,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.footer {
|
.footer {
|
||||||
@apply absolute bottom-0 left-0 w-full;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
|
|
@ -70,6 +70,13 @@
|
||||||
>
|
>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div
|
<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="list-item-action flex flex-row items-center gap-[8px] opacity-0"
|
||||||
:class="{ '!opacity-100': element.id === currentId }"
|
:class="{ '!opacity-100': element.id === currentId }"
|
||||||
>
|
>
|
||||||
|
@ -83,7 +90,12 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<MsMoreAction
|
<MsMoreAction
|
||||||
v-if="isSystemShowAll && !element.internal && (element.scopeId !== 'global' || !isGlobalDisable)"
|
v-if="
|
||||||
|
isSystemShowAll &&
|
||||||
|
!element.internal &&
|
||||||
|
(element.scopeId !== 'global' || !isGlobalDisable) &&
|
||||||
|
systemMoreAction.length > 0
|
||||||
|
"
|
||||||
:list="systemMoreAction"
|
:list="systemMoreAction"
|
||||||
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.SYSTEM)"
|
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.SYSTEM)"
|
||||||
>
|
>
|
||||||
|
@ -160,6 +172,13 @@
|
||||||
>
|
>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div
|
<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="list-item-action flex flex-row items-center gap-[8px] opacity-0"
|
||||||
:class="{ '!opacity-100': element.id === currentId }"
|
:class="{ '!opacity-100': element.id === currentId }"
|
||||||
>
|
>
|
||||||
|
@ -173,7 +192,12 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<MsMoreAction
|
<MsMoreAction
|
||||||
v-if="isOrdShowAll && !element.internal && (element.scopeId !== 'global' || !isGlobalDisable)"
|
v-if="
|
||||||
|
isOrdShowAll &&
|
||||||
|
!element.internal &&
|
||||||
|
(element.scopeId !== 'global' || !isGlobalDisable) &&
|
||||||
|
orgMoreAction.length > 0
|
||||||
|
"
|
||||||
:list="orgMoreAction"
|
:list="orgMoreAction"
|
||||||
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.ORGANIZATION)"
|
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.ORGANIZATION)"
|
||||||
>
|
>
|
||||||
|
@ -250,6 +274,13 @@
|
||||||
>
|
>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div
|
<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="list-item-action flex flex-row items-center gap-[8px] opacity-0"
|
||||||
:class="{ '!opacity-100': element.id === currentId }"
|
:class="{ '!opacity-100': element.id === currentId }"
|
||||||
>
|
>
|
||||||
|
@ -263,7 +294,12 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<MsMoreAction
|
<MsMoreAction
|
||||||
v-if="isProjectShowAll && !element.internal && (element.scopeId !== 'global' || !isGlobalDisable)"
|
v-if="
|
||||||
|
isProjectShowAll &&
|
||||||
|
!element.internal &&
|
||||||
|
(element.scopeId !== 'global' || !isGlobalDisable) &&
|
||||||
|
projectMoreAction.length > 0
|
||||||
|
"
|
||||||
:list="projectMoreAction"
|
:list="projectMoreAction"
|
||||||
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.PROJECT)"
|
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.PROJECT)"
|
||||||
>
|
>
|
||||||
|
@ -335,7 +371,6 @@
|
||||||
|
|
||||||
const currentItem = ref<CurrentUserGroupItem>({ id: '', name: '', internal: false, type: AuthScopeEnum.SYSTEM });
|
const currentItem = ref<CurrentUserGroupItem>({ id: '', name: '', internal: false, type: AuthScopeEnum.SYSTEM });
|
||||||
const currentId = ref('');
|
const currentId = ref('');
|
||||||
const currentName = computed(() => currentItem.value.name);
|
|
||||||
|
|
||||||
const userModalVisible = ref(false);
|
const userModalVisible = ref(false);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="px-[24px]">
|
<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>
|
<template v-if="hasAnyPermission(props.updatePermission || [])" #quickCreate>
|
||||||
<MsConfirmUserSelector :ok-loading="okLoading" v-bind="userSelectorProps" @confirm="handleAddMember" />
|
<MsConfirmUserSelector :ok-loading="okLoading" v-bind="userSelectorProps" @confirm="handleAddMember" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<template>
|
<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}`">
|
<div :class="`flex w-full items-center ${props.class}`">
|
||||||
<a-input-tag
|
<a-input-tag
|
||||||
v-model:model-value="innerModelValue"
|
v-model:model-value="innerModelValue"
|
||||||
|
@ -59,6 +63,7 @@
|
||||||
inputClass?: string;
|
inputClass?: string;
|
||||||
size?: 'small' | 'large' | 'medium' | 'mini';
|
size?: 'small' | 'large' | 'medium' | 'mini';
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
noTooltip?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
retainInputValue: true,
|
retainInputValue: true,
|
||||||
|
@ -68,6 +73,7 @@
|
||||||
class: '',
|
class: '',
|
||||||
inputClass: '',
|
inputClass: '',
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
|
noTooltip: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits(['update:modelValue', 'update:inputValue', 'change', 'clear', 'blur', 'click']);
|
const emit = defineEmits(['update:modelValue', 'update:inputValue', 'change', 'clear', 'blur', 'click']);
|
||||||
|
|
|
@ -88,7 +88,7 @@ export default function useSelect(config: UseSelectOption) {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (config.selectRef.value) {
|
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');
|
selectViewInner.value = config.selectRef.value.$el.nextElementSibling.querySelector('.arco-select-view-inner');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -728,6 +728,7 @@ interface ParsedCurlOptions {
|
||||||
url?: string;
|
url?: string;
|
||||||
queryParameters?: { key: string; value: string }[];
|
queryParameters?: { key: string; value: string }[];
|
||||||
headers?: { key: string; value: string }[];
|
headers?: { key: string; value: string }[];
|
||||||
|
method?: string;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 解析 curl 脚本
|
* 解析 curl 脚本
|
||||||
|
@ -740,16 +741,21 @@ export function parseCurlScript(curlScript: string): ParsedCurlOptions {
|
||||||
const [_, url] = curlScript.match(/curl\s+'([^']+)'/) || [];
|
const [_, url] = curlScript.match(/curl\s+'([^']+)'/) || [];
|
||||||
if (url) {
|
if (url) {
|
||||||
options.url = 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(/\?(.*?)'/);
|
const [, method] = curlScript.match(/-X\s+'([^']+)'/) || [];
|
||||||
if (queryMatch) {
|
if (method) {
|
||||||
const queryParams = queryMatch[1].split('&').map((param) => {
|
options.method = method;
|
||||||
const [key, value] = param.split('=');
|
|
||||||
return { key, value };
|
|
||||||
});
|
|
||||||
options.queryParameters = queryParams;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取 header
|
// 提取 header
|
||||||
|
|
|
@ -821,9 +821,11 @@
|
||||||
() => props.params,
|
() => props.params,
|
||||||
(arr) => {
|
(arr) => {
|
||||||
if (arr.length > 0) {
|
if (arr.length > 0) {
|
||||||
|
let hasNoIdItem = false;
|
||||||
paramsData.value = arr.map((item, i) => {
|
paramsData.value = arr.map((item, i) => {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
// 批量添加过来的数据最后一行会是 undefined
|
// 批量添加过来的数据最后一行会是 undefined
|
||||||
|
hasNoIdItem = true;
|
||||||
return {
|
return {
|
||||||
...cloneDeep(props.defaultParamItem),
|
...cloneDeep(props.defaultParamItem),
|
||||||
id: new Date().getTime() + i,
|
id: new Date().getTime() + i,
|
||||||
|
@ -831,6 +833,7 @@
|
||||||
}
|
}
|
||||||
if (!item.id) {
|
if (!item.id) {
|
||||||
// 后台存储无id,渲染时需要手动添加一次
|
// 后台存储无id,渲染时需要手动添加一次
|
||||||
|
hasNoIdItem = true;
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
id: new Date().getTime() + i,
|
id: new Date().getTime() + i,
|
||||||
|
@ -839,8 +842,10 @@
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
const lastTwoIsSame =
|
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 (
|
if (
|
||||||
|
hasNoIdItem &&
|
||||||
!filterKeyValParams(arr, props.defaultParamItem).lastDataIsDefault &&
|
!filterKeyValParams(arr, props.defaultParamItem).lastDataIsDefault &&
|
||||||
!props.isTreeTable &&
|
!props.isTreeTable &&
|
||||||
!lastTwoIsSame // 为了判断最后俩行是否一致(因为下拉框切换会新增一行一样的数据,此时最后一条数据与默认数据是不一样的)
|
!lastTwoIsSame // 为了判断最后俩行是否一致(因为下拉框切换会新增一行一样的数据,此时最后一条数据与默认数据是不一样的)
|
||||||
|
|
|
@ -274,9 +274,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCurlImportConfirm() {
|
function handleCurlImportConfirm() {
|
||||||
const { url, headers, queryParameters } = parseCurlScript(curlCode.value);
|
const { url, headers, queryParameters, method } = parseCurlScript(curlCode.value);
|
||||||
addDebugTab({
|
addDebugTab({
|
||||||
url,
|
url,
|
||||||
|
method: method?.toUpperCase() || RequestMethods.GET,
|
||||||
headers:
|
headers:
|
||||||
headers?.map((e) => ({
|
headers?.map((e) => ({
|
||||||
contentType: RequestContentTypeEnum.TEXT,
|
contentType: RequestContentTypeEnum.TEXT,
|
||||||
|
@ -348,6 +349,9 @@
|
||||||
[activeDebug.value] = debugTabs.value;
|
[activeDebug.value] = debugTabs.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (debugTabs.value.length === 0) {
|
||||||
|
addDebugTab();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
|
|
||||||
import type { ApiCaseDetail, ApiDefinitionDetail } from '@/models/apiTest/management';
|
import type { ApiCaseDetail, ApiDefinitionDetail } from '@/models/apiTest/management';
|
||||||
import type { ApiScenarioTableItem } from '@/models/apiTest/scenario';
|
import type { ApiScenarioTableItem } from '@/models/apiTest/scenario';
|
||||||
import { ScenarioStepRefType } from '@/enums/apiEnum';
|
import { ScenarioStepRefType, ScenarioStepType } from '@/enums/apiEnum';
|
||||||
|
|
||||||
export interface ImportData {
|
export interface ImportData {
|
||||||
api: MsTableDataItem<ApiDefinitionDetail>[];
|
api: MsTableDataItem<ApiDefinitionDetail>[];
|
||||||
|
@ -261,11 +261,25 @@
|
||||||
// 复制需要递归给每个节点生成新的uniqueId,并记录copyFromStepId
|
// 复制需要递归给每个节点生成新的uniqueId,并记录copyFromStepId
|
||||||
fullScenarioArr = mapTree<MsTableDataItem<ApiScenarioTableItem>>(fullScenarioArr, (node) => {
|
fullScenarioArr = mapTree<MsTableDataItem<ApiScenarioTableItem>>(fullScenarioArr, (node) => {
|
||||||
const id = getGenerateId();
|
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 {
|
return {
|
||||||
...node,
|
...node,
|
||||||
copyFromStepId: node.id,
|
copyFromStepId: node.id,
|
||||||
originProjectId: node.projectId,
|
originProjectId: node.projectId,
|
||||||
id,
|
id: node.stepType === ScenarioStepType.API_SCENARIO ? id : node.id, // 引用场景节点生成新的步骤 id
|
||||||
uniqueId: id,
|
uniqueId: id,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -407,7 +407,13 @@
|
||||||
<a-button type="secondary" :disabled="scheduleModalLoading" @click="cancelScheduleModal">
|
<a-button type="secondary" :disabled="scheduleModalLoading" @click="cancelScheduleModal">
|
||||||
{{ t('common.cancel') }}
|
{{ t('common.cancel') }}
|
||||||
</a-button>
|
</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') }}
|
{{ t('common.save') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -711,6 +711,9 @@
|
||||||
|
|
||||||
function setStepMoreAction(items: ActionsItem[], node: MsTreeNodeData) {
|
function setStepMoreAction(items: ActionsItem[], node: MsTreeNodeData) {
|
||||||
const _stepType = getStepType(node as ScenarioStepItem);
|
const _stepType = getStepType(node as ScenarioStepItem);
|
||||||
|
if ((node as ScenarioStepItem).isQuoteScenarioStep) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
if ((node as ScenarioStepItem).stepType === ScenarioStepType.CUSTOM_REQUEST) {
|
if ((node as ScenarioStepItem).stepType === ScenarioStepType.CUSTOM_REQUEST) {
|
||||||
// 自定义请求
|
// 自定义请求
|
||||||
return [
|
return [
|
||||||
|
@ -746,9 +749,6 @@
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if ((node as ScenarioStepItem).isQuoteScenarioStep) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (_stepType.isQuoteApi || _stepType.isCopyApi) {
|
if (_stepType.isQuoteApi || _stepType.isCopyApi) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -2096,6 +2096,8 @@
|
||||||
}
|
}
|
||||||
.ms-tree-node-extra {
|
.ms-tree-node-extra {
|
||||||
@apply !visible !w-auto;
|
@apply !visible !w-auto;
|
||||||
|
|
||||||
|
margin-right: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ms-form {
|
.ms-form {
|
||||||
|
|
|
@ -105,10 +105,11 @@
|
||||||
:field-config="{
|
:field-config="{
|
||||||
field: detail.name,
|
field: detail.name,
|
||||||
placeholder: t('project.fileManagement.fileNamePlaceholder'),
|
placeholder: t('project.fileManagement.fileNamePlaceholder'),
|
||||||
|
NotNullTip: t('project.fileManagement.fileNameNotNull'),
|
||||||
}"
|
}"
|
||||||
:node-id="detail.id"
|
:node-id="detail.id"
|
||||||
:all-names="[]"
|
:all-names="[]"
|
||||||
@rename-finish="detailDrawerRef?.initDetail"
|
@rename-finish="() => detailDrawerRef?.initDetail()"
|
||||||
>
|
>
|
||||||
<MsButton class="!mr-0 ml-[8px]">
|
<MsButton class="!mr-0 ml-[8px]">
|
||||||
{{ t('common.rename') }}
|
{{ t('common.rename') }}
|
||||||
|
@ -132,12 +133,13 @@
|
||||||
:field-config="{
|
:field-config="{
|
||||||
field: detail.desc,
|
field: detail.desc,
|
||||||
placeholder: t('project.fileManagement.descPlaceholder'),
|
placeholder: t('project.fileManagement.descPlaceholder'),
|
||||||
maxLength: 250,
|
maxLength: 1000,
|
||||||
isTextArea: true,
|
isTextArea: true,
|
||||||
}"
|
}"
|
||||||
:node-id="detail.id"
|
:node-id="detail.id"
|
||||||
:all-names="[]"
|
: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>
|
<MsButton class="ml-[8px]"> <MsIcon type="icon-icon_edit_outlined" /></MsButton>
|
||||||
</popConfirm>
|
</popConfirm>
|
||||||
|
@ -170,7 +172,6 @@
|
||||||
v-bind="caseTableProps"
|
v-bind="caseTableProps"
|
||||||
:data="caseList"
|
:data="caseList"
|
||||||
no-disable
|
no-disable
|
||||||
:action-config="caseBatchActions"
|
|
||||||
v-on="caseTableEvent"
|
v-on="caseTableEvent"
|
||||||
>
|
>
|
||||||
<template #id="{ record }">
|
<template #id="{ record }">
|
||||||
|
@ -403,8 +404,7 @@
|
||||||
title: 'project.fileManagement.caseType',
|
title: 'project.fileManagement.caseType',
|
||||||
dataIndex: 'sourceType',
|
dataIndex: 'sourceType',
|
||||||
slotName: 'sourceType',
|
slotName: 'sourceType',
|
||||||
width: 100,
|
width: 120,
|
||||||
showTooltip: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.fileManagement.caseFileVersion',
|
title: 'project.fileManagement.caseFileVersion',
|
||||||
|
@ -428,20 +428,20 @@
|
||||||
scroll: { x: 800 },
|
scroll: { x: 800 },
|
||||||
columns: caseColumns,
|
columns: caseColumns,
|
||||||
heightUsed: 200,
|
heightUsed: 200,
|
||||||
selectable: true,
|
selectable: false,
|
||||||
showSelectAll: true,
|
showSelectAll: false,
|
||||||
showPagination: false,
|
showPagination: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const caseBatchActions = {
|
// const caseBatchActions = {
|
||||||
baseAction: [
|
// baseAction: [
|
||||||
{
|
// {
|
||||||
label: 'project.fileManagement.updateCaseFile',
|
// label: 'project.fileManagement.updateCaseFile',
|
||||||
eventTag: 'updateCaseFile',
|
// eventTag: 'updateCaseFile',
|
||||||
permission: ['PROJECT_FILE_MANAGEMENT:READ+UPDATE'],
|
// permission: ['PROJECT_FILE_MANAGEMENT:READ+UPDATE'],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|
||||||
const keyword = ref('');
|
const keyword = ref('');
|
||||||
const caseList = computed(() => caseTableProps.value.data.filter((item) => item.sourceName.includes(keyword.value)));
|
const caseList = computed(() => caseTableProps.value.data.filter((item) => item.sourceName.includes(keyword.value)));
|
||||||
|
|
|
@ -20,7 +20,14 @@
|
||||||
<a-form-item
|
<a-form-item
|
||||||
class="hidden-item"
|
class="hidden-item"
|
||||||
field="field"
|
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
|
<a-textarea
|
||||||
v-if="props.fieldConfig?.isTextArea"
|
v-if="props.fieldConfig?.isTextArea"
|
||||||
|
@ -68,6 +75,7 @@
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
isTextArea?: boolean;
|
isTextArea?: boolean;
|
||||||
|
NotNullTip?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -79,6 +87,7 @@
|
||||||
fieldConfig?: FieldConfig;
|
fieldConfig?: FieldConfig;
|
||||||
parentId?: string; // 父节点 id
|
parentId?: string; // 父节点 id
|
||||||
nodeId?: string; // 节点 id
|
nodeId?: string; // 节点 id
|
||||||
|
noRule?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);
|
const emit = defineEmits(['update:visible', 'close', 'addFinish', 'renameFinish', 'updateDescFinish']);
|
||||||
|
|
|
@ -227,7 +227,13 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
initModulesCount(tableFilterParams.value);
|
initModulesCount({
|
||||||
|
...tableFilterParams.value,
|
||||||
|
combine: {
|
||||||
|
...tableFilterParams.value.combine,
|
||||||
|
storage: 'minio',
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ export default {
|
||||||
'project.fileManagement.addStorage': 'Add repository',
|
'project.fileManagement.addStorage': 'Add repository',
|
||||||
'project.fileManagement.rename': 'Rename',
|
'project.fileManagement.rename': 'Rename',
|
||||||
'project.fileManagement.nameNotNull': 'Module name cannot be empty',
|
'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.namePlaceholder': 'Please enter the module name and press Enter to save',
|
||||||
'project.fileManagement.renameSuccess': 'Rename successful',
|
'project.fileManagement.renameSuccess': 'Rename successful',
|
||||||
'project.fileManagement.updateDescSuccess': 'File description updated successfully',
|
'project.fileManagement.updateDescSuccess': 'File description updated successfully',
|
||||||
|
|
|
@ -8,6 +8,7 @@ export default {
|
||||||
'project.fileManagement.addStorage': '添加存储库',
|
'project.fileManagement.addStorage': '添加存储库',
|
||||||
'project.fileManagement.rename': '重命名',
|
'project.fileManagement.rename': '重命名',
|
||||||
'project.fileManagement.nameNotNull': '模块名称不能为空',
|
'project.fileManagement.nameNotNull': '模块名称不能为空',
|
||||||
|
'project.fileManagement.fileNameNotNull': '文件名称不能为空',
|
||||||
'project.fileManagement.namePlaceholder': '请输入模块名称,按回车键保存',
|
'project.fileManagement.namePlaceholder': '请输入模块名称,按回车键保存',
|
||||||
'project.fileManagement.renameSuccess': '重命名成功',
|
'project.fileManagement.renameSuccess': '重命名成功',
|
||||||
'project.fileManagement.updateDescSuccess': '文件描述更新成功',
|
'project.fileManagement.updateDescSuccess': '文件描述更新成功',
|
||||||
|
|
|
@ -1,52 +1,81 @@
|
||||||
<template>
|
<template>
|
||||||
<MsBaseTable
|
<div>
|
||||||
v-bind="propsRes"
|
<div class="mb-4 grid grid-cols-4 gap-2">
|
||||||
:action-config="tableBatchActions"
|
<div class="col-span-2">
|
||||||
@selected-change="handleTableSelect"
|
<a-button v-permission="['PROJECT_USER:READ+ADD']" class="mr-3" type="primary" @click="addMember">
|
||||||
v-on="propsEvent"
|
{{ t('project.member.addMember') }}
|
||||||
@batch-action="handleTableBatch"
|
</a-button>
|
||||||
>
|
|
||||||
<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>
|
||||||
<div v-else class="flex items-center text-[var(--color-text-4)]">
|
<div>
|
||||||
<MsIcon type="icon-icon_disable" class="mr-[2px]" />
|
<a-select v-model="roleIds" @change="changeSelect">
|
||||||
{{ t('organization.member.statusDisable') }}
|
<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>
|
||||||
</template>
|
<div>
|
||||||
<template #operation="{ record }">
|
<a-input-search
|
||||||
<MsRemoveButton
|
v-model="keyword"
|
||||||
v-permission="['PROJECT_USER:READ+DELETE']"
|
:max-length="255"
|
||||||
position="br"
|
:placeholder="t('project.member.searchMember')"
|
||||||
:title="t('project.member.deleteMemberTip', { name: characterLimit(record.name) })"
|
allow-clear
|
||||||
:sub-title-tip="t('project.member.subTitle')"
|
@search="searchHandler"
|
||||||
:loading="deleteLoading"
|
@press-enter="searchHandler"
|
||||||
@ok="removeMember(record)"
|
@clear="searchHandler"
|
||||||
/>
|
>
|
||||||
</template>
|
</a-input-search>
|
||||||
</MsBaseTable>
|
</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
|
<AddMemberModal
|
||||||
ref="projectMemberRef"
|
ref="projectMemberRef"
|
||||||
v-model:visible="addMemberVisible"
|
v-model:visible="addMemberVisible"
|
||||||
|
@ -95,12 +124,6 @@
|
||||||
} from '@/models/projectManagement/projectAndPermission';
|
} from '@/models/projectManagement/projectAndPermission';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
roleIds: string;
|
|
||||||
userGroupOptions: ProjectUserOption[];
|
|
||||||
keyword: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openModal } = useModal();
|
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 () => {
|
const initData = async () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
setLoadListParams({
|
setLoadListParams({
|
||||||
filter: {
|
filter: {
|
||||||
roleIds: props.roleIds ? [props.roleIds] : [],
|
roleIds: roleIds.value ? [roleIds.value] : [],
|
||||||
},
|
},
|
||||||
projectId: lastProjectId.value,
|
projectId: lastProjectId.value,
|
||||||
keyword: props.keyword,
|
keyword: keyword.value,
|
||||||
});
|
});
|
||||||
await loadList();
|
await loadList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const searchHandler = () => {
|
||||||
|
initData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeSelect = () => {
|
||||||
|
initData();
|
||||||
|
};
|
||||||
|
|
||||||
// 跨页选择项
|
// 跨页选择项
|
||||||
const selectData = ref<string[] | undefined>([]);
|
const selectData = ref<string[] | undefined>([]);
|
||||||
|
|
||||||
|
@ -250,6 +298,7 @@
|
||||||
resetSelector();
|
resetSelector();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
deleteLoading.value = false;
|
deleteLoading.value = false;
|
||||||
|
@ -276,9 +325,9 @@
|
||||||
selectAll: !!selectAll,
|
selectAll: !!selectAll,
|
||||||
excludeIds: excludeIds || [],
|
excludeIds: excludeIds || [],
|
||||||
selectIds: selectedIds || [],
|
selectIds: selectedIds || [],
|
||||||
keyword: props.keyword,
|
keyword: keyword.value,
|
||||||
condition: {
|
condition: {
|
||||||
keyword: props.keyword,
|
keyword: keyword.value,
|
||||||
filter: propsRes.value.filter,
|
filter: propsRes.value.filter,
|
||||||
combine: batchParams.value.condition,
|
combine: batchParams.value.condition,
|
||||||
},
|
},
|
||||||
|
@ -288,6 +337,7 @@
|
||||||
initData();
|
initData();
|
||||||
resetSelector();
|
resetSelector();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -328,6 +378,7 @@
|
||||||
record.showUserSelect = false;
|
record.showUserSelect = false;
|
||||||
loadList();
|
loadList();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -360,15 +411,11 @@
|
||||||
editProjectMember(record);
|
editProjectMember(record);
|
||||||
};
|
};
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(async () => {
|
||||||
|
await initOptions();
|
||||||
initData();
|
initData();
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
initData,
|
|
||||||
addMember,
|
|
||||||
});
|
|
||||||
|
|
||||||
await tableStore.initColumn(TableKeyEnum.PROJECT_MEMBER, columns, 'drawer');
|
await tableStore.initColumn(TableKeyEnum.PROJECT_MEMBER, columns, 'drawer');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,87 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-4 grid grid-cols-4 gap-2">
|
<memberTable v-if="isMounted" />
|
||||||
<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"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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 项目管理-项目与权限-成员
|
* @description 项目管理-项目与权限-成员
|
||||||
*/
|
*/
|
||||||
const appStore = useAppStore();
|
const memberTable = defineAsyncComponent(() => import('./components/memberTable.vue'));
|
||||||
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 isMounted = ref(false);
|
const isMounted = ref(false);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,14 @@
|
||||||
></a-textarea>
|
></a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('system.resourcePool.serverUrl')" field="serverUrl" class="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
|
<a-input
|
||||||
v-model:model-value="form.serverUrl"
|
v-model:model-value="form.serverUrl"
|
||||||
:placeholder="t('system.resourcePool.rootUrlPlaceholder')"
|
:placeholder="t('system.resourcePool.rootUrlPlaceholder')"
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default {
|
||||||
'system.resourcePool.deletePoolCancel': 'Cancel',
|
'system.resourcePool.deletePoolCancel': 'Cancel',
|
||||||
'system.resourcePool.deletePoolSuccess': 'Deleted successfully',
|
'system.resourcePool.deletePoolSuccess': 'Deleted successfully',
|
||||||
'system.resourcePool.detailDesc': 'Description',
|
'system.resourcePool.detailDesc': 'Description',
|
||||||
'system.resourcePool.detailUrl': 'Current site URL',
|
'system.resourcePool.detailUrl': 'Intranet URL',
|
||||||
'system.resourcePool.detailRange': 'Applied organization',
|
'system.resourcePool.detailRange': 'Applied organization',
|
||||||
'system.resourcePool.detailUse': 'Use',
|
'system.resourcePool.detailUse': 'Use',
|
||||||
'system.resourcePool.detailMirror': 'Mirror',
|
'system.resourcePool.detailMirror': 'Mirror',
|
||||||
|
@ -41,7 +41,9 @@ export default {
|
||||||
'system.resourcePool.namePlaceholder': 'Please enter a resource pool name',
|
'system.resourcePool.namePlaceholder': 'Please enter a resource pool name',
|
||||||
'system.resourcePool.desc': 'Description',
|
'system.resourcePool.desc': 'Description',
|
||||||
'system.resourcePool.descPlaceholder': 'Please describe the resource pool',
|
'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.rootUrlPlaceholder': 'MS deployment address',
|
||||||
'system.resourcePool.orgRange': 'Applied organization',
|
'system.resourcePool.orgRange': 'Applied organization',
|
||||||
'system.resourcePool.orgAll': 'All organization',
|
'system.resourcePool.orgAll': 'All organization',
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default {
|
||||||
'system.resourcePool.deletePoolCancel': '取消',
|
'system.resourcePool.deletePoolCancel': '取消',
|
||||||
'system.resourcePool.deletePoolSuccess': '删除成功',
|
'system.resourcePool.deletePoolSuccess': '删除成功',
|
||||||
'system.resourcePool.detailDesc': '描述',
|
'system.resourcePool.detailDesc': '描述',
|
||||||
'system.resourcePool.detailUrl': '当前站点 URL',
|
'system.resourcePool.detailUrl': '内网 URL',
|
||||||
'system.resourcePool.detailRange': '应用组织',
|
'system.resourcePool.detailRange': '应用组织',
|
||||||
'system.resourcePool.detailUse': '用途',
|
'system.resourcePool.detailUse': '用途',
|
||||||
'system.resourcePool.detailMirror': '镜像',
|
'system.resourcePool.detailMirror': '镜像',
|
||||||
|
@ -40,7 +40,8 @@ export default {
|
||||||
'system.resourcePool.namePlaceholder': '请输入资源池名称',
|
'system.resourcePool.namePlaceholder': '请输入资源池名称',
|
||||||
'system.resourcePool.desc': '描述',
|
'system.resourcePool.desc': '描述',
|
||||||
'system.resourcePool.descPlaceholder': '请对该资源池进行描述',
|
'system.resourcePool.descPlaceholder': '请对该资源池进行描述',
|
||||||
'system.resourcePool.serverUrl': '当前站点 URL',
|
'system.resourcePool.serverUrl': '内网 URL',
|
||||||
|
'system.resourcePool.serverUrlTip': '资源池部署在内网时,可走内网地址',
|
||||||
'system.resourcePool.rootUrlPlaceholder': 'MS的部署地址',
|
'system.resourcePool.rootUrlPlaceholder': 'MS的部署地址',
|
||||||
'system.resourcePool.orgRange': '应用组织',
|
'system.resourcePool.orgRange': '应用组织',
|
||||||
'system.resourcePool.orgAll': '全部组织',
|
'system.resourcePool.orgAll': '全部组织',
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #second>
|
<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]">
|
<div class="flex flex-row items-center justify-between px-[24px]">
|
||||||
<a-tooltip :content="currentUserGroupItem.name">
|
<a-tooltip :content="currentUserGroupItem.name">
|
||||||
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
|
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[16px]">
|
<div class="flex-1 overflow-hidden">
|
||||||
<UserTable
|
<UserTable
|
||||||
v-if="currentTable === 'user' && couldShowUser"
|
v-if="currentTable === 'user' && couldShowUser"
|
||||||
ref="userRef"
|
ref="userRef"
|
||||||
|
|
Loading…
Reference in New Issue