Browse Source

Update 优化修复 Table等组件

YueYunyun 1 năm trước cách đây
mục cha
commit
a113de8d25

+ 63 - 10
UI/VAP_V3.VUE/src/components/table/VbDataTable.vue

@@ -15,8 +15,8 @@ const formSlotSuffix = "tool-form_"
 
 const props = withDefaults(
 	defineProps<{
-		header?: Header[] // 逐渐弃用
 		columns: Header[]
+		columnsFun?: () => Header[]
 		tableTitle?: string
 		emptyTableText?: string
 		keyField?: string
@@ -160,7 +160,6 @@ const props = withDefaults(
 	}
 )
 const emits = defineEmits<{
-	(e: "update:header", v: Header[]): void
 	(e: "update:columns", v: Header[]): void
 	(e: "update:selectedRows", v: any[]): void
 	(e: "update:currentPage", v: number): void
@@ -170,8 +169,12 @@ const emits = defineEmits<{
 	(e: "page-change", v: number): void
 	(e: "update:formData", v: any): void
 	(e: "sort", v: Sort[]): void
+	(e: "row-click", row: any): void
+	(e: "row-db-click", row: any): void
+	(e: "checkbox-change", isChecked: boolean, row: any): void
 	(e: "select", row: any): void
 	(e: "unSelect", row: any): void
+	(e: "checkbox-all", isChecked: boolean, rows: any[]): void
 	(e: "select-all", rows: any[]): void
 	(e: "unSelect-all", rows: any[]): void
 }>()
@@ -179,7 +182,7 @@ const tableBoxRef = ref()
 const tableContentRef = ref()
 const id = ref("")
 
-const { data, queryParams, searchFormRowItems, searchFormItems } = toRefs(props)
+const { data, searchFormRowItems, searchFormItems } = toRefs(props)
 const leftFixedRef = ref()
 const tableResponsiveRef = ref()
 const rightFixedRef = ref()
@@ -198,14 +201,29 @@ const sortParams = ref<Sort[]>([
 	}
 ])
 
-const _columns = ref<Header[]>()
+const _columns = ref<Header[]>([])
 const columns: WritableComputedRef<Header[]> = computed({
 	get(): Header[] {
-		return _columns.value ?? props.columns ?? props.header ?? []
+		if (_columns.value && _columns.value.length > 0) {
+			if (props.columnsFun) {
+				const cols = props.columnsFun() ?? []
+				const newCols: Header[] = []
+				cols.forEach((v: Header) => {
+					const col = _columns.value.find((vv: Header) => vv.field == v.field)
+					if (col) {
+						v.visible = col.visible
+					}
+					newCols.push(v)
+				})
+				_columns.value = newCols
+			}
+		} else {
+			_columns.value = props.columnsFun ? props.columnsFun() : props.columns ?? []
+		}
+		return _columns.value
 	},
 	set(value: Header[]): void {
 		_columns.value = value
-		emits("update:header", value)
 		emits("update:columns", value)
 	}
 })
@@ -392,9 +410,8 @@ const defaultHandleFuns = {
 		if (props.exportUrl) {
 			download(
 				props.exportUrl,
-				{ ...innerQueryParams.value },
 				`${props.exportName ? props.exportName + "_" : ""}${new Date().getTime()}.xlsx`,
-				{ method: "POST" }
+				{ method: "POST", params: { ...innerQueryParams.value } }
 			)
 		} else {
 			message.alertError("导出接口方法未配置,请联系管理员")
@@ -631,6 +648,19 @@ function getSelectedIds() {
 function getData() {
 	return remoteData.value
 }
+function setSelecteds(rows: any[] | any, isSelected: boolean) {
+	if (!Array.isArray(rows)) {
+		rows = [rows]
+	}
+	if (isSelected) {
+		selectedRows.value = [...new Set([...selectedRows.value, ...rows])]
+	} else {
+		selectedRows.value = selectedRows.value.filter((item: any) => !rows.includes(item))
+	}
+}
+function clearSelecteds() {
+	selectedRows.value = []
+}
 provide(symbolKeys.tableBox, tableBoxRef)
 provide(symbolKeys.searchFrom, {
 	queryParams: innerQueryParams,
@@ -652,9 +682,9 @@ provide(symbolKeys.content, {
 	tableClass: props.tableClass,
 	tableStyle: tableStyle.value
 })
+provide(symbolKeys.checkAll, checkAll)
 provide(symbolKeys.header, {
 	columns,
-	checkAll,
 	hasCheckbox: isMultipleCheck.value || props.hasCheckbox,
 	isMultipleCheck: isMultipleCheck.value,
 	sortField: props.sortField ?? "",
@@ -733,6 +763,7 @@ const onSelectAll = (isChecked: boolean) => {
 		sRows = [...new Set([...selectedRows.value, ...displayData.value])]
 		selectedRows.value = sRows
 		emits("select-all", sRows)
+		emits("checkbox-all", true, sRows)
 	} else {
 		if (props.checkPageMultiple) {
 			sRows = selectedRows.value.filter(
@@ -743,6 +774,7 @@ const onSelectAll = (isChecked: boolean) => {
 		}
 		selectedRows.value = sRows
 		emits("unSelect-all", sRows)
+		emits("checkbox-all", false, displayData.value)
 	}
 }
 const onSelect = (v: { isChecked: boolean; row: any }) => {
@@ -752,12 +784,14 @@ const onSelect = (v: { isChecked: boolean; row: any }) => {
 		sRows = isMultipleCheck.value ? [...new Set([...selectedRows.value, row])] : [row]
 		selectedRows.value = sRows
 		emits("select", row)
+		emits("checkbox-change", true, row)
 	} else {
 		sRows = isMultipleCheck.value
 			? selectedRows.value.filter((vv) => vv[keyField.value] != row[keyField.value])
 			: []
 		selectedRows.value = sRows
 		emits("unSelect", row)
+		emits("checkbox-change", false, row)
 	}
 }
 const onQuery = () => {
@@ -766,10 +800,12 @@ const onQuery = () => {
 const onRowClick = (v: any) => {
 	const row = toValue(v)
 	props.rowClick && props.rowClick(row)
+	emits("row-click", row)
 }
 const onRowDbClick = (v: any) => {
 	const row = toValue(v)
 	props.rowDbClick && props.rowDbClick(row)
+	emits("row-db-click", row)
 }
 const onReset = () => {
 	innerQueryParams.value = JSON.parse(emptyQueryParams)
@@ -917,11 +953,26 @@ function init() {
 		_tableBoxStyle.value = calcTableBoxStyle()
 	})
 }
-
 onMounted(init)
 onUnmounted(() => {
 	tableResponsiveRef.value?.removeEventListener("scroll", onFixedScrollX, true)
 })
+watch(selectedRows, (val: any) => {
+	if (val.length > 0 && val.length == displayData.value.length) {
+		let flag = true
+		displayData.value.forEach((item: any) => {
+			if (
+				selectedRows.value.find((row: any) => row[keyField.value] == item[keyField.value]) == null
+			) {
+				flag = false
+				return
+			}
+		})
+		checkAll.value = flag
+	} else {
+		checkAll.value = false
+	}
+})
 watch(
 	() => props.queryParams,
 	(val: any) => {
@@ -938,6 +989,8 @@ defineExpose({
 	getSelecteds,
 	getData,
 	getQueryParams,
+	setSelecteds,
+	clearSelecteds,
 	defaultHandleFuns
 })
 </script>

+ 1 - 2
UI/VAP_V3.VUE/src/components/table/partials/header/HeaderTr.vue

@@ -9,7 +9,6 @@ const props = withDefaults(
 		columns: HeaderEx[]
 		sort: Sort
 		rowspan: number
-		checkAll: boolean
 		hasCheckbox: boolean
 		isMultipleCheck: boolean
 		thTrClass: string
@@ -17,7 +16,7 @@ const props = withDefaults(
 	{}
 )
 const tableBox = inject(symbolKeys.tableBox) as Ref<HTMLElement>
-const checkAll = ref(props.checkAll)
+const checkAll = inject(symbolKeys.checkAll, ref(false))
 const onChange = (event: Event) => {
 	const target = event.target as HTMLInputElement
 	VbUtil.EventHandlerUtil.trigger(tableBox.value, "vbtable.select-all", target.checked)

+ 1 - 4
UI/VAP_V3.VUE/src/components/table/partials/header/TableHeader.vue

@@ -4,7 +4,6 @@ import VbTr from "@@@/table/partials/header/HeaderTr.vue"
 import type { Sort, Header, HeaderEx } from "@@@/table/models"
 const propOpts = inject(symbolKeys.header, {
 	columns: ref([]),
-	checkAll: ref(false),
 	hasCheckbox: true,
 	isMultipleCheck: true,
 	sortField: "",
@@ -12,8 +11,7 @@ const propOpts = inject(symbolKeys.header, {
 	headerClass: "fixed",
 	thTrClass: "text-center text-gray-800 fw-bold fs-7"
 })
-
-const { columns, checkAll } = propOpts
+const { columns } = propOpts
 
 const sort = ref<Sort>({
 	label: propOpts.sortField,
@@ -88,7 +86,6 @@ const headerColumns = computed(() => {
 				:sort="sort"
 				:has-checkbox="i == 0 && propOpts.hasCheckbox"
 				:is-multiple-check="propOpts.isMultipleCheck"
-				:check-all="checkAll"
 				:th-tr-class="propOpts.thTrClass">
 				<template v-for="(_, name) in $slots" #[name]="{ row }">
 					<slot :name="name" :row="row" />

+ 25 - 3
UI/VAP_V3.VUE/src/components/table/partials/toolbar/TableRightToolbar.vue

@@ -35,17 +35,17 @@ const style = computed(() => {
 const visColumnIds = ref()
 function getVisibleIds() {
 	const ids: string[] = []
-	function caclVisibleIds(list: Header[]) {
+	function calcVisibleIds(list: Header[]) {
 		list.forEach((v) => {
 			if (v.visible === undefined || v.visible) {
 				ids.push(v.field)
 				if (v.children && v.children.length > 0) {
-					caclVisibleIds(v.children)
+					calcVisibleIds(v.children)
 				}
 			}
 		})
 	}
-	caclVisibleIds(columns.value)
+	calcVisibleIds(columns.value)
 	return ids
 }
 function getColumnById(id: string, list: Header[]): Header | null {
@@ -72,6 +72,7 @@ const toggleSearch = () => {
 const refresh = () => {
 	VbUtil.EventHandlerUtil.trigger(tableBox.value, "vbtable.query")
 }
+
 const hideColumnMenu = () => {
 	VbComponents.MenuComponent.hideDropdowns(columnMenuRef.value)
 }
@@ -83,8 +84,29 @@ const onColumnChange = (data: any) => {
 	}
 }
 onMounted(() => {
+	const el = document.querySelector("#" + btnColumnId.value) as HTMLElement
+	if (!VbComponents.MenuComponent.getInstance(el)) {
+		VbComponents.MenuComponent.createInstance("#" + btnColumnId.value, {
+			dropdown: {
+				hoverTimeout: 200,
+				zindex: 105
+			},
+			accordion: {
+				slideSpeed: 250,
+				expand: false
+			}
+		})
+	}
+
 	visColumnIds.value = getVisibleIds()
 })
+watch(
+	() => columns.value,
+	() => {
+		visColumnIds.value = getVisibleIds()
+		elTreeRef.value.setCheckedKeys(visColumnIds.value)
+	}
+)
 </script>
 <template>
 	<div :style="style">

+ 1 - 1
UI/VAP_V3.VUE/src/components/table/symbol.ts

@@ -25,9 +25,9 @@ export default {
 		tableClass: string
 		tableStyle: string
 	}>,
+	checkAll: Symbol("checkAll") as InjectionKey<Ref<boolean>>,
 	header: Symbol("header") as InjectionKey<{
 		columns: Ref<Header[]>
-		checkAll: Ref<boolean>
 		hasCheckbox: boolean // 是否有选择框
 		isMultipleCheck: boolean // 是否多选
 		sortField: string // 排序字段

+ 120 - 0
UI/VAP_V3.VUE/src/components/tree/VbTree.vue

@@ -0,0 +1,120 @@
+<script setup lang="ts">
+const props = withDefaults(
+	defineProps<{
+		modelValue?: string | number
+		data?: any
+		dataFun?: () => Promise<any>
+		showSearchInput?: boolean
+		searchWords?: string
+		treeBoxClass?: string
+		treeBoxStyle?: string
+		props?: any
+	}>(),
+	{
+		searchWords: "",
+		treeBoxClass: "h-100",
+		treeBoxStyle: "margin-top:15px;background: var(--bs-app-header-minimize-bg-color);",
+		props: () => {
+			return {
+				children: "children",
+				label: "label",
+				id: "id"
+			}
+		}
+	}
+)
+const emits = defineEmits<{
+	(e: "update:modelValue", v: string): void
+	(e: "nodeClick", v: any): void
+}>()
+
+const { searchWords, data } = toRefs(props)
+const treeRef = ref<any>()
+const treeData = ref<any>([])
+
+const filterNode = (value: string, data: any) => {
+	if (!value) return true
+	return data.label.indexOf(value) !== -1
+}
+function handleNodeClick(data: any) {
+	emits("update:modelValue", data.id)
+	emits("nodeClick", data)
+}
+function loadTreeData() {
+	if (props.dataFun) {
+		props.dataFun().then((res) => {
+			treeData.value = res.data
+			if (treeData.value.length > 0) {
+				initDefaultKey(treeData.value[0].id)
+			}
+		})
+	} else if (data?.value) {
+		treeData.value = data.value
+		if (treeData.value.length > 0) {
+			initDefaultKey(treeData.value[0].id)
+		}
+		console.log("----", data.value)
+	}
+}
+/** 初始化默认选中 */
+function initDefaultKey(id: any) {
+	emits("update:modelValue", id)
+	setTimeout(() => {
+		treeRef.value.setCurrentKey(id)
+	}, 50)
+}
+function setCurrentKey(id: any) {
+	if (!id) {
+		id = treeData.value[0].id
+	}
+	initDefaultKey(id)
+}
+function init() {
+	loadTreeData()
+}
+
+onMounted(init)
+/** 根据关键字筛选 */
+watchEffect(
+	() => {
+		treeRef.value?.filter(searchWords.value)
+	},
+	{
+		flush: "post" // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
+	}
+)
+defineExpose({
+	setCurrentKey
+})
+</script>
+<template>
+	<div :class="treeBoxClass" :style="treeBoxStyle">
+		<el-input
+			v-if="showSearchInput"
+			v-model="searchWords"
+			placeholder="请输入关键字"
+			clearable
+			prefix-icon="Search" />
+		<el-tree
+			class="pt-3"
+			ref="treeRef"
+			:data="treeData"
+			:props="props.props"
+			:expand-on-click-node="false"
+			:filter-node-method="filterNode"
+			:node-key="props.props.id"
+			highlight-current
+			default-expand-all
+			@node-click="handleNodeClick" />
+	</div>
+</template>
+
+<style lang="scss" scoped>
+:deep(.el-tree--highlight-current) {
+	.el-tree-node.is-current > .el-tree-node__content {
+		background-color: var(--bs-primary);
+		color: #fff;
+		border-radius: 0.25rem;
+	}
+}
+</style>

+ 0 - 1
UI/VAP_V3.VUE/src/components/upload/ImportModal.vue

@@ -71,7 +71,6 @@ function handleFileError(error: Error, file: any, fileList: any) {
 function importTemplate() {
 	download(
 		opts.value.templateUrl,
-		{},
 		`${opts.value.templateName}_TEMPLATE_${new Date().getTime()}.xlsx`
 	)
 }