feat(项目日志): 项目日志&项目选择器
This commit is contained in:
parent
064894fa3b
commit
509804dc06
|
@ -1,9 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<a-config-provider :locale="locale">
|
<a-config-provider :locale="locale">
|
||||||
<router-view />
|
<router-view />
|
||||||
<template #empty>
|
<!-- <template #empty>
|
||||||
<MsEmpty />
|
<MsEmpty />
|
||||||
</template>
|
</template> -->
|
||||||
<!-- <global-setting /> -->
|
<!-- <global-setting /> -->
|
||||||
</a-config-provider>
|
</a-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
import { ProjectListUrl } from '@/api/requrls/setting/project';
|
import { ProjectListUrl } from '@/api/requrls/project-management/project';
|
||||||
import type { ProjectListItem } from '@/models/setting/project';
|
import type { ProjectListItem } from '@/models/setting/project';
|
||||||
|
|
||||||
export function getProjectList(organizationId: string) {
|
export function getProjectList(organizationId: string) {
|
|
@ -6,13 +6,15 @@ import {
|
||||||
GetOrgLogListUrl,
|
GetOrgLogListUrl,
|
||||||
GetOrgLogOptionsUrl,
|
GetOrgLogOptionsUrl,
|
||||||
GetOrgLogUserUrl,
|
GetOrgLogUserUrl,
|
||||||
|
GetProjectLogListUrl,
|
||||||
|
GetProjectLogUserUrl,
|
||||||
} from '@/api/requrls/setting/log';
|
} from '@/api/requrls/setting/log';
|
||||||
|
|
||||||
import type { CommonList } from '@/models/common';
|
import type { CommonList } from '@/models/common';
|
||||||
import type { LogOptions, LogItem, UserItem } from '@/models/setting/log';
|
import type { LogOptions, LogItem, UserItem, LogListParams } from '@/models/setting/log';
|
||||||
|
|
||||||
// 获取系统日志列表
|
// 获取系统日志列表
|
||||||
export function getSystemLogList(data: any) {
|
export function getSystemLogList(data: LogListParams) {
|
||||||
return MSR.post<CommonList<LogItem>>({ url: GetSystemLogListUrl, data });
|
return MSR.post<CommonList<LogItem>>({ url: GetSystemLogListUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +24,12 @@ export function getSystemLogOptions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取系统日志-操作用户列表
|
// 获取系统日志-操作用户列表
|
||||||
export function getSystemLogUsers() {
|
export function getSystemLogUsers({ keyword }: { keyword: string }) {
|
||||||
return MSR.get<UserItem[]>({ url: GetSystemLogUserUrl });
|
return MSR.get<UserItem[]>({ url: GetSystemLogUserUrl, params: { keyword } });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取组织日志列表
|
// 获取组织日志列表
|
||||||
export function getOrgLogList(data: any) {
|
export function getOrgLogList(data: LogListParams) {
|
||||||
return MSR.post<CommonList<LogItem>>({ url: GetOrgLogListUrl, data });
|
return MSR.post<CommonList<LogItem>>({ url: GetOrgLogListUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +39,16 @@ export function getOrgLogOptions(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取组织日志-操作用户列表
|
// 获取组织日志-操作用户列表
|
||||||
export function getOrgLogUsers(id: string) {
|
export function getOrgLogUsers({ id, keyword }: { id: string; keyword: string }) {
|
||||||
return MSR.get<UserItem[]>({ url: GetOrgLogUserUrl, params: id });
|
return MSR.get<UserItem[]>({ url: `${GetOrgLogUserUrl}/${id}`, params: { keyword } });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取项目日志列表
|
||||||
|
export function getProjectLogList(data: LogListParams) {
|
||||||
|
return MSR.post<CommonList<LogItem>>({ url: GetProjectLogListUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取项目日志-操作用户列表
|
||||||
|
export function getProjectLogUsers({ id, keyword }: { id: string; keyword: string }) {
|
||||||
|
return MSR.get<UserItem[]>({ url: `${GetProjectLogUserUrl}/${id}`, params: { keyword } });
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const ProjectListUrl = '/project/list/options';
|
||||||
|
|
||||||
|
export default {};
|
|
@ -5,5 +5,9 @@ export const GetSystemLogUserUrl = '/operation/log/user/list'; // 搜索操作
|
||||||
|
|
||||||
// 组织级别日志
|
// 组织级别日志
|
||||||
export const GetOrgLogListUrl = '/organization/log/list';
|
export const GetOrgLogListUrl = '/organization/log/list';
|
||||||
export const GetOrgLogOptionsUrl = '/organization/log/get/options'; // 获取组织/项目级联下拉框选项
|
export const GetOrgLogOptionsUrl = '/organization/log/get/options'; // 获取项目级联下拉框选
|
||||||
export const GetOrgLogUserUrl = '/organization/log/user/list'; // 搜索操作用户
|
export const GetOrgLogUserUrl = '/organization/log/user/list'; // 搜索操作用户
|
||||||
|
|
||||||
|
// 项目级别日志
|
||||||
|
export const GetProjectLogListUrl = '/project/log/list';
|
||||||
|
export const GetProjectLogUserUrl = '/project/log/user/list'; // 搜索操作用户
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export const ProjectListUrl = '/system/project/list';
|
|
||||||
|
|
||||||
export default {};
|
|
|
@ -526,6 +526,18 @@
|
||||||
background-color: var(--color-text-input-border);
|
background-color: var(--color-text-input-border);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.ms-card-container .arco-scrollbar .arco-scrollbar-track-direction-vertical {
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
.ms-card-container .arco-scrollbar .arco-scrollbar-track-direction-horizontal {
|
||||||
|
bottom: -10px;
|
||||||
|
}
|
||||||
|
.ms-base-table .arco-scrollbar .arco-scrollbar-track-direction-vertical {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.ms-base-table .arco-scrollbar .arco-scrollbar-track-direction-horizontal {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
.arco-scrollbar-track-direction-vertical {
|
.arco-scrollbar-track-direction-vertical {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
.arco-scrollbar-thumb-bar {
|
.arco-scrollbar-thumb-bar {
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
import { watch, ref, h, defineComponent } from 'vue';
|
import { watch, ref, h, defineComponent, onBeforeMount } from 'vue';
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce } from 'lodash-es';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import type { SelectOptionData } from '@arco-design/web-vue';
|
import type { SelectOptionData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
export type ModelType = string | number | Record<string, any> | (string | number | Record<string, any>)[];
|
export type ModelType = string | number | Record<string, any> | (string | number | Record<string, any>)[];
|
||||||
|
export type RemoteFieldsMap = {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
export interface MsSearchSelectProps {
|
export interface MsSearchSelectProps {
|
||||||
|
mode?: 'static' | 'remote'; // 静态模式,远程模式。默认为静态模式,需要传入 options 数据;远程模式需要传入请求函数
|
||||||
modelValue: ModelType;
|
modelValue: ModelType;
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
searchKeys: string[]; // 需要搜索的 key 名,关键字会遍历这个 key 数组,然后取 item[key] 进行模糊匹配
|
searchKeys: string[]; // 需要搜索的 key 名,关键字会遍历这个 key 数组,然后取 item[key] 进行模糊匹配
|
||||||
options: SelectOptionData[];
|
options: SelectOptionData[];
|
||||||
|
remoteFieldsMap?: RemoteFieldsMap; // 远程模式下的结果 key 映射,例如 { value: 'id' },表示远程请求时,会将返回结果的 id 赋值到 value 字段
|
||||||
|
remoteExtraParams?: Record<string, any>; // 远程模式下的额外参数
|
||||||
|
remoteFunc?(params: Record<string, any>): Promise<any>; // 远程模式下的请求函数,返回一个 Promise
|
||||||
optionLabelRender?: (item: SelectOptionData) => string; // 自定义 option 的 label 渲染,返回一个 html 字符串,默认使用 item.label
|
optionLabelRender?: (item: SelectOptionData) => string; // 自定义 option 的 label 渲染,返回一个 html 字符串,默认使用 item.label
|
||||||
|
optionTooltipContent?: (item: SelectOptionData) => string; // 自定义 option 的 tooltip 内容,返回一个字符串,默认使用 item.label
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent(
|
export default defineComponent(
|
||||||
|
@ -21,7 +32,8 @@ export default defineComponent(
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const innerValue = ref(props.modelValue);
|
const innerValue = ref(props.modelValue);
|
||||||
const filterOptions = ref<SelectOptionData[]>([...props.options]);
|
const filterOptions = ref<SelectOptionData[]>([]);
|
||||||
|
const remoteOriginOptions = ref<SelectOptionData[]>([...props.options]);
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
@ -36,34 +48,73 @@ export default defineComponent(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleUserSearch(val: string) {
|
const loading = ref(false);
|
||||||
if (val.trim() === '') {
|
|
||||||
filterOptions.value = [...props.options];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const highlightedKeyword = `<span class="text-[rgb(var(--primary-4))]">${val}</span>`;
|
|
||||||
filterOptions.value = props.options
|
|
||||||
.map((e) => {
|
|
||||||
const item = { ...e };
|
|
||||||
let hasMatch = false;
|
|
||||||
for (let i = 0; i < props.searchKeys.length; i++) {
|
|
||||||
// 遍历传入的搜索字段
|
|
||||||
const key = props.searchKeys[i];
|
|
||||||
|
|
||||||
if (e[key].includes(val)) {
|
async function handleUserSearch(val: string) {
|
||||||
// 是否匹配
|
try {
|
||||||
hasMatch = true;
|
loading.value = true;
|
||||||
item[key] = e[key].replace(new RegExp(val, 'gi'), highlightedKeyword); // 高亮关键字替换
|
// 如果是远程模式,则请求接口数据
|
||||||
|
if (props.mode === 'remote' && typeof props.remoteFunc === 'function') {
|
||||||
|
remoteOriginOptions.value = (await props.remoteFunc({ ...props.remoteExtraParams, keyword: val })).map(
|
||||||
|
(e: any) => {
|
||||||
|
const item = {
|
||||||
|
...e,
|
||||||
|
};
|
||||||
|
// 支持接口字段自定义映射
|
||||||
|
if (props.remoteFieldsMap) {
|
||||||
|
const map = props.remoteFieldsMap;
|
||||||
|
Object.keys(map).forEach((key) => {
|
||||||
|
item[key] = e[map[key]];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 为了避免关键词搜索影响 label 值,这里需要开辟新字段存储 tooltip 内容
|
||||||
|
item.tooltipContent =
|
||||||
|
typeof props.optionTooltipContent === 'function' ? props.optionTooltipContent(e) : e.label;
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
if (hasMatch) {
|
}
|
||||||
return item;
|
if (val.trim() === '') {
|
||||||
}
|
// 如果搜索关键字为空,则直接返回所有数据
|
||||||
return null;
|
filterOptions.value = [...remoteOriginOptions.value];
|
||||||
})
|
return;
|
||||||
.filter((e) => e) as SelectOptionData[];
|
}
|
||||||
|
const highlightedKeyword = `<span class="text-[rgb(var(--primary-4))]">${val}</span>`;
|
||||||
|
filterOptions.value = remoteOriginOptions.value
|
||||||
|
.map((e) => {
|
||||||
|
const item = { ...e };
|
||||||
|
let hasMatch = false;
|
||||||
|
for (let i = 0; i < props.searchKeys.length; i++) {
|
||||||
|
// 遍历传入的搜索字段
|
||||||
|
const key = props.searchKeys[i];
|
||||||
|
if (e[key].includes(val)) {
|
||||||
|
// 是否匹配
|
||||||
|
hasMatch = true;
|
||||||
|
item[key] = e[key].replace(new RegExp(val, 'gi'), highlightedKeyword); // 高亮关键字替换
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasMatch) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter((e) => e) as SelectOptionData[];
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const optionItemLabelRender = (item: SelectOptionData) =>
|
||||||
|
typeof props.optionLabelRender === 'function'
|
||||||
|
? h('div', { innerHTML: props.optionLabelRender(item) })
|
||||||
|
: item.label;
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
handleUserSearch('');
|
||||||
|
});
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<a-select
|
<a-select
|
||||||
default-value={innerValue}
|
default-value={innerValue}
|
||||||
|
@ -71,6 +122,7 @@ export default defineComponent(
|
||||||
allow-clear={props.allowClear}
|
allow-clear={props.allowClear}
|
||||||
allow-search
|
allow-search
|
||||||
filter-option={false}
|
filter-option={false}
|
||||||
|
loading={loading.value}
|
||||||
onUpdate:model-value={(value: ModelType) => emit('update:modelValue', value)}
|
onUpdate:model-value={(value: ModelType) => emit('update:modelValue', value)}
|
||||||
onInputValueChange={debounce(handleUserSearch, 300)}
|
onInputValueChange={debounce(handleUserSearch, 300)}
|
||||||
>
|
>
|
||||||
|
@ -78,19 +130,32 @@ export default defineComponent(
|
||||||
prefix: () => t(props.prefix || ''),
|
prefix: () => t(props.prefix || ''),
|
||||||
default: () =>
|
default: () =>
|
||||||
filterOptions.value.map((item) => (
|
filterOptions.value.map((item) => (
|
||||||
<a-option key={item.id} value={item.value}>
|
<a-tooltip content={item.tooltipContent} mouse-enter-delay={500}>
|
||||||
{typeof props.optionLabelRender === 'function'
|
<a-option key={item.id} value={item.value}>
|
||||||
? h('div', { innerHTML: props.optionLabelRender(item) })
|
{optionItemLabelRender(item)}
|
||||||
: item.label}
|
</a-option>
|
||||||
</a-option>
|
</a-tooltip>
|
||||||
)),
|
)),
|
||||||
}}
|
}}
|
||||||
</a-select>
|
</a-select>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
/* eslint-disable vue/require-prop-types */
|
||||||
props: ['modelValue', 'allowClear', 'placeholder', 'prefix', 'searchKeys', 'options', 'optionLabelRender'],
|
props: [
|
||||||
|
'mode',
|
||||||
|
'modelValue',
|
||||||
|
'allowClear',
|
||||||
|
'placeholder',
|
||||||
|
'prefix',
|
||||||
|
'searchKeys',
|
||||||
|
'options',
|
||||||
|
'optionLabelRender',
|
||||||
|
'remoteFieldsMap',
|
||||||
|
'remoteExtraParams',
|
||||||
|
'remoteFunc',
|
||||||
|
'optionTooltipContent',
|
||||||
|
],
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -140,9 +140,6 @@
|
||||||
.arco-divider {
|
.arco-divider {
|
||||||
@apply mb-0;
|
@apply mb-0;
|
||||||
}
|
}
|
||||||
.ms-card-container {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.card-header {
|
.card-header {
|
||||||
@apply flex items-center;
|
@apply flex items-center;
|
||||||
|
@ -160,11 +157,5 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:deep(.arco-scrollbar-track-direction-vertical) {
|
|
||||||
right: -10px;
|
|
||||||
}
|
|
||||||
:deep(.arco-scrollbar-track-direction-horizontal) {
|
|
||||||
bottom: -10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -24,8 +24,9 @@
|
||||||
<a-option
|
<a-option
|
||||||
:value="project.id"
|
:value="project.id"
|
||||||
:class="project.id === appStore.getCurrentProjectId ? 'arco-select-option-selected' : ''"
|
:class="project.id === appStore.getCurrentProjectId ? 'arco-select-option-selected' : ''"
|
||||||
>{{ project.name }}</a-option
|
|
||||||
>
|
>
|
||||||
|
{{ project.name }}
|
||||||
|
</a-option>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-divider direction="vertical" class="mr-0" />
|
<a-divider direction="vertical" class="mr-0" />
|
||||||
|
@ -188,7 +189,7 @@
|
||||||
import TopMenu from '@/components/business/ms-top-menu/index.vue';
|
import TopMenu from '@/components/business/ms-top-menu/index.vue';
|
||||||
import MessageBox from '../message-box/index.vue';
|
import MessageBox from '../message-box/index.vue';
|
||||||
import { NOT_SHOW_PROJECT_SELECT_MODULE } from '@/router/constants';
|
import { NOT_SHOW_PROJECT_SELECT_MODULE } from '@/router/constants';
|
||||||
// import { getProjectList } from '@/api/modules/setting/project';
|
import { getProjectList } from '@/api/modules/project-management/project';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import type { ProjectListItem } from '@/models/setting/project';
|
import type { ProjectListItem } from '@/models/setting/project';
|
||||||
|
@ -207,12 +208,12 @@
|
||||||
const projectList: Ref<ProjectListItem[]> = ref([]);
|
const projectList: Ref<ProjectListItem[]> = ref([]);
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
// try {
|
try {
|
||||||
// const res = await getProjectList(appStore.getCurrentOrgId);
|
const res = await getProjectList(appStore.getCurrentOrgId);
|
||||||
// projectList.value = res;
|
projectList.value = res;
|
||||||
// } catch (error) {
|
} catch (error) {
|
||||||
// console.log(error);
|
console.log(error);
|
||||||
// }
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const showProjectSelect = computed(() => {
|
const showProjectSelect = computed(() => {
|
||||||
|
@ -364,4 +365,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@/models/setting/project @/api/modules/setting/project
|
@/models/setting/project @/api/modules/setting/project @/api/modules/project-management/project
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="project-selection">
|
|
||||||
<a-select v-model="value" placeholder="Please select ...">
|
|
||||||
<a-option v-for="item of data" :key="item.key" :value="item" :label="item.label" />
|
|
||||||
</a-select>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const value = ref('默认工作空间');
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
value: '测试项目1',
|
|
||||||
label: '测试项目1',
|
|
||||||
key: '1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '测试项目2',
|
|
||||||
label: '测试项目2',
|
|
||||||
key: '2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '默认工作空间',
|
|
||||||
label: '默认工作空间',
|
|
||||||
key: '2',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.project-selection {
|
|
||||||
& .arco-select-view-single {
|
|
||||||
@apply border-none;
|
|
||||||
|
|
||||||
color: #323233;
|
|
||||||
background-color: var(--color-bg-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,5 +1,36 @@
|
||||||
import type { RouteEnum } from '@/enums/routeEnum';
|
import type { RouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
|
interface Sort {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Combine {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Filter {
|
||||||
|
[key: string]: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LogListParams {
|
||||||
|
keyword: string;
|
||||||
|
filter: Filter;
|
||||||
|
combine: Combine;
|
||||||
|
current: number;
|
||||||
|
pageSize: number;
|
||||||
|
sort: Sort;
|
||||||
|
operUser: string; // 操作人
|
||||||
|
startTime: number;
|
||||||
|
endTime: number;
|
||||||
|
projectIds: string[]; // 项目 id 集合
|
||||||
|
organizationIds: string[]; // 组织 id 集合
|
||||||
|
type: string; // 操作类型
|
||||||
|
module: string; // 操作对象
|
||||||
|
content: string; // 操作名称
|
||||||
|
level: string; // 系统/组织/项目级别
|
||||||
|
sortString: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OptionsItem {
|
export interface OptionsItem {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -61,6 +61,7 @@ const useUserStore = defineStore('user', {
|
||||||
setToken(res.sessionId, res.csrfToken);
|
setToken(res.sessionId, res.csrfToken);
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
appStore.setCurrentOrgId(res.lastOrganizationId || '');
|
appStore.setCurrentOrgId(res.lastOrganizationId || '');
|
||||||
|
appStore.setCurrentProjectId(res.lastProjectId || '');
|
||||||
this.setInfo(res);
|
this.setInfo(res);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
clearToken();
|
clearToken();
|
||||||
|
@ -96,9 +97,8 @@ const useUserStore = defineStore('user', {
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
setToken(res.sessionId, res.csrfToken);
|
setToken(res.sessionId, res.csrfToken);
|
||||||
this.setInfo(res);
|
this.setInfo(res);
|
||||||
if (appStore.currentOrgId === '') {
|
appStore.setCurrentOrgId(res.lastOrganizationId || '');
|
||||||
appStore.setCurrentOrgId(res.lastOrganizationId || '');
|
appStore.setCurrentProjectId(res.lastProjectId || '');
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,17 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<MsCard simple auto-height>
|
<MsCard simple auto-height>
|
||||||
<div class="filter-box">
|
<div class="filter-box">
|
||||||
<MsSearchSelect
|
<div class="filter-item">
|
||||||
v-model:model-value="operUser"
|
<MsSearchSelect
|
||||||
placeholder="system.log.operatorPlaceholder"
|
v-model:model-value="operUser"
|
||||||
prefix="system.log.operator"
|
mode="remote"
|
||||||
:options="userList"
|
placeholder="system.log.operatorPlaceholder"
|
||||||
:search-keys="['label', 'email']"
|
prefix="system.log.operator"
|
||||||
:option-label-render="
|
:options="[]"
|
||||||
(item) => `${item.label}<span class='text-[var(--color-text-2)]'>(${item.email})</span>`
|
:remote-func="requestFuncMap[props.mode].usersFunc"
|
||||||
"
|
:remote-extra-params="{ id: props.mode === 'PROJECT' ? appStore.currentProjectId : appStore.currentOrgId }"
|
||||||
allow-clear
|
:remote-fields-map="{
|
||||||
/>
|
id: 'id',
|
||||||
|
value: 'value',
|
||||||
|
label: 'name',
|
||||||
|
email: 'email',
|
||||||
|
}"
|
||||||
|
:search-keys="['label', 'email']"
|
||||||
|
:option-tooltip-content="(item) => `${item.name}(${item.email})`"
|
||||||
|
:option-label-render="
|
||||||
|
(item) => `${item.label}<span class='text-[var(--color-text-2)]'>(${item.email})</span>`
|
||||||
|
"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<a-range-picker
|
<a-range-picker
|
||||||
v-model:model-value="time"
|
v-model:model-value="time"
|
||||||
show-time
|
show-time
|
||||||
|
@ -30,6 +42,7 @@
|
||||||
</template>
|
</template>
|
||||||
</a-range-picker>
|
</a-range-picker>
|
||||||
<MsCascader
|
<MsCascader
|
||||||
|
v-if="props.mode !== 'PROJECT'"
|
||||||
v-model:model-value="operateRange"
|
v-model:model-value="operateRange"
|
||||||
v-model:level="level"
|
v-model:level="level"
|
||||||
:options="rangeOptions"
|
:options="rangeOptions"
|
||||||
|
@ -37,6 +50,7 @@
|
||||||
:level-top="[...MENU_LEVEL]"
|
:level-top="[...MENU_LEVEL]"
|
||||||
:virtual-list-props="{ height: 200 }"
|
:virtual-list-props="{ height: 200 }"
|
||||||
:loading="rangeLoading"
|
:loading="rangeLoading"
|
||||||
|
class="filter-item"
|
||||||
/>
|
/>
|
||||||
<a-select v-model:model-value="type" class="filter-item">
|
<a-select v-model:model-value="type" class="filter-item">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
|
@ -53,6 +67,7 @@
|
||||||
:placeholder="t('system.log.operateTargetPlaceholder')"
|
:placeholder="t('system.log.operateTargetPlaceholder')"
|
||||||
:panel-width="100"
|
:panel-width="100"
|
||||||
strictly
|
strictly
|
||||||
|
class="filter-item"
|
||||||
/>
|
/>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="content"
|
v-model:model-value="content"
|
||||||
|
@ -64,11 +79,19 @@
|
||||||
{{ t('system.log.operateName') }}
|
{{ t('system.log.operateName') }}
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
<div v-if="props.mode === 'PROJECT'">
|
||||||
|
<a-button type="outline" @click="searchLog">{{ t('system.log.search') }}</a-button>
|
||||||
|
<a-button type="outline" class="arco-btn-outline--secondary ml-[8px]" @click="resetFilter">
|
||||||
|
{{ t('system.log.reset') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-button type="outline" @click="searchLog">{{ t('system.log.search') }}</a-button>
|
<template v-if="props.mode !== 'PROJECT'">
|
||||||
<a-button type="outline" class="arco-btn-outline--secondary ml-[8px]" @click="resetFilter">
|
<a-button type="outline" @click="searchLog">{{ t('system.log.search') }}</a-button>
|
||||||
{{ t('system.log.reset') }}
|
<a-button type="outline" class="arco-btn-outline--secondary ml-[8px]" @click="resetFilter">
|
||||||
</a-button>
|
{{ t('system.log.reset') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
</MsCard>
|
</MsCard>
|
||||||
<div class="log-card">
|
<div class="log-card">
|
||||||
<div class="log-card-header">
|
<div class="log-card-header">
|
||||||
|
@ -109,6 +132,8 @@
|
||||||
getOrgLogList,
|
getOrgLogList,
|
||||||
getOrgLogOptions,
|
getOrgLogOptions,
|
||||||
getOrgLogUsers,
|
getOrgLogUsers,
|
||||||
|
getProjectLogList,
|
||||||
|
getProjectLogUsers,
|
||||||
} from '@/api/modules/setting/log';
|
} from '@/api/modules/setting/log';
|
||||||
import MsCascader from '@/components/business/ms-cascader/index.vue';
|
import MsCascader from '@/components/business/ms-cascader/index.vue';
|
||||||
import useTableStore from '@/store/modules/ms-table';
|
import useTableStore from '@/store/modules/ms-table';
|
||||||
|
@ -151,9 +176,9 @@
|
||||||
usersFunc: getOrgLogUsers,
|
usersFunc: getOrgLogUsers,
|
||||||
},
|
},
|
||||||
[MENU_LEVEL[2]]: {
|
[MENU_LEVEL[2]]: {
|
||||||
listFunc: getOrgLogList,
|
listFunc: getProjectLogList,
|
||||||
optionsFunc: getOrgLogOptions,
|
optionsFunc: getOrgLogOptions, // 忽略,这里并不加载
|
||||||
usersFunc: getOrgLogUsers,
|
usersFunc: getProjectLogUsers,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,6 +223,7 @@
|
||||||
* 初始化操作范围级联选项
|
* 初始化操作范围级联选项
|
||||||
*/
|
*/
|
||||||
async function initRangeOptions() {
|
async function initRangeOptions() {
|
||||||
|
if (props.mode === 'PROJECT') return;
|
||||||
try {
|
try {
|
||||||
rangeLoading.value = true;
|
rangeLoading.value = true;
|
||||||
const res = await requestFuncMap[props.mode].optionsFunc(appStore.currentOrgId);
|
const res = await requestFuncMap[props.mode].optionsFunc(appStore.currentOrgId);
|
||||||
|
@ -418,7 +444,7 @@
|
||||||
title: 'system.log.time',
|
title: 'system.log.time',
|
||||||
dataIndex: 'createTime',
|
dataIndex: 'createTime',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 170,
|
width: 180,
|
||||||
sortable: {
|
sortable: {
|
||||||
sortDirections: ['ascend', 'descend'],
|
sortDirections: ['ascend', 'descend'],
|
||||||
},
|
},
|
||||||
|
@ -433,6 +459,7 @@
|
||||||
columns,
|
columns,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
showSelectAll: false,
|
showSelectAll: false,
|
||||||
|
size: 'default',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -474,7 +501,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initUserList();
|
// initUserList();
|
||||||
initRangeOptions();
|
initRangeOptions();
|
||||||
initModuleOptions();
|
initModuleOptions();
|
||||||
searchLog();
|
searchLog();
|
||||||
|
@ -487,6 +514,9 @@
|
||||||
|
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
.filter-item {
|
||||||
|
@apply overflow-hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 1400px) {
|
@media screen and (max-width: 1400px) {
|
||||||
.filter-box {
|
.filter-box {
|
||||||
|
|
Loading…
Reference in New Issue