mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
refactor: PageTable组件重构
This commit is contained in:
@@ -15,7 +15,7 @@ const config = {
|
|||||||
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
|
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
|
||||||
|
|
||||||
// 系统版本
|
// 系统版本
|
||||||
version: 'v1.6.0',
|
version: 'v1.6.1',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
66
mayfly_go_web/src/components/Grid/components/GridItem.vue
Normal file
66
mayfly_go_web/src/components/Grid/components/GridItem.vue
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<div v-show="isShow" :style="style">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts" name="GridItem">
|
||||||
|
import { computed, inject, Ref, ref, useAttrs, watch } from 'vue';
|
||||||
|
import { BreakPoint, Responsive } from '../interface/index';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
offset?: number;
|
||||||
|
span?: number;
|
||||||
|
suffix?: boolean;
|
||||||
|
xs?: Responsive;
|
||||||
|
sm?: Responsive;
|
||||||
|
md?: Responsive;
|
||||||
|
lg?: Responsive;
|
||||||
|
xl?: Responsive;
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
offset: 0,
|
||||||
|
span: 1,
|
||||||
|
suffix: false,
|
||||||
|
xs: undefined,
|
||||||
|
sm: undefined,
|
||||||
|
md: undefined,
|
||||||
|
lg: undefined,
|
||||||
|
xl: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const attrs = useAttrs() as { index: string };
|
||||||
|
const isShow = ref(true);
|
||||||
|
|
||||||
|
// 注入断点
|
||||||
|
const breakPoint = inject<Ref<BreakPoint>>('breakPoint', ref('xl'));
|
||||||
|
const shouldHiddenIndex = inject<Ref<number>>('shouldHiddenIndex', ref(-1));
|
||||||
|
watch(
|
||||||
|
() => [shouldHiddenIndex.value, breakPoint.value],
|
||||||
|
(n) => {
|
||||||
|
if (attrs.index) {
|
||||||
|
isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= Number(n[0]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const gap = inject('gap', 0);
|
||||||
|
const cols = inject('cols', ref(4));
|
||||||
|
const style = computed(() => {
|
||||||
|
let span = props[breakPoint.value]?.span ?? props.span;
|
||||||
|
let offset = props[breakPoint.value]?.offset ?? props.offset;
|
||||||
|
if (props.suffix) {
|
||||||
|
return {
|
||||||
|
gridColumnStart: cols.value - span - offset + 1,
|
||||||
|
gridColumnEnd: `span ${span + offset}`,
|
||||||
|
marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : 'unset',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
gridColumn: `span ${span + offset > cols.value ? cols.value : span + offset}/span ${span + offset > cols.value ? cols.value : span + offset}`,
|
||||||
|
marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : 'unset',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
159
mayfly_go_web/src/components/Grid/index.vue
Normal file
159
mayfly_go_web/src/components/Grid/index.vue
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="style">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="Grid">
|
||||||
|
import { ref, watch, useSlots, computed, provide, onBeforeMount, onMounted, onUnmounted, onDeactivated, onActivated, VNodeArrayChildren, VNode } from 'vue';
|
||||||
|
import type { BreakPoint } from './interface/index';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
cols?: number | Record<BreakPoint, number>;
|
||||||
|
collapsed?: boolean;
|
||||||
|
collapsedRows?: number;
|
||||||
|
gap?: [number, number] | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
cols: () => ({ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }),
|
||||||
|
collapsed: false,
|
||||||
|
collapsedRows: 1,
|
||||||
|
gap: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => props.collapsed && findIndex());
|
||||||
|
onMounted(() => {
|
||||||
|
resize({ target: { innerWidth: window.innerWidth } } as unknown as UIEvent);
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
});
|
||||||
|
onActivated(() => {
|
||||||
|
resize({ target: { innerWidth: window.innerWidth } } as unknown as UIEvent);
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', resize);
|
||||||
|
});
|
||||||
|
onDeactivated(() => {
|
||||||
|
window.removeEventListener('resize', resize);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听屏幕变化
|
||||||
|
const resize = (e: UIEvent) => {
|
||||||
|
let width = (e.target as Window).innerWidth;
|
||||||
|
switch (!!width) {
|
||||||
|
case width < 768:
|
||||||
|
breakPoint.value = 'xs';
|
||||||
|
break;
|
||||||
|
case width >= 768 && width < 992:
|
||||||
|
breakPoint.value = 'sm';
|
||||||
|
break;
|
||||||
|
case width >= 992 && width < 1200:
|
||||||
|
breakPoint.value = 'md';
|
||||||
|
break;
|
||||||
|
case width >= 1200 && width < 1920:
|
||||||
|
breakPoint.value = 'lg';
|
||||||
|
break;
|
||||||
|
case width >= 1920:
|
||||||
|
breakPoint.value = 'xl';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 注入 gap 间距
|
||||||
|
provide('gap', Array.isArray(props.gap) ? props.gap[0] : props.gap);
|
||||||
|
|
||||||
|
// 注入响应式断点
|
||||||
|
let breakPoint = ref<BreakPoint>('xl');
|
||||||
|
provide('breakPoint', breakPoint);
|
||||||
|
|
||||||
|
// 注入要开始折叠的 index
|
||||||
|
const hiddenIndex = ref(-1);
|
||||||
|
provide('shouldHiddenIndex', hiddenIndex);
|
||||||
|
|
||||||
|
// 注入 cols
|
||||||
|
const gridCols = computed(() => {
|
||||||
|
if (typeof props.cols === 'object') return props.cols[breakPoint.value] ?? props.cols;
|
||||||
|
return props.cols;
|
||||||
|
});
|
||||||
|
provide('cols', gridCols);
|
||||||
|
|
||||||
|
// 寻找需要开始折叠的字段 index
|
||||||
|
const slots = useSlots().default!();
|
||||||
|
|
||||||
|
const findIndex = () => {
|
||||||
|
let fields: VNodeArrayChildren = [];
|
||||||
|
let suffix: VNode | null = null;
|
||||||
|
slots.forEach((slot: any) => {
|
||||||
|
// suffix
|
||||||
|
if (typeof slot.type === 'object' && slot.type.__name === 'GridItem' && slot.props?.suffix !== undefined) {
|
||||||
|
suffix = slot;
|
||||||
|
}
|
||||||
|
// slot children
|
||||||
|
if (typeof slot.type === 'symbol' && Array.isArray(slot.children)) {
|
||||||
|
fields.push(...slot.children);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算 suffix 所占用的列
|
||||||
|
let suffixCols = 0;
|
||||||
|
if (suffix) {
|
||||||
|
suffixCols =
|
||||||
|
((suffix as VNode).props![breakPoint.value]?.span ?? (suffix as VNode).props?.span ?? 1) +
|
||||||
|
((suffix as VNode).props![breakPoint.value]?.offset ?? (suffix as VNode).props?.offset ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let find = false;
|
||||||
|
fields.reduce((prev = 0, current, index) => {
|
||||||
|
prev +=
|
||||||
|
((current as VNode)!.props![breakPoint.value]?.span ?? (current as VNode)!.props?.span ?? 1) +
|
||||||
|
((current as VNode)!.props![breakPoint.value]?.offset ?? (current as VNode)!.props?.offset ?? 0);
|
||||||
|
if (Number(prev) > props.collapsedRows * gridCols.value - suffixCols) {
|
||||||
|
hiddenIndex.value = index;
|
||||||
|
find = true;
|
||||||
|
throw 'find it';
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, 0);
|
||||||
|
if (!find) hiddenIndex.value = -1;
|
||||||
|
} catch (e) {
|
||||||
|
// console.warn(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 断点变化时执行 findIndex
|
||||||
|
watch(
|
||||||
|
() => breakPoint.value,
|
||||||
|
() => {
|
||||||
|
if (props.collapsed) findIndex();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 监听 collapsed
|
||||||
|
watch(
|
||||||
|
() => props.collapsed,
|
||||||
|
(value) => {
|
||||||
|
if (value) return findIndex();
|
||||||
|
hiddenIndex.value = -1;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 设置间距
|
||||||
|
const gridGap = computed(() => {
|
||||||
|
if (typeof props.gap === 'number') return `${props.gap}px`;
|
||||||
|
if (Array.isArray(props.gap)) return `${props.gap[1]}px ${props.gap[0]}px`;
|
||||||
|
return 'unset';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设置 style
|
||||||
|
const style = computed(() => {
|
||||||
|
return {
|
||||||
|
display: 'grid',
|
||||||
|
gridGap: gridGap.value,
|
||||||
|
gridTemplateColumns: `repeat(${gridCols.value}, minmax(0, 1fr))`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({ breakPoint });
|
||||||
|
</script>
|
||||||
6
mayfly_go_web/src/components/Grid/interface/index.ts
Normal file
6
mayfly_go_web/src/components/Grid/interface/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export type BreakPoint = "xs" | "sm" | "md" | "lg" | "xl";
|
||||||
|
|
||||||
|
export type Responsive = {
|
||||||
|
span?: number;
|
||||||
|
offset?: number;
|
||||||
|
};
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<component
|
||||||
|
:is="item?.render ?? `el-${item.type}`"
|
||||||
|
v-bind="{ ...handleSearchProps, ...placeholder, clearable: true }"
|
||||||
|
v-model.trim="itemValue"
|
||||||
|
:data="item.type === 'tree-select' ? item.options : []"
|
||||||
|
:options="['cascader', 'select-v2'].includes(item.type!) ? item.options : []"
|
||||||
|
>
|
||||||
|
<template v-if="item.type === 'cascader'" #default="{ data }">
|
||||||
|
<span>{{ data[fieldNames.label] }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="item.type === 'select'">
|
||||||
|
<component
|
||||||
|
:is="`el-option`"
|
||||||
|
v-for="(col, index) in item.options"
|
||||||
|
:key="index"
|
||||||
|
:label="col[fieldNames.label]"
|
||||||
|
:value="col[fieldNames.value]"
|
||||||
|
></component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<slot v-else></slot>
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="SearchFormItem">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { SearchItem } from '../index';
|
||||||
|
import { useVModel } from '@vueuse/core';
|
||||||
|
|
||||||
|
interface SearchFormItemProps {
|
||||||
|
modelValue: any;
|
||||||
|
item: SearchItem;
|
||||||
|
}
|
||||||
|
const props = defineProps<SearchFormItemProps>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
const itemValue = useVModel(props, 'modelValue', emit);
|
||||||
|
|
||||||
|
// 判断 fieldNames 设置 label && value && children 的 key 值
|
||||||
|
const fieldNames = computed(() => {
|
||||||
|
return {
|
||||||
|
label: props.item?.fieldNames?.label ?? 'label',
|
||||||
|
value: props.item?.fieldNames?.value ?? 'value',
|
||||||
|
children: props.item.fieldNames?.children ?? 'children',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 接收 enumMap (el 为 select-v2 需单独处理 enumData)
|
||||||
|
// const enumMap = inject('enumMap', ref(new Map()));
|
||||||
|
// const columnEnum = computed(() => {
|
||||||
|
// let enumData = enumMap.value.get(props.item.prop);
|
||||||
|
// if (!enumData) return [];
|
||||||
|
// if (props.item?.type === 'select-v2' && props.item.fieldNames) {
|
||||||
|
// enumData = enumData.map((item: { [key: string]: any }) => {
|
||||||
|
// return { ...item, label: item[fieldNames.value.label], value: item[fieldNames.value.value] };
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// return enumData;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 处理透传的 searchProps (type 为 tree-select、cascader 的时候需要给下默认 label && value && children)
|
||||||
|
const handleSearchProps = computed(() => {
|
||||||
|
const label = fieldNames.value.label;
|
||||||
|
const value = fieldNames.value.value;
|
||||||
|
const children = fieldNames.value.children;
|
||||||
|
const searchEl = props.item?.type;
|
||||||
|
let searchProps = props.item?.props ?? {};
|
||||||
|
if (searchEl === 'tree-select') {
|
||||||
|
searchProps = { ...searchProps, props: { ...searchProps.props, label, children }, nodeKey: value };
|
||||||
|
}
|
||||||
|
if (searchEl === 'cascader') {
|
||||||
|
searchProps = { ...searchProps, props: { ...searchProps.props, label, value, children } };
|
||||||
|
}
|
||||||
|
return searchProps;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理默认 placeholder
|
||||||
|
const placeholder = computed(() => {
|
||||||
|
const search = props.item;
|
||||||
|
const label = search.label;
|
||||||
|
if (['datetimerange', 'daterange', 'monthrange'].includes(search?.props?.type) || search?.props?.isRange) {
|
||||||
|
return {
|
||||||
|
rangeSeparator: search?.props?.rangeSeparator ?? '至',
|
||||||
|
startPlaceholder: search?.props?.startPlaceholder ?? '开始时间',
|
||||||
|
endPlaceholder: search?.props?.endPlaceholder ?? '结束时间',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const placeholder = search?.props?.placeholder ?? (search?.type?.includes('input') ? `请输入${label}` : `请选择${label}`);
|
||||||
|
return { placeholder };
|
||||||
|
});
|
||||||
|
</script>
|
||||||
115
mayfly_go_web/src/components/SearchForm/index.ts
Normal file
115
mayfly_go_web/src/components/SearchForm/index.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import { VNode } from 'vue';
|
||||||
|
|
||||||
|
export type FieldNamesProps = {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
children?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SearchItemType =
|
||||||
|
| 'input'
|
||||||
|
| 'input-number'
|
||||||
|
| 'select'
|
||||||
|
| 'select-v2'
|
||||||
|
| 'tree-select'
|
||||||
|
| 'cascader'
|
||||||
|
| 'date-picker'
|
||||||
|
| 'time-picker'
|
||||||
|
| 'time-select'
|
||||||
|
| 'switch'
|
||||||
|
| 'slider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索项
|
||||||
|
*/
|
||||||
|
export class SearchItem {
|
||||||
|
/**
|
||||||
|
* 属性字段
|
||||||
|
*/
|
||||||
|
prop: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前项搜索框的 label
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单项类型,input、select、date等
|
||||||
|
*/
|
||||||
|
type: SearchItemType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select等组件的可选值
|
||||||
|
*/
|
||||||
|
options: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插槽名
|
||||||
|
*/
|
||||||
|
slot: string;
|
||||||
|
|
||||||
|
props?: any; // 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件
|
||||||
|
|
||||||
|
tooltip?: string; // 搜索提示
|
||||||
|
|
||||||
|
span?: number; // 搜索项所占用的列数,默认为 1 列
|
||||||
|
|
||||||
|
offset?: number; // 搜索字段左侧偏移列数
|
||||||
|
|
||||||
|
fieldNames: FieldNamesProps; // 指定 label && value && children 的 key 值,用于select等类型组件
|
||||||
|
|
||||||
|
render?: (scope: any) => VNode; // 自定义搜索内容渲染(tsx语法)
|
||||||
|
|
||||||
|
constructor(prop: string, label: string) {
|
||||||
|
this.prop = prop;
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
static new(prop: string, label: string): SearchItem {
|
||||||
|
return new SearchItem(prop, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static text(prop: string, label: string): SearchItem {
|
||||||
|
const tq = new SearchItem(prop, label);
|
||||||
|
tq.type = 'input';
|
||||||
|
return tq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static select(prop: string, label: string): SearchItem {
|
||||||
|
const tq = new SearchItem(prop, label);
|
||||||
|
tq.type = 'select';
|
||||||
|
return tq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static date(prop: string, label: string): SearchItem {
|
||||||
|
const tq = new SearchItem(prop, label);
|
||||||
|
tq.type = 'date-picker';
|
||||||
|
return tq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static slot(prop: string, label: string, slotName: string): SearchItem {
|
||||||
|
const tq = new SearchItem(prop, label);
|
||||||
|
tq.slot = slotName;
|
||||||
|
return tq;
|
||||||
|
}
|
||||||
|
|
||||||
|
withSpan(span: number): SearchItem {
|
||||||
|
this.span = span;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置枚举值用于选择等
|
||||||
|
* @param enumValues 枚举值对象
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
withEnum(enumValues: any): SearchItem {
|
||||||
|
this.options = Object.values(enumValues);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOptions(options: any): SearchItem {
|
||||||
|
this.options = options;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
136
mayfly_go_web/src/components/SearchForm/index.vue
Normal file
136
mayfly_go_web/src/components/SearchForm/index.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="items.length" class="search-form">
|
||||||
|
<el-form ref="formRef" :model="searchParam" label-width="auto">
|
||||||
|
<Grid ref="gridRef" :collapsed="collapsed" :gap="[20, 0]" :cols="searchCol">
|
||||||
|
<GridItem v-for="(item, index) in items" :key="item.prop" v-bind="getResponsive(item)" :index="index">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<el-space :size="4">
|
||||||
|
<span>{{ `${item?.label}` }}</span>
|
||||||
|
<el-tooltip v-if="item.tooltip" :content="item?.tooltip" placement="top">
|
||||||
|
<SvgIcon name="QuestionFilled" />
|
||||||
|
</el-tooltip>
|
||||||
|
</el-space>
|
||||||
|
<span>:</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<SearchFormItem v-if="!item.slot" :item="item" v-model="searchParam[item.prop]" />
|
||||||
|
|
||||||
|
<slot v-else :name="item.slot"></slot>
|
||||||
|
</el-form-item>
|
||||||
|
</GridItem>
|
||||||
|
<GridItem suffix>
|
||||||
|
<div class="operation">
|
||||||
|
<el-button type="primary" :icon="Search" @click="search" plain> 搜索 </el-button>
|
||||||
|
<el-button :icon="Delete" @click="reset"> 重置 </el-button>
|
||||||
|
<el-button v-if="showCollapse" type="primary" link class="search-isOpen" @click="collapsed = !collapsed">
|
||||||
|
{{ collapsed ? '展开' : '合并' }}
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<component :is="collapsed ? ArrowDown : ArrowUp"></component>
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</GridItem>
|
||||||
|
</Grid>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts" name="SearchForm">
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { BreakPoint } from '@/components/Grid/interface/index';
|
||||||
|
import { Delete, Search, ArrowDown, ArrowUp } from '@element-plus/icons-vue';
|
||||||
|
import SearchFormItem from './components/SearchFormItem.vue';
|
||||||
|
import Grid from '@/components/Grid/index.vue';
|
||||||
|
import GridItem from '@/components/Grid/components/GridItem.vue';
|
||||||
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
|
import { SearchItem } from './index';
|
||||||
|
import { useVModel } from '@vueuse/core';
|
||||||
|
|
||||||
|
interface ProTableProps {
|
||||||
|
items: SearchItem[]; // 搜索配置项
|
||||||
|
modelValue?: { [key: string]: any }; // 搜索参数
|
||||||
|
searchCol: number | Record<BreakPoint, number>;
|
||||||
|
search: (params: any) => void; // 搜索方法
|
||||||
|
reset: (params: any) => void; // 重置方法
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认值
|
||||||
|
const props = withDefaults(defineProps<ProTableProps>(), {
|
||||||
|
items: () => [],
|
||||||
|
modelValue: () => ({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
const searchParam = useVModel(props, 'modelValue', emit);
|
||||||
|
|
||||||
|
// 获取响应式设置
|
||||||
|
const getResponsive = (item: SearchItem) => {
|
||||||
|
return {
|
||||||
|
span: item?.span,
|
||||||
|
offset: item.offset ?? 0,
|
||||||
|
// xs: item.search?.xs,
|
||||||
|
// sm: item.search?.sm,
|
||||||
|
// md: item.search?.md,
|
||||||
|
// lg: item.search?.lg,
|
||||||
|
// xl: item.search?.xl,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 是否默认折叠搜索项
|
||||||
|
const collapsed = ref(true);
|
||||||
|
|
||||||
|
// 获取响应式断点
|
||||||
|
const gridRef = ref();
|
||||||
|
const breakPoint = computed<BreakPoint>(() => gridRef.value?.breakPoint);
|
||||||
|
|
||||||
|
// 判断是否显示 展开/合并 按钮
|
||||||
|
const showCollapse = computed(() => {
|
||||||
|
let show = false;
|
||||||
|
props.items.reduce((prev, current) => {
|
||||||
|
prev += (current![breakPoint.value]?.span ?? current?.span ?? 1) + (current![breakPoint.value]?.offset ?? current?.offset ?? 0);
|
||||||
|
if (typeof props.searchCol !== 'number') {
|
||||||
|
if (prev >= props.searchCol[breakPoint.value]) show = true;
|
||||||
|
} else {
|
||||||
|
if (prev >= props.searchCol) show = true;
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, 0);
|
||||||
|
return show;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.search-form {
|
||||||
|
padding: 18px 18px 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-x: hidden;
|
||||||
|
background-color: var(--el-bg-color);
|
||||||
|
border: 1px solid var(--el-border-color-light);
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||||
|
|
||||||
|
.el-form {
|
||||||
|
.el-form-item__content > * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去除时间选择器上下 padding
|
||||||
|
.el-range-editor.el-input__wrapper {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 18px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,170 +1,112 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-table">
|
<div>
|
||||||
<!--
|
<!-- 查询表单 -->
|
||||||
实现:通过我们配置好的 查询条件
|
<SearchForm v-show="isShowSearch" :items="searchItems" v-model="queryForm_" :search="queryData" :reset="reset" :search-col="searchCol">
|
||||||
首先去创建form表单,根据我们配置的查询条件去做一个循环判断,展示出不用类型所对应不同的输入框
|
<!-- 遍历父组件传入的 solts 透传给子组件 -->
|
||||||
比如:text对应普通的输入框,select对应下拉选择,dateTime对应日期时间选择器
|
<template v-for="(_, key) in useSlots()" v-slot:[key]>
|
||||||
在使用时,父组件会传来一个queryForm空的对象,
|
<slot :name="key"></slot>
|
||||||
循环出来的输入框会绑定表格配置中的prop字段绑定在queryForm对象中
|
</template>
|
||||||
-->
|
</SearchForm>
|
||||||
|
|
||||||
<el-card>
|
<el-card>
|
||||||
<div class="query" ref="queryRef">
|
<div class="table-main">
|
||||||
<div>
|
<!-- 表格头部 操作按钮 -->
|
||||||
<div v-if="props.query.length > 0">
|
<div class="table-header">
|
||||||
<el-form :model="queryForm_" label-width="auto" :size="props.size">
|
<div class="header-button-lf">
|
||||||
<el-row
|
<slot name="tableHeader" />
|
||||||
v-for="i in Math.ceil((props.query.length + 1) / (defaultQueryCount + 1))"
|
</div>
|
||||||
:key="i"
|
|
||||||
v-show="i == 1 || isOpenMoreQuery"
|
<div v-if="toolButton" class="header-button-ri">
|
||||||
:class="i > 1 && isOpenMoreQuery ? 'is-open' : ''"
|
<slot name="toolButton">
|
||||||
|
<el-button v-if="showToolButton('refresh')" icon="Refresh" circle @click="execQuery()" />
|
||||||
|
|
||||||
|
<el-button v-if="showToolButton('search') && searchItems?.length" icon="Search" circle @click="isShowSearch = !isShowSearch" />
|
||||||
|
|
||||||
|
<el-popover
|
||||||
|
placement="bottom"
|
||||||
|
title="表格配置"
|
||||||
|
popper-style="max-height: 550px; overflow: auto; max-width: 450px"
|
||||||
|
width="auto"
|
||||||
|
trigger="click"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<div v-for="(item, index) in tableColumns" :key="index">
|
||||||
:label="item.label"
|
<el-checkbox v-model="item.show" :label="item.label" :true-label="true" :false-label="false" />
|
||||||
style="margin-right: 12px; margin-bottom: 0px"
|
</div>
|
||||||
v-for="item in getRowQueryItem(i)"
|
<template #reference>
|
||||||
:key="item.prop"
|
<el-button icon="Operation" circle :size="props.size"></el-button>
|
||||||
>
|
</template>
|
||||||
<!-- 这里只获取指定个数的筛选条件 -->
|
</el-popover>
|
||||||
<el-input
|
</slot>
|
||||||
v-model="queryForm_[item.prop]"
|
|
||||||
:placeholder="'输入' + item.label + '关键字'"
|
|
||||||
clearable
|
|
||||||
v-if="item.type == 'text'"
|
|
||||||
></el-input>
|
|
||||||
|
|
||||||
<el-select-v2
|
|
||||||
v-model="queryForm_[item.prop]"
|
|
||||||
:options="item.options"
|
|
||||||
clearable
|
|
||||||
:placeholder="'选择' + item.label + '关键字'"
|
|
||||||
v-else-if="item.type == 'select'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<el-date-picker
|
|
||||||
v-model="queryForm_[item.prop]"
|
|
||||||
clearable
|
|
||||||
type="datetimerange"
|
|
||||||
format="YYYY-MM-DD hh:mm:ss"
|
|
||||||
value-format="x"
|
|
||||||
range-separator="至"
|
|
||||||
start-placeholder="开始时间"
|
|
||||||
end-placeholder="结束时间"
|
|
||||||
v-else-if="item.type == 'date'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template v-else-if="item.slot == 'queryBtns'">
|
|
||||||
<template v-if="props.query?.length > defaultQueryCount">
|
|
||||||
<el-button
|
|
||||||
@click="isOpenMoreQuery = !isOpenMoreQuery"
|
|
||||||
v-if="!isOpenMoreQuery"
|
|
||||||
icon="ArrowDownBold"
|
|
||||||
circle
|
|
||||||
></el-button>
|
|
||||||
<el-button @click="isOpenMoreQuery = !isOpenMoreQuery" v-else icon="ArrowUpBold" circle></el-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-button @click="queryData()" type="primary" icon="search" plain>查询</el-button>
|
|
||||||
<el-button @click="reset()" icon="RefreshRight">重置</el-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<slot :name="item.slot"></slot>
|
|
||||||
</el-form-item>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="slot">
|
<el-table
|
||||||
<!-- 查询栏右侧slot插槽(用来添加表格其他操作,比如,新增数据,删除数据等其他操作) -->
|
v-bind="$attrs"
|
||||||
<slot name="queryRight"></slot>
|
:max-height="tableMaxHeight"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
:data="state.data"
|
||||||
|
highlight-current-row
|
||||||
|
v-loading="state.loading"
|
||||||
|
:size="props.size"
|
||||||
|
:border="border"
|
||||||
|
>
|
||||||
|
<el-table-column v-if="props.showSelection" type="selection" width="40" />
|
||||||
|
|
||||||
<!--
|
<template v-for="(item, index) in tableColumns">
|
||||||
动态表头显示,根据表格每条配置项中的show字段来决定改列是否显示或者隐藏
|
<el-table-column
|
||||||
columns 就是我们表格配置的数组对象
|
:key="index"
|
||||||
-->
|
v-if="item.show"
|
||||||
<el-popover
|
:prop="item.prop"
|
||||||
placement="bottom"
|
:label="item.label"
|
||||||
title="表格配置"
|
:fixed="item.fixed"
|
||||||
popper-style="max-height: 550px; overflow: auto; max-width: 450px"
|
:align="item.align"
|
||||||
width="auto"
|
:show-overflow-tooltip="item.showOverflowTooltip"
|
||||||
trigger="click"
|
:min-width="item.minWidth"
|
||||||
>
|
:sortable="item.sortable || false"
|
||||||
<div v-for="(item, index) in props.columns" :key="index">
|
:type="item.type"
|
||||||
<el-checkbox v-model="item.show" :label="item.label" :true-label="true" :false-label="false" />
|
:width="item.width"
|
||||||
</div>
|
>
|
||||||
<template #reference>
|
<!-- 插槽:预留功能 -->
|
||||||
<!-- 一个Element Plus中的图标 -->
|
<template #default="scope" v-if="item.slot">
|
||||||
<el-button icon="Operation" :size="props.size"></el-button>
|
<slot :name="item.prop" :data="scope.row"></slot>
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
|
||||||
</div>
|
<!-- 枚举类型使用tab展示 -->
|
||||||
|
<template #default="scope" v-else-if="item.type == 'tag'">
|
||||||
|
<enum-tag :size="props.size" :enums="item.typeParam" :value="scope.row[item.prop]"></enum-tag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default="scope" v-else>
|
||||||
|
<!-- 配置了美化文本按钮以及文本内容大于指定长度,则显示美化按钮 -->
|
||||||
|
<el-popover
|
||||||
|
v-if="item.isBeautify && scope.row[item.prop]?.length > 35"
|
||||||
|
effect="light"
|
||||||
|
trigger="click"
|
||||||
|
placement="top"
|
||||||
|
width="600px"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<el-input :autosize="{ minRows: 3, maxRows: 15 }" disabled v-model="formatVal" type="textarea" />
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<el-link
|
||||||
|
@click="formatText(scope.row[item.prop])"
|
||||||
|
:underline="false"
|
||||||
|
type="success"
|
||||||
|
icon="MagicStick"
|
||||||
|
class="mr5"
|
||||||
|
></el-link>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
|
||||||
|
<span>{{ item.getValueByData(scope.row) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table
|
<el-row class="mt20" type="flex" justify="end">
|
||||||
v-bind="$attrs"
|
|
||||||
:max-height="tableMaxHeight"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
:data="state.data"
|
|
||||||
highlight-current-row
|
|
||||||
v-loading="state.loading"
|
|
||||||
:size="props.size"
|
|
||||||
>
|
|
||||||
<el-table-column v-if="props.showSelection" type="selection" width="40" />
|
|
||||||
|
|
||||||
<template v-for="(item, index) in columns">
|
|
||||||
<el-table-column
|
|
||||||
:key="index"
|
|
||||||
v-if="item.show"
|
|
||||||
:prop="item.prop"
|
|
||||||
:label="item.label"
|
|
||||||
:fixed="item.fixed"
|
|
||||||
:align="item.align"
|
|
||||||
:show-overflow-tooltip="item.showOverflowTooltip"
|
|
||||||
:min-width="item.minWidth"
|
|
||||||
:sortable="item.sortable || false"
|
|
||||||
:type="item.type"
|
|
||||||
:width="item.width"
|
|
||||||
>
|
|
||||||
<!-- 插槽:预留功能 -->
|
|
||||||
<template #default="scope" v-if="item.slot">
|
|
||||||
<slot :name="item.prop" :data="scope.row"></slot>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 枚举类型使用tab展示 -->
|
|
||||||
<template #default="scope" v-else-if="item.type == 'tag'">
|
|
||||||
<enum-tag :size="props.size" :enums="item.typeParam" :value="scope.row[item.prop]"></enum-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="scope" v-else>
|
|
||||||
<!-- 配置了美化文本按钮以及文本内容大于指定长度,则显示美化按钮 -->
|
|
||||||
<el-popover
|
|
||||||
v-if="item.isBeautify && scope.row[item.prop]?.length > 35"
|
|
||||||
effect="light"
|
|
||||||
trigger="click"
|
|
||||||
placement="top"
|
|
||||||
width="600px"
|
|
||||||
>
|
|
||||||
<template #default>
|
|
||||||
<el-input :autosize="{ minRows: 3, maxRows: 15 }" disabled v-model="formatVal" type="textarea" />
|
|
||||||
</template>
|
|
||||||
<template #reference>
|
|
||||||
<el-link
|
|
||||||
@click="formatText(scope.row[item.prop])"
|
|
||||||
:underline="false"
|
|
||||||
type="success"
|
|
||||||
icon="MagicStick"
|
|
||||||
class="mr5"
|
|
||||||
></el-link>
|
|
||||||
</template>
|
|
||||||
</el-popover>
|
|
||||||
|
|
||||||
<span>{{ item.getValueByData(scope.row) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</template>
|
|
||||||
</el-table>
|
|
||||||
|
|
||||||
<el-row style="margin-top: 20px" type="flex" justify="end">
|
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:small="props.size == 'small'"
|
:small="props.size == 'small'"
|
||||||
@current-change="handlePageChange"
|
@current-change="handlePageChange"
|
||||||
@@ -182,79 +124,55 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { toRefs, watch, reactive, onMounted, Ref } from 'vue';
|
import { toRefs, watch, reactive, onMounted, Ref, ref, useSlots } from 'vue';
|
||||||
import { TableColumn, TableQuery } from './index';
|
import { TableColumn } from './index';
|
||||||
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||||
import { useThemeConfig } from '@/store/themeConfig';
|
import { useThemeConfig } from '@/store/themeConfig';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel, useEventListener } from '@vueuse/core';
|
||||||
import Api from '@/common/Api';
|
import Api from '@/common/Api';
|
||||||
|
import SearchForm from '@/components/SearchForm/index.vue';
|
||||||
|
import { SearchItem } from '../SearchForm/index';
|
||||||
|
|
||||||
const emit = defineEmits(['update:queryForm', 'update:pageNum', 'update:pageSize', 'update:selectionData', 'pageChange']);
|
const emit = defineEmits(['update:queryForm', 'update:selectionData', 'pageChange']);
|
||||||
|
|
||||||
const props = defineProps({
|
export interface PageTableProps {
|
||||||
size: {
|
size?: string;
|
||||||
type: String,
|
showSelection?: boolean;
|
||||||
default: '',
|
showSearch?: boolean; // 是否显示搜索表单
|
||||||
},
|
columns: TableColumn[]; // 列配置项 ==> 必传
|
||||||
inputWidth: {
|
data?: any[]; // 静态 table data 数据,若存在则不会使用 requestApi 返回的 data ==> 非必传
|
||||||
type: [Number, String],
|
pageApi: Api; // 请求表格数据的 api
|
||||||
default: '200px',
|
lazy?: boolean; // 是否自动执行请求 api ==> 非必传(默认为false)
|
||||||
},
|
beforeQueryFn?: (params: any) => any; // 执行查询时对查询参数进行处理,调整等
|
||||||
// 是否显示选择列
|
dataHandlerFn?: (data: any) => any; // 数据处理回调函数,用于将请求回来的数据二次加工处理等
|
||||||
showSelection: {
|
searchItems?: SearchItem[];
|
||||||
type: Boolean,
|
queryForm?: any; // 查询表单参数 ==> 非必传(默认为{pageNum:1, pageSize: 10})
|
||||||
default: false,
|
border?: boolean; // 是否带有纵向边框 ==> 非必传(默认为false)
|
||||||
},
|
toolButton?: ('refresh' | 'setting' | 'search')[] | boolean; // 是否显示表格功能按钮 ==> 非必传(默认为true)
|
||||||
// 当前选择的数据
|
searchCol?: any; // 表格搜索项 每列占比配置 ==> 非必传 { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }
|
||||||
selectionData: {
|
}
|
||||||
type: Array<any>,
|
|
||||||
},
|
// 接受父组件参数,配置默认值
|
||||||
// 列信息
|
const props = withDefaults(defineProps<PageTableProps>(), {
|
||||||
columns: {
|
columns: () => [],
|
||||||
type: Array<TableColumn>,
|
showSelection: false,
|
||||||
default: function () {
|
lazy: false,
|
||||||
return [];
|
initParam: {},
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
// 调用分页数据的api
|
|
||||||
pageApi: {
|
|
||||||
type: Api,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
// 懒加载,即需要手动调用search方法才可调接口获取数据,不会在mounted的时候调用。
|
|
||||||
lazy: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
// 执行查询时对查询参数进行处理,调整等
|
|
||||||
beforeQueryFn: {
|
|
||||||
type: Function,
|
|
||||||
},
|
|
||||||
// 数据处理回调函数,用于将请求回来的数据二次加工处理等
|
|
||||||
dataHandlerFn: {
|
|
||||||
type: Function,
|
|
||||||
},
|
|
||||||
// 查询条件配置
|
|
||||||
query: {
|
|
||||||
type: Array<TableQuery>,
|
|
||||||
default: function () {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 绑定的查询表单
|
|
||||||
queryForm: {
|
queryForm: {
|
||||||
type: Object,
|
pageNum: 1,
|
||||||
default: function () {
|
pageSize: 0,
|
||||||
return {
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
border: false,
|
||||||
|
toolButton: true,
|
||||||
|
showSearch: false,
|
||||||
|
searchItems: () => [],
|
||||||
|
searchCol: () => ({ xs: 1, sm: 3, md: 3, lg: 4, xl: 4 }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 接收 columns 并设置为响应式
|
||||||
|
const tableColumns = reactive<TableColumn[]>(props.columns);
|
||||||
|
|
||||||
const { themeConfig } = storeToRefs(useThemeConfig());
|
const { themeConfig } = storeToRefs(useThemeConfig());
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -267,10 +185,18 @@ const state = reactive({
|
|||||||
// 输入框宽度
|
// 输入框宽度
|
||||||
inputWidth_: '200px' as any,
|
inputWidth_: '200px' as any,
|
||||||
formatVal: '', // 格式化后的值
|
formatVal: '', // 格式化后的值
|
||||||
tableMaxHeight: window.innerHeight - 240 + 'px',
|
tableMaxHeight: '500px',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { pageSizes, isOpenMoreQuery, defaultQueryCount, inputWidth_, formatVal, tableMaxHeight } = toRefs(state);
|
// 是否显示搜索模块
|
||||||
|
const isShowSearch = ref(props.showSearch);
|
||||||
|
|
||||||
|
// 控制 ToolButton 显示
|
||||||
|
const showToolButton = (key: 'refresh' | 'setting' | 'search') => {
|
||||||
|
return Array.isArray(props.toolButton) ? props.toolButton.includes(key) : props.toolButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { pageSizes, formatVal, tableMaxHeight } = toRefs(state);
|
||||||
|
|
||||||
const queryForm_: Ref<any> = useVModel(props, 'queryForm', emit);
|
const queryForm_: Ref<any> = useVModel(props, 'queryForm', emit);
|
||||||
|
|
||||||
@@ -287,9 +213,19 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(async () => {
|
watch(
|
||||||
let pageSize = queryForm_.value.pageSize;
|
() => isShowSearch.value,
|
||||||
|
() => {
|
||||||
|
console.log('watch show sa');
|
||||||
|
calcuTableHeight();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
calcuTableHeight();
|
||||||
|
useEventListener(window, 'resize', calcuTableHeight);
|
||||||
|
|
||||||
|
let pageSize = queryForm_.value.pageSize;
|
||||||
// 如果pageSize设为0,则使用系统全局配置的pageSize
|
// 如果pageSize设为0,则使用系统全局配置的pageSize
|
||||||
if (!pageSize) {
|
if (!pageSize) {
|
||||||
pageSize = themeConfig.value.defaultListPageSize;
|
pageSize = themeConfig.value.defaultListPageSize;
|
||||||
@@ -303,24 +239,14 @@ onMounted(async () => {
|
|||||||
queryForm_.value.pageSize = pageSize;
|
queryForm_.value.pageSize = pageSize;
|
||||||
state.pageSizes = [pageSize, pageSize * 2, pageSize * 3, pageSize * 4, pageSize * 5];
|
state.pageSizes = [pageSize, pageSize * 2, pageSize * 3, pageSize * 4, pageSize * 5];
|
||||||
|
|
||||||
// 如果没传输入框宽度,则根据组件size设置默认宽度
|
|
||||||
if (!props.inputWidth) {
|
|
||||||
state.inputWidth_ = props.size == 'small' ? '150px' : '200px';
|
|
||||||
} else {
|
|
||||||
state.inputWidth_ = props.inputWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
calcuTableHeight();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!props.lazy) {
|
if (!props.lazy) {
|
||||||
await reqPageApi();
|
await reqPageApi();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const calcuTableHeight = () => {
|
const calcuTableHeight = () => {
|
||||||
state.tableMaxHeight = window.innerHeight - 240 + 'px';
|
const headerHeight = isShowSearch.value ? 320 : 240;
|
||||||
|
state.tableMaxHeight = window.innerHeight - headerHeight + 'px';
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatText = (data: any) => {
|
const formatText = (data: any) => {
|
||||||
@@ -332,18 +258,6 @@ const formatText = (data: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRowQueryItem = (row: number) => {
|
|
||||||
// 第一行需要加个查询等按钮列
|
|
||||||
if (row === 1) {
|
|
||||||
const res = props.query.slice(row - 1, defaultQueryCount.value);
|
|
||||||
// 查询等按钮列
|
|
||||||
res.push(TableQuery.slot('', '', 'queryBtns'));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
const columnCount = defaultQueryCount.value + 1;
|
|
||||||
return props.query.slice((row - 1) * columnCount - 1, row * columnCount - 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSelectionChange = (val: any) => {
|
const handleSelectionChange = (val: any) => {
|
||||||
emit('update:selectionData', val);
|
emit('update:selectionData', val);
|
||||||
};
|
};
|
||||||
@@ -390,7 +304,7 @@ const queryData = () => {
|
|||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
// 将查询参数绑定的值置空,并重新粗发查询接口
|
// 将查询参数绑定的值置空,并重新粗发查询接口
|
||||||
for (let qi of props.query) {
|
for (let qi of props.searchItems) {
|
||||||
queryForm_.value[qi.prop] = null;
|
queryForm_.value[qi.prop] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,49 +325,88 @@ defineExpose({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.page-table {
|
.table-box,
|
||||||
.query {
|
.table-main {
|
||||||
margin-bottom: 10px;
|
display: flex;
|
||||||
overflow: hidden;
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
.is-open {
|
// 表格 header 样式
|
||||||
// padding: 10px 0;
|
.table-header {
|
||||||
max-height: 200px;
|
width: 100%;
|
||||||
margin-top: 10px;
|
.header-button-lf {
|
||||||
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
display: flex;
|
.header-button-ri {
|
||||||
align-items: flex-start;
|
float: right;
|
||||||
justify-content: space-between;
|
}
|
||||||
|
|
||||||
.slot {
|
.el-button {
|
||||||
display: flex;
|
margin-bottom: 10px;
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
// el-table 表格样式
|
||||||
margin-top: 10px;
|
.el-table {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
// 修复 safari 浏览器表格错位 https://github.com/HalseySpicy/Geeker-Admin/issues/83
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .el-table__header th {
|
||||||
|
// height: 45px;
|
||||||
|
// font-size: 15px;
|
||||||
|
// font-weight: bold;
|
||||||
|
// color: var(--el-text-color-primary);
|
||||||
|
// background: var(--el-fill-color-light);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .el-table__row {
|
||||||
|
// height: 45px;
|
||||||
|
// font-size: 14px;
|
||||||
|
|
||||||
|
// .move {
|
||||||
|
// cursor: move;
|
||||||
|
|
||||||
|
// .el-icon {
|
||||||
|
// cursor: move;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 设置 el-table 中 header 文字不换行,并省略
|
||||||
|
.el-table__header .el-table__cell > .cell {
|
||||||
|
// white-space: nowrap;
|
||||||
|
white-space: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解决表格数据为空时样式不居中问题(仅在element-plus中)
|
||||||
|
// .el-table__empty-block {
|
||||||
|
// position: absolute;
|
||||||
|
// top: 50%;
|
||||||
|
// left: 50%;
|
||||||
|
// transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
// .table-empty {
|
||||||
|
// line-height: 30px;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// table 中 image 图片样式
|
||||||
|
.table-image {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep(.el-form-item__label) {
|
::v-deep(.el-form-item__label) {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select-v2 {
|
|
||||||
width: v-bind(inputWidth_);
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-input {
|
|
||||||
width: v-bind(inputWidth_);
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-select {
|
|
||||||
width: v-bind(inputWidth_);
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-date-editor {
|
|
||||||
width: 380px !important;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -242,68 +242,3 @@ export class TableColumn {
|
|||||||
this.minWidth = (flexWidth > 400 ? 400 : flexWidth) + this.addWidth;
|
this.minWidth = (flexWidth > 400 ? 400 : flexWidth) + this.addWidth;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableQuery {
|
|
||||||
/**
|
|
||||||
* 属性字段
|
|
||||||
*/
|
|
||||||
prop: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示表头
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询类型,text、select、date
|
|
||||||
*/
|
|
||||||
type: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* select可选值
|
|
||||||
*/
|
|
||||||
options: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插槽名
|
|
||||||
*/
|
|
||||||
slot: string;
|
|
||||||
|
|
||||||
constructor(prop: string, label: string) {
|
|
||||||
this.prop = prop;
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
static new(prop: string, label: string): TableQuery {
|
|
||||||
return new TableQuery(prop, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
static text(prop: string, label: string): TableQuery {
|
|
||||||
const tq = new TableQuery(prop, label);
|
|
||||||
tq.type = 'text';
|
|
||||||
return tq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static select(prop: string, label: string): TableQuery {
|
|
||||||
const tq = new TableQuery(prop, label);
|
|
||||||
tq.type = 'select';
|
|
||||||
return tq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static date(prop: string, label: string): TableQuery {
|
|
||||||
const tq = new TableQuery(prop, label);
|
|
||||||
tq.type = 'date';
|
|
||||||
return tq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static slot(prop: string, label: string, slotName: string): TableQuery {
|
|
||||||
const tq = new TableQuery(prop, label);
|
|
||||||
tq.slot = slotName;
|
|
||||||
return tq;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptions(options: any): TableQuery {
|
|
||||||
this.options = options;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
|
|
||||||
/** 全局设置 */
|
/** 全局设置 */
|
||||||
// 默认列表页的分页大小
|
// 默认列表页的分页大小
|
||||||
defaultListPageSize: 15,
|
defaultListPageSize: 10,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -4,28 +4,20 @@
|
|||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="dbApi.dbs"
|
:page-api="dbApi.dbs"
|
||||||
:before-query-fn="checkRouteTagPath"
|
:before-query-fn="checkRouteTagPath"
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="state.selectionData"
|
v-model:selection-data="state.selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" filterable clearable style="width: 200px">
|
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" filterable clearable>
|
||||||
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #instanceSelect>
|
<template #instanceSelect>
|
||||||
<el-select
|
<el-select remote :remote-method="getInstances" v-model="query.instanceId" placeholder="输入并选择实例" filterable clearable>
|
||||||
remote
|
|
||||||
:remote-method="getInstances"
|
|
||||||
v-model="query.instanceId"
|
|
||||||
placeholder="输入并选择实例"
|
|
||||||
filterable
|
|
||||||
clearable
|
|
||||||
style="width: 200px"
|
|
||||||
>
|
|
||||||
<el-option v-for="item in state.instances" :key="item.id" :label="`${item.name}`" :value="item.id">
|
<el-option v-for="item in state.instances" :key="item.id" :label="`${item.name}`" :value="item.id">
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
@@ -37,7 +29,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.saveDb" type="primary" icon="plus" @click="editDb(false)">添加</el-button>
|
<el-button v-auth="perms.saveDb" type="primary" icon="plus" @click="editDb(false)">添加</el-button>
|
||||||
<el-button v-auth="perms.delDb" :disabled="selectionData.length < 1" @click="deleteDb()" type="danger" icon="delete">删除</el-button>
|
<el-button v-auth="perms.delDb" :disabled="selectionData.length < 1" @click="deleteDb()" type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -170,7 +162,7 @@ import { isTrue } from '@/common/assert';
|
|||||||
import { dateFormat } from '@/common/utils/date';
|
import { dateFormat } from '@/common/utils/date';
|
||||||
import ResourceTag from '../component/ResourceTag.vue';
|
import ResourceTag from '../component/ResourceTag.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
import DbSqlExecLog from './DbSqlExecLog.vue';
|
import DbSqlExecLog from './DbSqlExecLog.vue';
|
||||||
import { DbType } from './dialect';
|
import { DbType } from './dialect';
|
||||||
@@ -178,6 +170,7 @@ import { tagApi } from '../tag/api';
|
|||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { getDbDialect } from './dialect/index';
|
import { getDbDialect } from './dialect/index';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
||||||
|
|
||||||
@@ -187,7 +180,7 @@ const perms = {
|
|||||||
delDb: 'db:del',
|
delDb: 'db:del',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect'), TableQuery.slot('instanceId', '实例', 'instanceSelect')];
|
const searchItems = [SearchItem.slot('tagPath', '标签', 'tagPathSelect'), SearchItem.slot('instanceId', '实例', 'instanceSelect')];
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('instanceName', '实例名'),
|
TableColumn.new('instanceName', '实例名'),
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
:page-api="dbApi.getSqlExecs"
|
:page-api="dbApi.getSqlExecs"
|
||||||
:lazy="true"
|
:lazy="true"
|
||||||
height="100%"
|
height="100%"
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #dbSelect>
|
<template #dbSelect>
|
||||||
<el-select v-model="query.db" placeholder="请选择数据库" style="width: 200px" filterable clearable>
|
<el-select v-model="query.db" placeholder="请选择数据库" filterable clearable>
|
||||||
<el-option v-for="item in dbs" :key="item" :label="`${item}`" :value="item"> </el-option>
|
<el-option v-for="item in dbs" :key="item" :label="`${item}`" :value="item"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
@@ -40,7 +40,8 @@ import { toRefs, watch, reactive, onMounted, Ref, ref } from 'vue';
|
|||||||
import { dbApi } from './api';
|
import { dbApi } from './api';
|
||||||
import { DbSqlExecTypeEnum } from './enums';
|
import { DbSqlExecTypeEnum } from './enums';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dbId: {
|
dbId: {
|
||||||
@@ -53,13 +54,13 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const queryConfig = [
|
const searchItems = [
|
||||||
TableQuery.slot('db', '数据库', 'dbSelect'),
|
SearchItem.slot('db', '数据库', 'dbSelect'),
|
||||||
TableQuery.text('table', '表名'),
|
SearchItem.text('table', '表名'),
|
||||||
TableQuery.select('type', '操作类型').setOptions(Object.values(DbSqlExecTypeEnum)),
|
SearchItem.select('type', '操作类型').withEnum(DbSqlExecTypeEnum),
|
||||||
];
|
];
|
||||||
|
|
||||||
const columns = [
|
const columns = ref([
|
||||||
TableColumn.new('db', '数据库'),
|
TableColumn.new('db', '数据库'),
|
||||||
TableColumn.new('table', '表'),
|
TableColumn.new('table', '表'),
|
||||||
TableColumn.new('type', '类型').typeTag(DbSqlExecTypeEnum).setAddWidth(10),
|
TableColumn.new('type', '类型').typeTag(DbSqlExecTypeEnum).setAddWidth(10),
|
||||||
@@ -69,7 +70,7 @@ const columns = [
|
|||||||
TableColumn.new('createTime', '执行时间').isTime(),
|
TableColumn.new('createTime', '执行时间').isTime(),
|
||||||
TableColumn.new('remark', '备注'),
|
TableColumn.new('remark', '备注'),
|
||||||
TableColumn.new('action', '操作').isSlot().setMinWidth(90).fixedRight().alignCenter(),
|
TableColumn.new('action', '操作').isSlot().setMinWidth(90).fixedRight().alignCenter(),
|
||||||
];
|
]);
|
||||||
|
|
||||||
const pageTableRef: Ref<any> = ref(null);
|
const pageTableRef: Ref<any> = ref(null);
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
<page-table
|
<page-table
|
||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="dbApi.instances"
|
:page-api="dbApi.instances"
|
||||||
:query="queryConfig"
|
:searchItems="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="state.selectionData"
|
v-model:selection-data="state.selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.saveInstance" type="primary" icon="plus" @click="editInstance(false)">添加</el-button>
|
<el-button v-auth="perms.saveInstance" type="primary" icon="plus" @click="editInstance(false)">添加</el-button>
|
||||||
<el-button v-auth="perms.delInstance" :disabled="selectionData.length < 1" @click="deleteInstance()" type="danger" icon="delete"
|
<el-button v-auth="perms.delInstance" :disabled="selectionData.length < 1" @click="deleteInstance()" type="danger" icon="delete"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
@@ -66,10 +66,11 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
|||||||
import { dbApi } from './api';
|
import { dbApi } from './api';
|
||||||
import { dateFormat } from '@/common/utils/date';
|
import { dateFormat } from '@/common/utils/date';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
import { getDbDialect } from './dialect';
|
import { getDbDialect } from './dialect';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const InstanceEdit = defineAsyncComponent(() => import('./InstanceEdit.vue'));
|
const InstanceEdit = defineAsyncComponent(() => import('./InstanceEdit.vue'));
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ const perms = {
|
|||||||
delInstance: 'db:instance:del',
|
delInstance: 'db:instance:del',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryConfig = [TableQuery.text('name', '名称')];
|
const searchItems = [SearchItem.text('name', '名称')];
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
|
|||||||
@@ -4,19 +4,19 @@
|
|||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="machineApi.list"
|
:page-api="machineApi.list"
|
||||||
:before-query-fn="checkRouteTagPath"
|
:before-query-fn="checkRouteTagPath"
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="params"
|
v-model:query-form="params"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="state.selectionData"
|
v-model:selection-data="state.selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
<el-select @focus="getTags" v-model="params.tagPath" placeholder="请选择标签" @clear="search" filterable clearable style="width: 200px">
|
<el-select @focus="getTags" v-model="params.tagPath" placeholder="请选择标签" @clear="search" filterable clearable>
|
||||||
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
<el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
||||||
<el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete">删除</el-button>
|
<el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -190,11 +190,12 @@ import { machineApi, getMachineTerminalSocketUrl } from './api';
|
|||||||
import { dateFormat } from '@/common/utils/date';
|
import { dateFormat } from '@/common/utils/date';
|
||||||
import ResourceTag from '../component/ResourceTag.vue';
|
import ResourceTag from '../component/ResourceTag.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
import { formatByteSize } from '@/common/utils/format';
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
import { tagApi } from '../tag/api';
|
import { tagApi } from '../tag/api';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
|
const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
|
||||||
@@ -218,9 +219,9 @@ const perms = {
|
|||||||
closeCli: 'machine:close-cli',
|
closeCli: 'machine:close-cli',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect'), TableQuery.text('ip', 'IP'), TableQuery.text('name', '名称')];
|
const searchItems = [SearchItem.slot('tagPath', '标签', 'tagPathSelect'), SearchItem.text('ip', 'IP'), SearchItem.text('name', '名称')];
|
||||||
|
|
||||||
const columns = ref([
|
const columns = [
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
TableColumn.new('ipPort', 'ip:port').isSlot().setAddWidth(50),
|
TableColumn.new('ipPort', 'ip:port').isSlot().setAddWidth(50),
|
||||||
TableColumn.new('stat', '运行状态').isSlot().setAddWidth(50),
|
TableColumn.new('stat', '运行状态').isSlot().setAddWidth(50),
|
||||||
@@ -230,7 +231,7 @@ const columns = ref([
|
|||||||
TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(10).alignCenter(),
|
TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(10).alignCenter(),
|
||||||
TableColumn.new('remark', '备注'),
|
TableColumn.new('remark', '备注'),
|
||||||
TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
|
TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
|
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
|
||||||
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
|
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
:page-api="machineApi.scripts"
|
:page-api="machineApi.scripts"
|
||||||
:before-query-fn="checkScriptType"
|
:before-query-fn="checkScriptType"
|
||||||
:lazy="true"
|
:lazy="true"
|
||||||
:query="queryConfig"
|
:search-items="state.searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="'machine:script:save'" type="primary" @click="editScript(null)" icon="plus" plain>添加</el-button>
|
<el-button v-auth="'machine:script:save'" type="primary" @click="editScript(null)" icon="plus" plain>添加</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-auth="'machine:script:del'"
|
v-auth="'machine:script:del'"
|
||||||
@@ -93,8 +93,9 @@ import { getMachineTerminalSocketUrl, machineApi } from './api';
|
|||||||
import { ScriptResultEnum, ScriptTypeEnum } from './enums';
|
import { ScriptResultEnum, ScriptTypeEnum } from './enums';
|
||||||
import ScriptEdit from './ScriptEdit.vue';
|
import ScriptEdit from './ScriptEdit.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { DynamicFormDialog } from '@/components/dynamic-form';
|
import { DynamicFormDialog } from '@/components/dynamic-form';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: { type: Boolean },
|
visible: { type: Boolean },
|
||||||
@@ -110,7 +111,7 @@ const pageTableRef: Ref<any> = ref(null);
|
|||||||
const state = reactive({
|
const state = reactive({
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
selectionData: [],
|
selectionData: [],
|
||||||
queryConfig: [TableQuery.select('type', '类型').setOptions(Object.values(ScriptTypeEnum))],
|
searchItems: [SearchItem.select('type', '类型').withEnum(ScriptTypeEnum)],
|
||||||
columns: [
|
columns: [
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
TableColumn.new('description', '描述'),
|
TableColumn.new('description', '描述'),
|
||||||
@@ -129,8 +130,6 @@ const state = reactive({
|
|||||||
title: '',
|
title: '',
|
||||||
machineId: 9999999,
|
machineId: 9999999,
|
||||||
},
|
},
|
||||||
total: 0,
|
|
||||||
scriptTable: [],
|
|
||||||
scriptParamsDialog: {
|
scriptParamsDialog: {
|
||||||
script: null,
|
script: null,
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -148,7 +147,7 @@ const state = reactive({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { dialogVisible, queryConfig, columns, selectionData, query, editDialog, scriptParamsDialog, resultDialog, terminalDialog } = toRefs(state);
|
const { dialogVisible, columns, selectionData, query, editDialog, scriptParamsDialog, resultDialog, terminalDialog } = toRefs(state);
|
||||||
|
|
||||||
watch(props, async (newValue) => {
|
watch(props, async (newValue) => {
|
||||||
state.dialogVisible = newValue.visible;
|
state.dialogVisible = newValue.visible;
|
||||||
@@ -281,7 +280,6 @@ const handleClose = () => {
|
|||||||
emit('update:machineId', null);
|
emit('update:machineId', null);
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
state.query.type = ScriptTypeEnum.Private.value;
|
state.query.type = ScriptTypeEnum.Private.value;
|
||||||
state.scriptTable = [];
|
|
||||||
state.scriptParamsDialog.paramsFormItem = [];
|
state.scriptParamsDialog.paramsFormItem = [];
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
<page-table
|
<page-table
|
||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="authCertApi.list"
|
:page-api="authCertApi.list"
|
||||||
:query="state.queryConfig"
|
:search-items="state.searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
:columns="state.columns"
|
:columns="state.columns"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button type="primary" icon="plus" @click="edit(false)">添加</el-button>
|
<el-button type="primary" icon="plus" @click="edit(false)">添加</el-button>
|
||||||
<el-button :disabled="selectionData.length < 1" @click="deleteAc(selectionData)" type="danger" icon="delete">删除 </el-button>
|
<el-button :disabled="selectionData.length < 1" @click="deleteAc(selectionData)" type="danger" icon="delete">删除 </el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -29,8 +29,9 @@ import AuthCertEdit from './AuthCertEdit.vue';
|
|||||||
import { authCertApi } from '../api';
|
import { authCertApi } from '../api';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { AuthMethodEnum } from '../enums';
|
import { AuthMethodEnum } from '../enums';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const pageTableRef: Ref<any> = ref(null);
|
const pageTableRef: Ref<any> = ref(null);
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -39,7 +40,7 @@ const state = reactive({
|
|||||||
pageSize: 0,
|
pageSize: 0,
|
||||||
name: null,
|
name: null,
|
||||||
},
|
},
|
||||||
queryConfig: [TableQuery.text('name', '凭证名称')],
|
searchItems: [SearchItem.text('name', '凭证名称')],
|
||||||
columns: [
|
columns: [
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
TableColumn.new('authMethod', '认证方式').typeTag(AuthMethodEnum),
|
TableColumn.new('authMethod', '认证方式').typeTag(AuthMethodEnum),
|
||||||
@@ -50,8 +51,6 @@ const state = reactive({
|
|||||||
TableColumn.new('createTime', '修改时间').isTime(),
|
TableColumn.new('createTime', '修改时间').isTime(),
|
||||||
TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(65).alignCenter(),
|
TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(65).alignCenter(),
|
||||||
],
|
],
|
||||||
total: 0,
|
|
||||||
authcerts: [],
|
|
||||||
selectionData: [],
|
selectionData: [],
|
||||||
paramsDialog: {
|
paramsDialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
:page-api="cronJobApi.execList"
|
:page-api="cronJobApi.execList"
|
||||||
:lazy="true"
|
:lazy="true"
|
||||||
:data-handler-fn="parseData"
|
:data-handler-fn="parseData"
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="params"
|
v-model:query-form="params"
|
||||||
:data="state.data.list"
|
:data="state.data.list"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #machineSelect>
|
<template #machineSelect>
|
||||||
<el-select v-model="params.machineId" filterable placeholder="选择机器查询" style="width: 200px" clearable>
|
<el-select v-model="params.machineId" filterable placeholder="选择机器查询" clearable>
|
||||||
<el-option v-for="ac in machineMap.values()" :key="ac.id" :value="ac.id" :label="ac.ip">
|
<el-option v-for="ac in machineMap.values()" :key="ac.id" :value="ac.id" :label="ac.ip">
|
||||||
{{ ac.ip }}
|
{{ ac.ip }}
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
@@ -38,8 +38,9 @@
|
|||||||
import { watch, ref, toRefs, reactive, Ref } from 'vue';
|
import { watch, ref, toRefs, reactive, Ref } from 'vue';
|
||||||
import { cronJobApi, machineApi } from '../api';
|
import { cronJobApi, machineApi } from '../api';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { CronJobExecStatusEnum } from '../enums';
|
import { CronJobExecStatusEnum } from '../enums';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -55,9 +56,9 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'update:data', 'cancel']);
|
const emit = defineEmits(['update:visible', 'update:data', 'cancel']);
|
||||||
|
|
||||||
const queryConfig = [
|
const searchItems = [
|
||||||
TableQuery.slot('machineId', '机器', 'machineSelect'),
|
SearchItem.slot('machineId', '机器', 'machineSelect'),
|
||||||
TableQuery.select('status', '状态').setOptions(Object.values(CronJobExecStatusEnum)),
|
SearchItem.select('status', '状态').setOptions(Object.values(CronJobExecStatusEnum)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
<page-table
|
<page-table
|
||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="cronJobApi.list"
|
:page-api="cronJobApi.list"
|
||||||
:query="queryConfig"
|
:query="searchItems"
|
||||||
v-model:query-form="params"
|
v-model:query-form="params"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="state.selectionData"
|
v-model:selection-data="state.selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.saveCronJob" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
<el-button v-auth="perms.saveCronJob" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
||||||
<el-button v-auth="perms.delCronJob" :disabled="selectionData.length < 1" @click="deleteCronJob()" type="danger" icon="delete">删除</el-button>
|
<el-button v-auth="perms.delCronJob" :disabled="selectionData.length < 1" @click="deleteCronJob()" type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -38,8 +38,9 @@ import { ref, toRefs, reactive, onMounted, defineAsyncComponent, Ref } from 'vue
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { cronJobApi } from '../api';
|
import { cronJobApi } from '../api';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { CronJobStatusEnum, CronJobSaveExecResTypeEnum } from '../enums';
|
import { CronJobStatusEnum, CronJobSaveExecResTypeEnum } from '../enums';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const CronJobEdit = defineAsyncComponent(() => import('./CronJobEdit.vue'));
|
const CronJobEdit = defineAsyncComponent(() => import('./CronJobEdit.vue'));
|
||||||
const CronJobExecList = defineAsyncComponent(() => import('./CronJobExecList.vue'));
|
const CronJobExecList = defineAsyncComponent(() => import('./CronJobExecList.vue'));
|
||||||
@@ -49,7 +50,7 @@ const perms = {
|
|||||||
delCronJob: 'machine:cronjob:del',
|
delCronJob: 'machine:cronjob:del',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryConfig = [TableQuery.text('name', '名称'), TableQuery.select('status', '状态').setOptions(Object.values(CronJobStatusEnum))];
|
const searchItems = [SearchItem.text('name', '名称'), SearchItem.select('status', '状态').withEnum(CronJobStatusEnum)];
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('key', 'key'),
|
TableColumn.new('key', 'key'),
|
||||||
|
|||||||
@@ -4,19 +4,19 @@
|
|||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="mongoApi.mongoList"
|
:page-api="mongoApi.mongoList"
|
||||||
:before-query-fn="checkRouteTagPath"
|
:before-query-fn="checkRouteTagPath"
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" @clear="search" filterable clearable style="width: 200px">
|
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" @clear="search" filterable clearable>
|
||||||
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button type="primary" icon="plus" @click="editMongo(true)" plain>添加</el-button>
|
<el-button type="primary" icon="plus" @click="editMongo(true)" plain>添加</el-button>
|
||||||
<el-button type="danger" icon="delete" :disabled="selectionData.length < 1" @click="deleteMongo" plain>删除 </el-button>
|
<el-button type="danger" icon="delete" :disabled="selectionData.length < 1" @click="deleteMongo" plain>删除 </el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -53,10 +53,11 @@ import { defineAsyncComponent, ref, toRefs, reactive, onMounted, Ref } from 'vue
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import ResourceTag from '../component/ResourceTag.vue';
|
import ResourceTag from '../component/ResourceTag.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { tagApi } from '../tag/api';
|
import { tagApi } from '../tag/api';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const MongoEdit = defineAsyncComponent(() => import('./MongoEdit.vue'));
|
const MongoEdit = defineAsyncComponent(() => import('./MongoEdit.vue'));
|
||||||
const MongoDbs = defineAsyncComponent(() => import('./MongoDbs.vue'));
|
const MongoDbs = defineAsyncComponent(() => import('./MongoDbs.vue'));
|
||||||
@@ -65,15 +66,15 @@ const MongoRunCommand = defineAsyncComponent(() => import('./MongoRunCommand.vue
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const pageTableRef: Ref<any> = ref(null);
|
const pageTableRef: Ref<any> = ref(null);
|
||||||
|
|
||||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect')];
|
const searchItems = [SearchItem.slot('tagPath', '标签', 'tagPathSelect')];
|
||||||
const columns = ref([
|
const columns = [
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
TableColumn.new('uri', '连接uri'),
|
TableColumn.new('uri', '连接uri'),
|
||||||
TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(20).alignCenter(),
|
TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(20).alignCenter(),
|
||||||
TableColumn.new('createTime', '创建时间').isTime(),
|
TableColumn.new('createTime', '创建时间').isTime(),
|
||||||
TableColumn.new('creator', '创建人'),
|
TableColumn.new('creator', '创建人'),
|
||||||
TableColumn.new('action', '操作').isSlot().setMinWidth(170).fixedRight().alignCenter(),
|
TableColumn.new('action', '操作').isSlot().setMinWidth(170).fixedRight().alignCenter(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tags: [],
|
tags: [],
|
||||||
|
|||||||
@@ -4,19 +4,19 @@
|
|||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="redisApi.redisList"
|
:page-api="redisApi.redisList"
|
||||||
:before-query-fn="checkRouteTagPath"
|
:before-query-fn="checkRouteTagPath"
|
||||||
:query="queryConfig"
|
:searchItems="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" @clear="search" filterable clearable style="width: 200px">
|
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" @clear="search" filterable clearable>
|
||||||
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
<el-option v-for="item in tags" :key="item" :label="item" :value="item"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button type="primary" icon="plus" @click="editRedis(false)" plain>添加</el-button>
|
<el-button type="primary" icon="plus" @click="editRedis(false)" plain>添加</el-button>
|
||||||
<el-button type="danger" icon="delete" :disabled="selectionData.length < 1" @click="deleteRedis" plain>删除 </el-button>
|
<el-button type="danger" icon="delete" :disabled="selectionData.length < 1" @click="deleteRedis" plain>删除 </el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -163,15 +163,16 @@ import RedisEdit from './RedisEdit.vue';
|
|||||||
import { dateFormat } from '@/common/utils/date';
|
import { dateFormat } from '@/common/utils/date';
|
||||||
import ResourceTag from '../component/ResourceTag.vue';
|
import ResourceTag from '../component/ResourceTag.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { tagApi } from '../tag/api';
|
import { tagApi } from '../tag/api';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const pageTableRef: Ref<any> = ref(null);
|
const pageTableRef: Ref<any> = ref(null);
|
||||||
|
|
||||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect')];
|
const searchItems = [SearchItem.slot('tagPath', '标签', 'tagPathSelect')];
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
TableColumn.new('host', 'host:port'),
|
TableColumn.new('host', 'host:port'),
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
<page-table
|
<page-table
|
||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="tagApi.getTeams"
|
:page-api="tagApi.getTeams"
|
||||||
:query="state.queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
:columns="state.columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="'team:save'" type="primary" icon="plus" @click="showSaveTeamDialog(false)">添加</el-button>
|
<el-button v-auth="'team:save'" type="primary" icon="plus" @click="showSaveTeamDialog(false)">添加</el-button>
|
||||||
<el-button v-auth="'team:del'" :disabled="selectionData.length < 1" @click="deleteTeam()" type="danger" icon="delete">删除</el-button>
|
<el-button v-auth="'team:del'" :disabled="selectionData.length < 1" @click="deleteTeam()" type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -91,11 +91,11 @@
|
|||||||
ref="showMemPageTableRef"
|
ref="showMemPageTableRef"
|
||||||
:page-api="tagApi.getTeamMem"
|
:page-api="tagApi.getTeamMem"
|
||||||
:lazy="true"
|
:lazy="true"
|
||||||
:query="showMemDialog.queryConfig"
|
:search-items="showMemDialog.searchItems"
|
||||||
v-model:query-form="showMemDialog.query"
|
v-model:query-form="showMemDialog.query"
|
||||||
:columns="showMemDialog.columns"
|
:columns="showMemDialog.columns"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="'team:member:save'" @click="showAddMemberDialog()" type="primary" icon="plus">添加</el-button>
|
<el-button v-auth="'team:member:save'" @click="showAddMemberDialog()" type="primary" icon="plus">添加</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -139,13 +139,23 @@ import { accountApi } from '../../system/api';
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { notBlank } from '@/common/assert';
|
import { notBlank } from '@/common/assert';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const teamForm: any = ref(null);
|
const teamForm: any = ref(null);
|
||||||
const tagTreeRef: any = ref(null);
|
const tagTreeRef: any = ref(null);
|
||||||
const pageTableRef: Ref<any> = ref(null);
|
const pageTableRef: Ref<any> = ref(null);
|
||||||
const showMemPageTableRef: Ref<any> = ref(null);
|
const showMemPageTableRef: Ref<any> = ref(null);
|
||||||
|
|
||||||
|
const searchItems = [SearchItem.text('name', '团队名称')];
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new('name', '团队名称'),
|
||||||
|
TableColumn.new('remark', '备注'),
|
||||||
|
TableColumn.new('createTime', '创建时间').isTime(),
|
||||||
|
TableColumn.new('creator', '创建人'),
|
||||||
|
TableColumn.new('action', '操作').isSlot().setMinWidth(120).fixedRight().alignCenter(),
|
||||||
|
];
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
currentEditPermissions: false,
|
currentEditPermissions: false,
|
||||||
addTeamDialog: {
|
addTeamDialog: {
|
||||||
@@ -158,17 +168,9 @@ const state = reactive({
|
|||||||
pageSize: 0,
|
pageSize: 0,
|
||||||
name: null,
|
name: null,
|
||||||
},
|
},
|
||||||
queryConfig: [TableQuery.text('name', '团队名称')],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new('name', '团队名称'),
|
|
||||||
TableColumn.new('remark', '备注'),
|
|
||||||
TableColumn.new('createTime', '创建时间').isTime(),
|
|
||||||
TableColumn.new('creator', '创建人'),
|
|
||||||
TableColumn.new('action', '操作').isSlot().setMinWidth(120).fixedRight().alignCenter(),
|
|
||||||
],
|
|
||||||
selectionData: [],
|
selectionData: [],
|
||||||
showMemDialog: {
|
showMemDialog: {
|
||||||
queryConfig: [TableQuery.text('username', '用户名')],
|
searchItems: [SearchItem.text('username', '用户名').withSpan(2)],
|
||||||
columns: [
|
columns: [
|
||||||
TableColumn.new('name', '姓名'),
|
TableColumn.new('name', '姓名'),
|
||||||
TableColumn.new('username', '账号'),
|
TableColumn.new('username', '账号'),
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
<page-table
|
<page-table
|
||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
:page-api="accountApi.list"
|
:page-api="accountApi.list"
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.addAccount" type="primary" icon="plus" @click="editAccount(false)">添加</el-button>
|
<el-button v-auth="perms.addAccount" type="primary" icon="plus" @click="editAccount(false)">添加</el-button>
|
||||||
<el-button v-auth="perms.delAccount" :disabled="state.selectionData.length < 1" @click="deleteAccount()" type="danger" icon="delete"
|
<el-button v-auth="perms.delAccount" :disabled="state.selectionData.length < 1" @click="deleteAccount()" type="danger" icon="delete"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
@@ -85,8 +85,9 @@ import { accountApi } from '../api';
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { dateFormat } from '@/common/utils/date';
|
import { dateFormat } from '@/common/utils/date';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const perms = {
|
const perms = {
|
||||||
addAccount: 'account:add',
|
addAccount: 'account:add',
|
||||||
@@ -95,8 +96,8 @@ const perms = {
|
|||||||
changeAccountStatus: 'account:changeStatus',
|
changeAccountStatus: 'account:changeStatus',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryConfig = [TableQuery.text('username', '用户名')];
|
const searchItems = [SearchItem.text('username', '用户名')];
|
||||||
const columns = ref([
|
const columns = [
|
||||||
TableColumn.new('name', '姓名'),
|
TableColumn.new('name', '姓名'),
|
||||||
TableColumn.new('username', '用户名'),
|
TableColumn.new('username', '用户名'),
|
||||||
TableColumn.new('status', '状态').typeTag(AccountStatusEnum),
|
TableColumn.new('status', '状态').typeTag(AccountStatusEnum),
|
||||||
@@ -106,7 +107,7 @@ const columns = ref([
|
|||||||
TableColumn.new('createTime', '创建时间').isTime(),
|
TableColumn.new('createTime', '创建时间').isTime(),
|
||||||
TableColumn.new('modifier', '更新账号'),
|
TableColumn.new('modifier', '更新账号'),
|
||||||
TableColumn.new('updateTime', '更新时间').isTime(),
|
TableColumn.new('updateTime', '更新时间').isTime(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
// 该用户拥有的的操作列按钮权限
|
// 该用户拥有的的操作列按钮权限
|
||||||
const actionBtns = hasPerms([perms.addAccount, perms.saveAccountRole, perms.changeAccountStatus]);
|
const actionBtns = hasPerms([perms.addAccount, perms.saveAccountRole, perms.changeAccountStatus]);
|
||||||
@@ -155,7 +156,7 @@ const { selectionData, query, showRoleDialog, showResourceDialog, roleDialog, ac
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (Object.keys(actionBtns).length > 0) {
|
if (Object.keys(actionBtns).length > 0) {
|
||||||
columns.value.push(actionColumn);
|
columns.push(actionColumn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table ref="pageTableRef" :page-api="configApi.list" v-model:selection-data="selectionData" :columns="columns">
|
<page-table ref="pageTableRef" :page-api="configApi.list" v-model:selection-data="selectionData" :columns="columns">
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.saveConfig" type="primary" icon="plus" @click="editConfig(false)">添加</el-button>
|
<el-button v-auth="perms.saveConfig" type="primary" icon="plus" @click="editConfig(false)">添加</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table
|
<page-table
|
||||||
:query="queryConfig"
|
:search-items="searchItems"
|
||||||
v-model:query-form="query"
|
v-model:query-form="query"
|
||||||
:show-selection="true"
|
:show-selection="true"
|
||||||
v-model:selection-data="selectionData"
|
v-model:selection-data="selectionData"
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
:page-api="roleApi.list"
|
:page-api="roleApi.list"
|
||||||
ref="pageTableRef"
|
ref="pageTableRef"
|
||||||
>
|
>
|
||||||
<template #queryRight>
|
<template #tableHeader>
|
||||||
<el-button v-auth="perms.addRole" type="primary" icon="plus" @click="editRole(false)">添加</el-button>
|
<el-button v-auth="perms.addRole" type="primary" icon="plus" @click="editRole(false)">添加</el-button>
|
||||||
<el-button v-auth="perms.delRole" :disabled="selectionData.length < 1" @click="deleteRole(selectionData)" type="danger" icon="delete"
|
<el-button v-auth="perms.delRole" :disabled="selectionData.length < 1" @click="deleteRole(selectionData)" type="danger" icon="delete"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
@@ -43,9 +43,10 @@ import ShowResource from './ShowResource.vue';
|
|||||||
import { roleApi, resourceApi } from '../api';
|
import { roleApi, resourceApi } from '../api';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
import { RoleStatusEnum } from '../enums';
|
import { RoleStatusEnum } from '../enums';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const perms = {
|
const perms = {
|
||||||
addRole: 'role:add',
|
addRole: 'role:add',
|
||||||
@@ -54,7 +55,7 @@ const perms = {
|
|||||||
saveRoleResource: 'role:saveResources',
|
saveRoleResource: 'role:saveResources',
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryConfig = [TableQuery.text('name', '角色名')];
|
const searchItems = [SearchItem.text('name', '角色名')];
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('name', '角色名称'),
|
TableColumn.new('name', '角色名称'),
|
||||||
TableColumn.new('code', '角色code'),
|
TableColumn.new('code', '角色code'),
|
||||||
|
|||||||
@@ -1,16 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table :query="queryConfig" v-model:query-form="query" :columns="columns" :page-api="logApi.list">
|
<page-table :search-items="searchItems" v-model:query-form="query" :columns="columns" :page-api="logApi.list">
|
||||||
<template #selectAccount>
|
<template #selectAccount>
|
||||||
<el-select
|
<el-select remote :remote-method="getAccount" v-model="query.creatorId" filterable placeholder="请输入并选择账号" clearable>
|
||||||
style="width: 200px"
|
|
||||||
remote
|
|
||||||
:remote-method="getAccount"
|
|
||||||
v-model="query.creatorId"
|
|
||||||
filterable
|
|
||||||
placeholder="请输入并选择账号"
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<el-option v-for="item in accounts" :key="item.id" :label="item.username" :value="item.id"> </el-option>
|
<el-option v-for="item in accounts" :key="item.id" :label="item.username" :value="item.id"> </el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
@@ -22,13 +14,14 @@
|
|||||||
import { toRefs, reactive } from 'vue';
|
import { toRefs, reactive } from 'vue';
|
||||||
import { logApi, accountApi } from '../api';
|
import { logApi, accountApi } from '../api';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { LogTypeEnum } from '../enums';
|
import { LogTypeEnum } from '../enums';
|
||||||
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
|
||||||
const queryConfig = [
|
const searchItems = [
|
||||||
TableQuery.slot('creatorId', '操作人', 'selectAccount'),
|
SearchItem.slot('creatorId', '操作人', 'selectAccount'),
|
||||||
TableQuery.select('type', '操作结果').setOptions(Object.values(LogTypeEnum)),
|
SearchItem.select('type', '操作结果').withEnum(LogTypeEnum),
|
||||||
TableQuery.text('description', '描述'),
|
SearchItem.text('description', '描述'),
|
||||||
];
|
];
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import "fmt"
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
AppName = "mayfly-go"
|
AppName = "mayfly-go"
|
||||||
Version = "v1.6.0"
|
Version = "v1.6.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetAppInfo() string {
|
func GetAppInfo() string {
|
||||||
|
|||||||
Reference in New Issue
Block a user