|
@@ -8,14 +8,24 @@ import type { FormInstance } from 'element-plus'
|
|
|
import type { TableData, BaseFieldInfo } from '@/types/Tables/table'
|
|
|
|
|
|
import { TableFilterType } from '@/types/Tables/table'
|
|
|
-
|
|
|
-import { computed, onMounted, reactive, ref, watch } from 'vue'
|
|
|
+import { resetReactive } from '@/utils/common'
|
|
|
+import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
|
|
|
import { Search } from '@element-plus/icons-vue'
|
|
|
import { Plus, Operation } from '@element-plus/icons-vue'
|
|
|
+import { useTable } from '@/hooks/useTable'
|
|
|
+
|
|
|
+import customIndicatorDialog from '../dialog/customIndicatorDialog.vue'
|
|
|
+
|
|
|
+type CustomIndicatorDialog = typeof customIndicatorDialog
|
|
|
|
|
|
const props = withDefaults(defineProps<TableProps>(), {})
|
|
|
-const tableFieldLWidth = 300 // 长单元格的宽度
|
|
|
-const tableFieldSWidth = 200 // 短单元格的宽度
|
|
|
+
|
|
|
+const emits = defineEmits(['updateCustomIndicator'])
|
|
|
+
|
|
|
+const { isFixedField } = useTable()
|
|
|
+
|
|
|
+const tableFieldLWidth = 200 // 长单元格的宽度
|
|
|
+const tableFieldSWidth = 150 // 短单元格的宽度
|
|
|
|
|
|
// 表格数据
|
|
|
const tableData = reactive<Array<TableData>>(props.tableData)
|
|
@@ -26,33 +36,11 @@ const tableContent = ref<HTMLElement>()
|
|
|
// table的横向滚动条
|
|
|
const elScrollBarH = ref<HTMLElement>()
|
|
|
|
|
|
-//表格字段信息
|
|
|
-const tableFieldsInfo = reactive<Array<BaseFieldItem<TableFields>>>(
|
|
|
- JSON.parse(JSON.stringify(props.tableFields)),
|
|
|
-)
|
|
|
+// 表格字段信息
|
|
|
+const tableFieldsInfo = reactive<Array<TableFields>>([])
|
|
|
|
|
|
// 自定义指标的字段信息,为了不影响原本的表格字段信息
|
|
|
-const indicatorFields = reactive<Array<BaseFieldItem<TableFields>>>(
|
|
|
- JSON.parse(JSON.stringify(props.tableFields)),
|
|
|
-)
|
|
|
-
|
|
|
-// 自定义指标中需要固定的指标
|
|
|
-const fixedIndicator = computed<TableFields[]>(() => {
|
|
|
- let result: TableFields[] = []
|
|
|
- indicatorFields.forEach(item => {
|
|
|
- result.push(...item.children.filter(item => item.fixed))
|
|
|
- })
|
|
|
- return result
|
|
|
-})
|
|
|
-
|
|
|
-// 没有被固定的指标
|
|
|
-const unFixedIndicator = computed<TableFields[]>(() => {
|
|
|
- let result: TableFields[] = []
|
|
|
- indicatorFields.forEach(item => {
|
|
|
- result.push(...item.children.filter(item => !item.fixed && item.state))
|
|
|
- })
|
|
|
- return result
|
|
|
-})
|
|
|
+const indicatorFields = reactive<Array<BaseFieldItem<TableFields>>>([])
|
|
|
|
|
|
// 表格整体容器
|
|
|
const tableContainer = ref<HTMLElement>()
|
|
@@ -80,9 +68,6 @@ const filterFields = ref<Array<any>>([])
|
|
|
// 批量操作选中的值
|
|
|
const batchOper = ref<string>()
|
|
|
|
|
|
-// 自定义指标的展示状态
|
|
|
-const customIndicatorVisible = ref<boolean>(false)
|
|
|
-
|
|
|
// 批量操作的选项数组
|
|
|
const batchOperList = reactive<
|
|
|
Array<{
|
|
@@ -101,10 +86,58 @@ const batchOperList = reactive<
|
|
|
])
|
|
|
|
|
|
/**
|
|
|
+ * @description: 初始化自定义指标的字段信息
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const initIndicatorFields = () => {
|
|
|
+ resetReactive(indicatorFields)
|
|
|
+ indicatorFields.splice(
|
|
|
+ 0,
|
|
|
+ indicatorFields.length,
|
|
|
+ ...JSON.parse(JSON.stringify(props.tableFields)),
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 初始化表格字段,把所有字段都放到一个数组中
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const initTableFields = () => {
|
|
|
+ resetReactive(tableFieldsInfo)
|
|
|
+ props.tableFields.forEach(item => {
|
|
|
+ item.children.forEach(item => {
|
|
|
+ tableFieldsInfo.push(item)
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 自定义指标中需要固定的指标
|
|
|
+const fixedIndicator = computed<TableFields[]>(() => {
|
|
|
+ let result: TableFields[] = []
|
|
|
+ indicatorFields.forEach(item => {
|
|
|
+ result.push(...item.children.filter(item => item.fixed))
|
|
|
+ })
|
|
|
+ return result
|
|
|
+})
|
|
|
+
|
|
|
+// 没有被固定的指标
|
|
|
+const unFixedIndicator = computed<TableFields[]>(() => {
|
|
|
+ let result: TableFields[] = []
|
|
|
+ indicatorFields.forEach(item => {
|
|
|
+ result.push(...item.children.filter(item => !item.fixed && item.state))
|
|
|
+ })
|
|
|
+ // return JSON.parse(JSON.stringify(result))
|
|
|
+ return result
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
* @description: 初始化查询表单
|
|
|
* @return {*}
|
|
|
*/
|
|
|
const initfilterForm = () => {
|
|
|
+ // filterFormData
|
|
|
+ resetReactive(filterFormData)
|
|
|
+ resetReactive(filterFieldsStateList)
|
|
|
for (let [k, v] of Object.entries(props.filtersInfo)) {
|
|
|
// 表单给初始值
|
|
|
filterFormData[k] = v.value ? v.value : ''
|
|
@@ -123,6 +156,7 @@ const initfilterForm = () => {
|
|
|
* @return {*}
|
|
|
*/
|
|
|
const initFilterFields = () => {
|
|
|
+ resetReactive(filterFields.value)
|
|
|
filterFieldsStateList.forEach(v => {
|
|
|
filterFields.value.push(v.value)
|
|
|
})
|
|
@@ -134,7 +168,6 @@ const initFilterFields = () => {
|
|
|
*/
|
|
|
const resetFilterForm = () => {
|
|
|
filterFormRef.value?.resetFields()
|
|
|
- console.log(filterFormData)
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -209,30 +242,35 @@ const setElScrollBar = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @description: 判断当前字段是否是需要固定的字段
|
|
|
- * @param {*} info 字段信息
|
|
|
- * @return {boolean}
|
|
|
- */
|
|
|
-const isFixedField = (info: BaseFieldInfo): boolean => {
|
|
|
- return props.fixedFields.includes(info.name)
|
|
|
-}
|
|
|
+const customIndicatorDialogRef = ref<CustomIndicatorDialog>()
|
|
|
|
|
|
/**
|
|
|
* @description: 展示自定义指标弹窗
|
|
|
* @return {*}
|
|
|
*/
|
|
|
const showCustomIndicator = () => {
|
|
|
- customIndicatorVisible.value = true
|
|
|
+ if (!customIndicatorDialogRef.value) return
|
|
|
+ customIndicatorDialogRef.value.showCustomIndicator()
|
|
|
}
|
|
|
|
|
|
-initfilterForm()
|
|
|
-initFilterFields()
|
|
|
+/**
|
|
|
+ * @description: 应用自定义指标
|
|
|
+ * @param {*} newTableFieldsInfo 新的表格字段信息
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const applyCustomIndicator = (newTableFieldsInfo: Array<TableFields>) => {
|
|
|
+ tableFieldsInfo.splice(0, tableFieldsInfo.length, ...newTableFieldsInfo)
|
|
|
+ emits('updateCustomIndicator', indicatorFields)
|
|
|
+}
|
|
|
|
|
|
watch(
|
|
|
() => props.tableData,
|
|
|
newData => {
|
|
|
tableData.splice(0, tableData.length, ...newData)
|
|
|
+ initfilterForm()
|
|
|
+ initFilterFields()
|
|
|
+ initTableFields()
|
|
|
+ initIndicatorFields()
|
|
|
},
|
|
|
{
|
|
|
deep: true,
|
|
@@ -241,24 +279,6 @@ watch(
|
|
|
onMounted(() => {
|
|
|
initScroll()
|
|
|
})
|
|
|
-
|
|
|
-// 自定义指标搜索值
|
|
|
-const indicatorSearch = ref<string>('')
|
|
|
-
|
|
|
-/**
|
|
|
- * @description: 跳转到指定的指标区域
|
|
|
- * @param {*} name 标签分段的字段名
|
|
|
- * @return {*}
|
|
|
- */
|
|
|
-const goToIndicator = (name: string) => {
|
|
|
- let el = document.querySelector(`div[data-anchor="${name}"]`) as HTMLElement
|
|
|
- console.log(el)
|
|
|
- el.scrollIntoView({ behavior: 'smooth' })
|
|
|
-}
|
|
|
-
|
|
|
-const indicatorOpen = () => {}
|
|
|
-
|
|
|
-const indicatorClose = () => {}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
@@ -396,101 +416,32 @@ const indicatorClose = () => {}
|
|
|
border
|
|
|
:scrollbar-always-on="true"
|
|
|
>
|
|
|
- <template v-for="k in tableFieldsInfo">
|
|
|
- <template v-for="item in k.children" :key="item.name">
|
|
|
- <el-table-column
|
|
|
- :width="
|
|
|
- isFixedField(item) ? tableFieldLWidth : tableFieldSWidth
|
|
|
- "
|
|
|
- :fixed="isFixedField(item)"
|
|
|
- :prop="item.name"
|
|
|
- :label="item.label"
|
|
|
- v-if="item.state"
|
|
|
- >
|
|
|
- </el-table-column>
|
|
|
- </template>
|
|
|
+ <template v-for="item in tableFieldsInfo" :key="item.name">
|
|
|
+ <el-table-column
|
|
|
+ :width="
|
|
|
+ isFixedField(props.fixedFields, item)
|
|
|
+ ? tableFieldLWidth
|
|
|
+ : tableFieldSWidth
|
|
|
+ "
|
|
|
+ :fixed="isFixedField(props.fixedFields, item)"
|
|
|
+ :prop="item.name"
|
|
|
+ :label="item.label"
|
|
|
+ v-if="item.state"
|
|
|
+ >
|
|
|
+ </el-table-column>
|
|
|
</template>
|
|
|
</el-table>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="customIndicatorContainer">
|
|
|
- <el-dialog
|
|
|
- v-model="customIndicatorVisible"
|
|
|
- title="自定义指标"
|
|
|
- width="1096"
|
|
|
- :append-to-body="true"
|
|
|
- :align-center="true"
|
|
|
- @open="indicatorOpen"
|
|
|
- @close="indicatorClose"
|
|
|
- class="el-dialog"
|
|
|
- >
|
|
|
- <div class="indicatorBox">
|
|
|
- <div class="topWrapper">
|
|
|
- <el-input
|
|
|
- v-model="indicatorSearch"
|
|
|
- style="width: 240px"
|
|
|
- placeholder="Please Input"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div class="indicatorWrapper">
|
|
|
- <div class="indicatorSider">
|
|
|
- <div
|
|
|
- @click="goToIndicator(item.name)"
|
|
|
- v-for="item in indicatorFields"
|
|
|
- class="indicatorCategory"
|
|
|
- >
|
|
|
- {{ item.label }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="indicatorContent">
|
|
|
- <div
|
|
|
- v-for="field in indicatorFields"
|
|
|
- :data-anchor="field.name"
|
|
|
- class="indicatorBlock"
|
|
|
- >
|
|
|
- <div class="indicatorGroup">
|
|
|
- <span>{{ field.label }}</span>
|
|
|
- </div>
|
|
|
- <el-row class="indicatorItem">
|
|
|
- <el-col :span="8" v-for="item in field.children"
|
|
|
- ><el-checkbox
|
|
|
- style="margin-bottom: 16px"
|
|
|
- v-model="item.state"
|
|
|
- :label="item.label"
|
|
|
- /></el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="dragWrapper">
|
|
|
- <div class="dragHeader">
|
|
|
- <div class="dragTitle">已选指标</div>
|
|
|
- <div class="dragDes">拖拽可自定义指标顺序</div>
|
|
|
- <div class="fixedIndicator">
|
|
|
- <div class="dragBlock" v-for="item in fixedIndicator">
|
|
|
- {{ item.label }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="dragSepreate">以上指标将横向固定</div>
|
|
|
- </div>
|
|
|
- <div class="dragContent">
|
|
|
- <div class="dragBlock" v-for="item in unFixedIndicator">
|
|
|
- {{ item.label }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <div class="dialog-footer">
|
|
|
- <el-button @click="customIndicatorVisible = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="customIndicatorVisible = false">
|
|
|
- 应用
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
- </div>
|
|
|
+ <customIndicatorDialog
|
|
|
+ :indicator-fields="indicatorFields"
|
|
|
+ :un-fixed-indicator="unFixedIndicator"
|
|
|
+ :fixed-indicator="fixedIndicator"
|
|
|
+ :table-fields-info="tableFieldsInfo"
|
|
|
+ :fixed-fields="props.fixedFields"
|
|
|
+ ref="customIndicatorDialogRef"
|
|
|
+ @update-fields="applyCustomIndicator"
|
|
|
+ ></customIndicatorDialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -577,150 +528,4 @@ const indicatorClose = () => {}
|
|
|
// position: fixed !important;
|
|
|
bottom: 5px;
|
|
|
}
|
|
|
-
|
|
|
-.indicatorBox {
|
|
|
- position: relative;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-.topWrapper {
|
|
|
- margin-bottom: 16px;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorWrapper {
|
|
|
- display: flex;
|
|
|
- width: 832px;
|
|
|
- height: 516px;
|
|
|
- border: 1px solid #eaebec;
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorSider {
|
|
|
- flex-shrink: 0;
|
|
|
- width: 160px;
|
|
|
- overflow: auto;
|
|
|
- border-right: 1px solid #eaebec;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorCategory {
|
|
|
- padding-left: 16px;
|
|
|
- font-size: 14px;
|
|
|
- line-height: 40px;
|
|
|
- color: #333;
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorCategoryActive {
|
|
|
- color: #197afb;
|
|
|
- background-color: #d6eaff;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorContent {
|
|
|
- width: 672px;
|
|
|
- overflow: auto;
|
|
|
- scroll-behavior: smooth;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorGroup {
|
|
|
- color: rgb(51, 51, 51);
|
|
|
- color-scheme: light;
|
|
|
- display: block;
|
|
|
- font-weight: 700;
|
|
|
- font-size: 14px;
|
|
|
- word-break: break-all;
|
|
|
- -webkit-font-smoothing: subpixel-antialiased;
|
|
|
- margin-bottom: 16px;
|
|
|
-}
|
|
|
-
|
|
|
-.indicatorBlock {
|
|
|
- width: 100%;
|
|
|
- padding: 16px 0 0 24px;
|
|
|
- border-bottom: 1px solid #eaebec;
|
|
|
- // display: flex;
|
|
|
- // flex-wrap: wrap;
|
|
|
-}
|
|
|
-
|
|
|
-.dragWrapper {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- right: 0;
|
|
|
- flex-shrink: 0;
|
|
|
- width: 216px;
|
|
|
- height: 565px;
|
|
|
- padding: 10px 0;
|
|
|
- overflow: auto;
|
|
|
- background-color: #f8f8f9;
|
|
|
- border-right: 1px solid #eaebec;
|
|
|
-}
|
|
|
-
|
|
|
-.dragHeader,
|
|
|
-.dragContent {
|
|
|
- padding: 0 16px;
|
|
|
-}
|
|
|
-
|
|
|
-.dragBlock {
|
|
|
- position: relative;
|
|
|
- width: 184px;
|
|
|
- height: 40px;
|
|
|
- padding: 0 30px 0 36px;
|
|
|
- overflow: hidden;
|
|
|
- line-height: 40px;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
- background-color: #fff;
|
|
|
- border-bottom: 1px solid #e8eaec;
|
|
|
-}
|
|
|
-
|
|
|
-.dragSepreate {
|
|
|
- position: relative;
|
|
|
- margin: 16px 0 0;
|
|
|
- font-size: 12px;
|
|
|
- color: #999;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-
|
|
|
-.dragWrapper .dragSepreate::before {
|
|
|
- position: absolute;
|
|
|
- top: 9px;
|
|
|
- left: 0;
|
|
|
- width: 32px;
|
|
|
- height: 1px;
|
|
|
- content: '';
|
|
|
- background-color: #e8eaec;
|
|
|
-}
|
|
|
-.dragWrapper .dragSepreate::after {
|
|
|
- position: absolute;
|
|
|
- top: 9px;
|
|
|
- right: 0;
|
|
|
- width: 32px;
|
|
|
- height: 1px;
|
|
|
- content: '';
|
|
|
- background-color: #e8eaec;
|
|
|
-}
|
|
|
-
|
|
|
-.dragWrapper .dragBlock::before {
|
|
|
- position: absolute;
|
|
|
- top: 16px;
|
|
|
- left: 12px;
|
|
|
- width: 16px;
|
|
|
- height: 2px;
|
|
|
- content: '';
|
|
|
- background-color: #999;
|
|
|
-}
|
|
|
-.dragWrapper .dragBlock::after {
|
|
|
- position: absolute;
|
|
|
- bottom: 16px;
|
|
|
- left: 12px;
|
|
|
- width: 16px;
|
|
|
- height: 2px;
|
|
|
- content: '';
|
|
|
- background-color: #999;
|
|
|
-}
|
|
|
-
|
|
|
-.dragContent {
|
|
|
- margin-top: 16px;
|
|
|
- overflow-x: hidden;
|
|
|
- overflow-y: auto;
|
|
|
-}
|
|
|
</style>
|