|
@@ -1,22 +1,47 @@
|
|
|
<script setup lang="ts">
|
|
|
import type { BaseFieldItem, TableFields } from '@/types/Tables/table'
|
|
|
+import type { FormInstance, FormRules } from 'element-plus'
|
|
|
+import type { AllAdmgeTtFields } from '@/types/Tables/tableData/ttAd'
|
|
|
+import type {
|
|
|
+ DialogProps,
|
|
|
+ SaveForm,
|
|
|
+} from '@/types/Tables/customIndicatorDialog'
|
|
|
|
|
|
import { ref, reactive, watch } from 'vue'
|
|
|
import { useTable } from '@/hooks/useTable'
|
|
|
import { computed } from 'vue'
|
|
|
+import { useCustomIndicatorDialog } from '@/hooks/useCustomIndicatorDialog'
|
|
|
+import { useDialogDrag } from '@/hooks/useDialogDrag'
|
|
|
|
|
|
const { isFixedField } = useTable()
|
|
|
+const {
|
|
|
+ initSortedTableFieldsInfo,
|
|
|
+ validCustomName,
|
|
|
+ updateFixedIndicator,
|
|
|
+ updateUnfixedIndicator,
|
|
|
+ getActivedIndicator,
|
|
|
+ updateSortedTableFieldsInfo,
|
|
|
+} = useCustomIndicatorDialog()
|
|
|
+
|
|
|
+const props = withDefaults(defineProps<DialogProps>(), {
|
|
|
+ SaveFormData: () => {
|
|
|
+ return {
|
|
|
+ isSaveCustom: false,
|
|
|
+ saveCustomName: '',
|
|
|
+ }
|
|
|
+ },
|
|
|
+})
|
|
|
|
|
|
-interface DialogProps {
|
|
|
- indicatorFields: Array<BaseFieldItem<TableFields>>
|
|
|
- defaultActiveNav: string
|
|
|
- tableFieldsInfo: Array<TableFields>
|
|
|
- fixedFields: Array<string>
|
|
|
-}
|
|
|
+const emits = defineEmits(['updateFields'])
|
|
|
|
|
|
-const props = withDefaults(defineProps<DialogProps>(), {})
|
|
|
+const saveForm = reactive<SaveForm>(props.SaveFormData)
|
|
|
|
|
|
-const emits = defineEmits(['updateFields'])
|
|
|
+const saveFormRules = reactive<FormRules<SaveForm>>({
|
|
|
+ saveCustomName: [{ validator: validCustomName, trigger: 'blur' }],
|
|
|
+})
|
|
|
+
|
|
|
+// 保存自定义指标表单实例
|
|
|
+const saveFormRef = ref<FormInstance>()
|
|
|
|
|
|
// 被排序过后的表格字段信息
|
|
|
const sortedTableFieldsInfo = reactive<Array<TableFields>>([])
|
|
@@ -27,65 +52,33 @@ const newTableFieldsInfo = reactive<Array<TableFields>>([])
|
|
|
// 自定义指标的展示状态
|
|
|
const customIndicatorVisible = ref<boolean>(false)
|
|
|
|
|
|
+// 每次展开的时候,右侧栏目的排序需要跟表格字段的顺序同步
|
|
|
+// 不然会导致表格字段和右侧的栏目的顺序不一致
|
|
|
+// 关闭后需要重置这个状态,每次打开都要排一次
|
|
|
+const isFirstShow = ref<boolean>(true)
|
|
|
+
|
|
|
// 自定义指标搜索值
|
|
|
const indicatorSearch = ref<string>('')
|
|
|
|
|
|
// 自定义指标左侧导航选中值
|
|
|
const indicatorNavActive = ref<string>(props.defaultActiveNav)
|
|
|
|
|
|
-// 自定义指标中需要固定的指标
|
|
|
-const fixedIndicator = computed<TableFields[]>(() => {
|
|
|
- let result: TableFields[] = []
|
|
|
- // 对于固定的指标,为了防止传入的数据有误,所有直接state设置为true
|
|
|
- props.indicatorFields.forEach(item => {
|
|
|
- result.push(
|
|
|
- ...item.children.filter(item => {
|
|
|
- if (item.fixed) item.state = true
|
|
|
- return item.fixed
|
|
|
- }),
|
|
|
- )
|
|
|
- })
|
|
|
- console.log('asdf')
|
|
|
- console.log(JSON.parse(JSON.stringify(result)))
|
|
|
- return result
|
|
|
-})
|
|
|
-
|
|
|
-// 没有被固定的指标
|
|
|
-// 这里去更新state是为了让表格的字段能够正确同步
|
|
|
-const unFixedIndicator = computed<TableFields[]>(() => {
|
|
|
- let result: TableFields[] = []
|
|
|
- // 拿到所有的子元素
|
|
|
- let allChilds = props.indicatorFields.flatMap(
|
|
|
- item => item.children,
|
|
|
- ) as Array<TableFields>
|
|
|
- allChilds.map(item => (item.state = false))
|
|
|
-
|
|
|
- // 拿到所有的选中值
|
|
|
- let allSelected = props.indicatorFields.flatMap(
|
|
|
- item => item.value,
|
|
|
- ) as Array<string>
|
|
|
-
|
|
|
- // 之所以要这样去筛选,是为了保证顺序,
|
|
|
- // 如果直接通过filter去找存在于allSelected中的元素,
|
|
|
- // 那么当一个在前面的选项首先取消选择,然后又重新选中的时候,这个选项又会直接出现在他原来的位置,而不是末尾
|
|
|
- allSelected.forEach(item => {
|
|
|
- let child = allChilds.find(
|
|
|
- child => !child.fixed && child.name === item,
|
|
|
- ) as TableFields
|
|
|
- if (child) {
|
|
|
- child.state = true
|
|
|
- result.push(child)
|
|
|
- }
|
|
|
- })
|
|
|
- console.log(result)
|
|
|
- return result
|
|
|
-})
|
|
|
-
|
|
|
// 拖拽的容器
|
|
|
-const dragContentRef = ref<HTMLElement>()
|
|
|
+const dragContentRef = ref<HTMLElement | null>(null)
|
|
|
|
|
|
// 当前正在被拖拽的元素
|
|
|
-const dragingRef = ref<HTMLElement>()
|
|
|
+const dragingRef = ref<HTMLElement | null>(null)
|
|
|
+
|
|
|
+// 所有需要固定的指标
|
|
|
+const fixedIndicator = reactive<TableFields[]>([])
|
|
|
+
|
|
|
+// 所有需要不固定的指标
|
|
|
+const unFixedIndicator = reactive<TableFields[]>([])
|
|
|
+
|
|
|
+const { dragStart, dragEnter, dragOver } = useDialogDrag(
|
|
|
+ dragingRef,
|
|
|
+ dragContentRef,
|
|
|
+)
|
|
|
|
|
|
// 当默认值变化的时候,要更新一下,这里主要用在初始化的时候,数据可能还没有获取到
|
|
|
watch(
|
|
@@ -98,23 +91,44 @@ watch(
|
|
|
},
|
|
|
)
|
|
|
|
|
|
-const indicatorOpen = () => {}
|
|
|
-
|
|
|
-const indicatorClose = () => {
|
|
|
- // 重置到第一个锚点
|
|
|
- indicatorNavActive.value = props.indicatorFields[0]?.name
|
|
|
+/**
|
|
|
+ * @description: 多选框值改变,去更新不固定字段的展示
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const changeIndicatorChecked = () => {
|
|
|
+ updateUnfixedIndicator(
|
|
|
+ props.indicatorFields,
|
|
|
+ isFirstShow,
|
|
|
+ props.tableFieldsInfo,
|
|
|
+ unFixedIndicator,
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @description: 初始化一下被排序过的表格字段信息,这里要注意深拷贝
|
|
|
+ * @description: 对话框打开,做一些公布设置
|
|
|
* @return {*}
|
|
|
*/
|
|
|
-const initSortedTableFieldsInfo = () => {
|
|
|
- sortedTableFieldsInfo.splice(
|
|
|
- 0,
|
|
|
- sortedTableFieldsInfo.length,
|
|
|
- ...JSON.parse(JSON.stringify(props.tableFieldsInfo)),
|
|
|
+const indicatorOpen = () => {
|
|
|
+ isFirstShow.value = true // 用于同步表格和右侧栏目的顺序
|
|
|
+ // 给不固定框一个初始值
|
|
|
+ updateUnfixedIndicator(
|
|
|
+ props.indicatorFields,
|
|
|
+ isFirstShow,
|
|
|
+ props.tableFieldsInfo,
|
|
|
+ unFixedIndicator,
|
|
|
)
|
|
|
+ updateFixedIndicator(props.indicatorFields, fixedIndicator) // 固定框给初始值
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 对话框关闭
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const indicatorClose = () => {
|
|
|
+ // 重置到第一个锚点
|
|
|
+ indicatorNavActive.value = props.indicatorFields[0]?.name
|
|
|
+ // isSaveCustom.value = false
|
|
|
+ saveForm.isSaveCustom = false
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -144,118 +158,19 @@ const showCustomIndicator = () => {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @description: 判断当前是否可以插入
|
|
|
- * @param {*} e 触发事件的事件对象
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const canInsert = (e: DragEvent): boolean => {
|
|
|
- return !(
|
|
|
- !e.target ||
|
|
|
- !dragingRef.value ||
|
|
|
- !dragContentRef.value ||
|
|
|
- dragingRef.value === e.target ||
|
|
|
- e.target === dragContentRef.value
|
|
|
- )
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 拖动开始
|
|
|
- * @param {*} e 拖动事件对象
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const dragStart = (e: DragEvent) => {
|
|
|
- if (!dragContentRef.value || !e.target || !e.dataTransfer) return
|
|
|
- e.dataTransfer.effectAllowed = 'move' // 设置拖拽类型
|
|
|
- dragingRef.value = e.target as HTMLElement // 获取当前拖拽的元素
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 拖拽过程
|
|
|
- * @param {*} e 拖拽事件对象
|
|
|
+ * @description: 生成新的表格字段信息
|
|
|
* @return {*}
|
|
|
*/
|
|
|
-const dragEnter = (e: DragEvent) => {
|
|
|
- e.preventDefault()
|
|
|
- if (!canInsert(e)) return
|
|
|
- let listArray = Array.from(dragContentRef.value!.childNodes) // 整个可拖动的列表
|
|
|
- let curIndex = listArray.indexOf(dragingRef.value!) // 当前拖动元素在整个列表中的文职
|
|
|
- let targeIndex = listArray.indexOf(e.target as HTMLElement) // 目前拖动到的元素在整个列表中的位置
|
|
|
-
|
|
|
- if (curIndex < targeIndex) {
|
|
|
- dragContentRef.value!.insertBefore(
|
|
|
- dragingRef.value!,
|
|
|
- (e.target as HTMLElement).nextSibling,
|
|
|
- )
|
|
|
- } else {
|
|
|
- dragContentRef.value!.insertBefore(
|
|
|
- dragingRef.value!,
|
|
|
- e.target as HTMLElement,
|
|
|
- )
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 拖拽结束
|
|
|
- * @param {*} e 拖拽对象
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const dragOver = (e: DragEvent) => {
|
|
|
- e.preventDefault()
|
|
|
- if (!e.target) return
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 更新一下排序后的表格字段信息
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const updateSortedTableFieldsInfo = () => {
|
|
|
- sortedTableFieldsInfo.splice(0, sortedTableFieldsInfo.length)
|
|
|
- let sortedNodes = Array.from(dragContentRef.value!.children)
|
|
|
- let sortedFields: Array<string> = []
|
|
|
- // 把所有能够排序的节点的name提取出来,这些就是已经排好序的字段名
|
|
|
- sortedNodes.forEach((node: Element) => {
|
|
|
- if (node.nodeType === 1) {
|
|
|
- // 判断是否为元素节点
|
|
|
- sortedFields.push(node.getAttribute('name') as string)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // 根据排好序的字段名,去原本的字段信息中去找对应的字段名,把他加入到新字段信息中
|
|
|
- // 这里的排序与unFixedIndicator的排序不一样,这里是为了同步用户的拖动
|
|
|
- // unFixedIndicator的排序是为了同步新增的选项
|
|
|
- sortedFields.forEach((item: string) => {
|
|
|
- let fFiled = unFixedIndicator.value.find(field => field.name === item)
|
|
|
- if (fFiled) sortedTableFieldsInfo.push(fFiled)
|
|
|
- })
|
|
|
- console.log('fixed')
|
|
|
- console.log(fixedIndicator.value)
|
|
|
- // 还剩下固定字段的信息,把他加入数组头部
|
|
|
- sortedTableFieldsInfo.unshift(...fixedIndicator.value)
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 获取当前被激活的指标
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const getActivedIndicator = (): string[] => {
|
|
|
- let result: string[] = []
|
|
|
- props.indicatorFields.forEach(item => {
|
|
|
- item.children.forEach(field => {
|
|
|
- if (field.state) result.push(field.name)
|
|
|
- })
|
|
|
- })
|
|
|
- return result
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 应用配置的自定义指标
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const applyCustomIndicator = () => {
|
|
|
+const generateNewTableField = () => {
|
|
|
customIndicatorVisible.value = false
|
|
|
- updateSortedTableFieldsInfo() // 排序
|
|
|
+ updateSortedTableFieldsInfo(
|
|
|
+ sortedTableFieldsInfo,
|
|
|
+ dragContentRef,
|
|
|
+ unFixedIndicator,
|
|
|
+ fixedIndicator,
|
|
|
+ ) // 排序
|
|
|
// 拿到当前激活的所有自定义指标
|
|
|
- let actived = getActivedIndicator()
|
|
|
+ let actived = getActivedIndicator(props.indicatorFields)
|
|
|
// 把目前排好序的字段信息复制给新的字段信息
|
|
|
newTableFieldsInfo.splice(
|
|
|
0,
|
|
@@ -264,19 +179,45 @@ const applyCustomIndicator = () => {
|
|
|
)
|
|
|
// 根据当前已经激活的字段name,去吧字段信息中的state改为true
|
|
|
newTableFieldsInfo.map(item => {
|
|
|
- // console.log(item.name)
|
|
|
if (actived.includes(item.name)) {
|
|
|
item.state = true
|
|
|
} else {
|
|
|
item.state = false
|
|
|
}
|
|
|
})
|
|
|
- console.log(newTableFieldsInfo)
|
|
|
- emits('updateFields', newTableFieldsInfo)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @description: 取消选择
|
|
|
+ * @description: 验证保存自定义指标的表单是否填写正确了
|
|
|
+ * @param {FormInstance | undefined} saveFormRef 自定义指标表单实例
|
|
|
+ * @return {Promise<boolean>} 验证结果
|
|
|
+ */
|
|
|
+const validSaveForm = async (
|
|
|
+ saveFormRef: FormInstance | undefined,
|
|
|
+): Promise<boolean> => {
|
|
|
+ if (!saveFormRef) return false
|
|
|
+ let result = await saveFormRef.validate()
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 应用配置的自定义指标
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const applyCustomIndicator = async (saveFormRef: FormInstance | undefined) => {
|
|
|
+ let fileName = null
|
|
|
+ // 需要保存自定义指标为常用模板就需要去检查一下这个文件名
|
|
|
+ if (saveForm.isSaveCustom) {
|
|
|
+ let result = await validSaveForm(saveFormRef)
|
|
|
+ if (!result) return
|
|
|
+ fileName = saveForm.saveCustomName
|
|
|
+ }
|
|
|
+ generateNewTableField()
|
|
|
+ emits('updateFields', newTableFieldsInfo, fileName)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 取消已经选中的指标
|
|
|
* @param {*} name 字段名
|
|
|
* @return {*}
|
|
|
*/
|
|
@@ -291,7 +232,7 @@ const cancelSelect = (name: string) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-initSortedTableFieldsInfo()
|
|
|
+initSortedTableFieldsInfo(sortedTableFieldsInfo, props.tableFieldsInfo)
|
|
|
|
|
|
defineExpose({ showCustomIndicator })
|
|
|
</script>
|
|
@@ -340,7 +281,10 @@ defineExpose({ showCustomIndicator })
|
|
|
</div>
|
|
|
<el-row class="indicatorItem">
|
|
|
<el-col :span="8" v-for="item in field.children">
|
|
|
- <el-checkbox-group v-model="field.value">
|
|
|
+ <el-checkbox-group
|
|
|
+ v-model="field.value"
|
|
|
+ @change="changeIndicatorChecked"
|
|
|
+ >
|
|
|
<el-checkbox
|
|
|
style="margin-bottom: 16px"
|
|
|
:value="item.name"
|
|
@@ -387,11 +331,43 @@ defineExpose({ showCustomIndicator })
|
|
|
</div>
|
|
|
|
|
|
<template #footer>
|
|
|
- <div class="dialog-footer">
|
|
|
- <el-button @click="customIndicatorVisible = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="applyCustomIndicator">
|
|
|
- 应用
|
|
|
- </el-button>
|
|
|
+ <div class="dialogFooter">
|
|
|
+ <div class="footerTools">
|
|
|
+ <el-form
|
|
|
+ ref="saveFormRef"
|
|
|
+ :model="saveForm"
|
|
|
+ :rules="saveFormRules"
|
|
|
+ inline
|
|
|
+ >
|
|
|
+ <el-form-item class="saveFormItem" prop="isSaveCustom">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="saveForm.isSaveCustom"
|
|
|
+ label="保存为常用自定义指标"
|
|
|
+ size="default"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-if="saveForm.isSaveCustom"
|
|
|
+ prop="saveCustomName"
|
|
|
+ class="saveFormItem"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="saveForm.saveCustomName"
|
|
|
+ style="width: 240px"
|
|
|
+ placeholder="请输入自定义指标名"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div class="footerBtn">
|
|
|
+ <el-button @click="customIndicatorVisible = false">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="applyCustomIndicator(saveFormRef)"
|
|
|
+ >
|
|
|
+ 应用
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
@@ -525,20 +501,6 @@ defineExpose({ showCustomIndicator })
|
|
|
.dragBlock:not(.notAllow):hover {
|
|
|
background-color: #e7e7e7;
|
|
|
}
|
|
|
-
|
|
|
-// .draging {
|
|
|
-// position: relative;
|
|
|
-// }
|
|
|
-
|
|
|
-// .draging::after {
|
|
|
-// content: '';
|
|
|
-// position: absolute;
|
|
|
-// top: 0;
|
|
|
-// right: 0;
|
|
|
-// bottom: 0;
|
|
|
-// left: 0;
|
|
|
-// }
|
|
|
-
|
|
|
// 禁止拖拽
|
|
|
.notAllow {
|
|
|
cursor: not-allowed;
|
|
@@ -595,4 +557,16 @@ defineExpose({ showCustomIndicator })
|
|
|
overflow-x: hidden;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
+
|
|
|
+.saveFormItem {
|
|
|
+ margin-bottom: 0;
|
|
|
+ margin-right: 15px;
|
|
|
+ // padding: 0 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.dialogFooter {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
</style>
|