|
|
@ -6,9 +6,9 @@ |
|
|
|
v-model:pagination="state.pagination" |
|
|
|
flat |
|
|
|
binary-state-sort |
|
|
|
:no-data-label="state.noDataLabel" |
|
|
|
:no-data-label="$t('tip.noData')" |
|
|
|
:hide-no-data="true" |
|
|
|
:loading-label="state.loadingLabel" |
|
|
|
:loading-label="$t('tip.dataLoading')" |
|
|
|
v-bind="attrs" |
|
|
|
:selection="selectionComputed" |
|
|
|
separator="cell" |
|
|
@ -27,15 +27,15 @@ |
|
|
|
<template #top="scope"> |
|
|
|
<q-resize-observer debounce="100" @resize="onResize" /> |
|
|
|
<div class="col"> |
|
|
|
<w-form ref="queryFormRef" v-bind="props.queryFormAttrs" :fields="table.queryFormFields" :cols-num="queryFormColsNum"></w-form> |
|
|
|
<w-form ref="queryFormRef" v-bind="props.queryFormAttrs" :fields="queryFormFieldsComputed" :cols-num="queryFormColsNum"></w-form> |
|
|
|
<div |
|
|
|
v-if="title || buttons_.length > 0 || configButton || table.queryFormFields.length > 0" |
|
|
|
class="flex flex-nowrap items-end" |
|
|
|
:class="table.queryFormFields.length > 0 ? 'pt-2.5' : ''" |
|
|
|
> |
|
|
|
<div class="flex-none">{{ title }}</div> |
|
|
|
<div class="flex-none">{{ $t(title) }}</div> |
|
|
|
<div class="flex-1"> |
|
|
|
<w-toolbar :dense="denseToolbarComputed" v-bind="toolbarConfigure" :buttons="buttons_" :grid="instance"></w-toolbar> |
|
|
|
<w-toolbar :dense="denseToolbarComputed" v-bind="toolbarConfigure" :buttons="toolbarButtonsComputed" :grid="instance"></w-toolbar> |
|
|
|
</div> |
|
|
|
<div v-if="configButton" class="flex-none pl-1"> |
|
|
|
<q-btn round dense :size="denseToolbarComputed ? '13px' : undefined" icon="manage_accounts" unelevated outline> |
|
|
@ -74,7 +74,7 @@ |
|
|
|
</q-th> |
|
|
|
</q-tr> |
|
|
|
<q-tr v-if="table.rows.length === 0" :style="noDataTrHeightComputed" class="noDataTr"> |
|
|
|
<q-td :colspan="noDataTrColspanComputed" align="center" valian="middle"><q-icon size="2em" :name="IconEnum.提示" />{{ state.noDataLabel }}</q-td> |
|
|
|
<q-td :colspan="noDataTrColspanComputed" align="center" valian="middle"><q-icon size="2em" :name="IconEnum.提示" />{{ $t('tip.noData') }}</q-td> |
|
|
|
</q-tr> |
|
|
|
</template> |
|
|
|
<template v-else> |
|
|
@ -99,7 +99,7 @@ |
|
|
|
</template> |
|
|
|
</q-tr> |
|
|
|
<q-tr v-if="table.rows.length === 0" :style="noDataTrHeightComputed" class="noDataTr"> |
|
|
|
<q-td :colspan="noDataTrColspanComputed" align="center" valian="middle"><q-icon size="2em" :name="IconEnum.提示" />{{ state.noDataLabel }}</q-td> |
|
|
|
<q-td :colspan="noDataTrColspanComputed" align="center" valian="middle"><q-icon size="2em" :name="IconEnum.提示" />{{ $t('tip.noData') }}</q-td> |
|
|
|
</q-tr> |
|
|
|
</template> |
|
|
|
</template> |
|
|
@ -221,12 +221,7 @@ |
|
|
|
</div> |
|
|
|
</template> --> |
|
|
|
</q-table> |
|
|
|
<w-dialog |
|
|
|
ref="dialogRef" |
|
|
|
v-bind="editor.dialog" |
|
|
|
:title="dialog.dialogTitle" |
|
|
|
:buttons="editor.dialog?.buttons ? [...editor.dialog.buttons, ...dialog.dialogButtons] : dialog.dialogButtons" |
|
|
|
> |
|
|
|
<w-dialog ref="dialogRef" v-bind="editor.dialog" :title="dialog.dialogTitle" :buttons="dialogButtonsComputed"> |
|
|
|
<w-form ref="dialogFormRef" v-bind="editor.form" class="pt-1.5 px-1.5"></w-form> |
|
|
|
</w-dialog> |
|
|
|
<w-drawer ref="drawerRef" :title="$t('action.view')" v-bind="viewer.drawer"> |
|
|
@ -238,9 +233,9 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
|
import { ref, reactive, computed, onMounted, onUpdated, nextTick, toRaw, useAttrs, getCurrentInstance, provide, watchEffect, watch } from 'vue'; |
|
|
|
import { ref, reactive, computed, onMounted, nextTick, toRaw, useAttrs, getCurrentInstance, provide, watchEffect, watch, onUpdated } from 'vue'; |
|
|
|
import { useI18n } from 'vue-i18n'; |
|
|
|
import { axios, Environment, NotifyManager, TreeBuilder, VueTools, Tools } from '@/platform'; |
|
|
|
import { axios, Environment, NotifyManager, TreeBuilder, VueTools, Tools, eventBus } from '@/platform'; |
|
|
|
import { useQuasar, getCssVar, exportFile } from 'quasar'; |
|
|
|
import { IconEnum } from '@/platform/enums'; |
|
|
|
import { arrayToMap, OperatorTypeEnum, isEmpty, PageStatusEnum } from '@/platform/components/utils'; |
|
|
@ -427,6 +422,7 @@ const dialogFormRef = ref(); |
|
|
|
const infoRef = ref(); |
|
|
|
const tableColumns = ref(props.columns); |
|
|
|
const tableColumnsMap = ref(arrayToMap('name', tableColumns.value)); |
|
|
|
const localFlag = ref(false); |
|
|
|
const columnStyle = (item: any) => { |
|
|
|
let style = ''; |
|
|
|
if (Tools.hasOwnProperty(item, 'style')) { |
|
|
@ -481,6 +477,27 @@ watch( |
|
|
|
handlerMoreRowColumnTitle(); |
|
|
|
}, |
|
|
|
); |
|
|
|
eventBus.on('onLocaleChanged', (local) => { |
|
|
|
nextTick(() => { |
|
|
|
table.columns = extractTableColumns.value; |
|
|
|
handlerQueryFormShowField(); |
|
|
|
localFlag.value = !localFlag.value; |
|
|
|
// 重构内置按钮 label |
|
|
|
Object.keys(buttonObj).forEach((btn) => { |
|
|
|
if (typeof buttonObj[btn] === 'object' && buttonObj[btn].labelI18nKey) { |
|
|
|
buttonObj[btn].label = t(buttonObj[btn].labelI18nKey); |
|
|
|
} |
|
|
|
}); |
|
|
|
handleToolbarActions(); |
|
|
|
// 重构内置新增编辑窗口中的按钮 label |
|
|
|
dialog.dialogButtons[0].label = t(dialog.dialogButtons[0].labelI18nKey); |
|
|
|
}); |
|
|
|
}); |
|
|
|
// onUpdated(() => { |
|
|
|
// nextTick(() => { |
|
|
|
// console.info('onupdated.buttonObj', buttonObj); |
|
|
|
// }); |
|
|
|
// }); |
|
|
|
const queryFormFieldsMap = arrayToMap('name', props.queryFormFields); |
|
|
|
const rowKey_ = '_rowKey_'; // 行数据中前端附加的UUID字段名 |
|
|
|
const url = { |
|
|
@ -502,6 +519,15 @@ const titleScopeHandler = (column: any, scope: any) => { |
|
|
|
return undefined; |
|
|
|
}; |
|
|
|
|
|
|
|
const queryFormFieldsComputed = computed(() => { |
|
|
|
localFlag.value; |
|
|
|
return table.queryFormFields; |
|
|
|
}); |
|
|
|
const toolbarButtonsComputed = computed(() => { |
|
|
|
localFlag.value; |
|
|
|
return buttons_; |
|
|
|
}); |
|
|
|
|
|
|
|
const table = reactive({ |
|
|
|
tickedField: props.tickedField, |
|
|
|
selectedField: props.selectedField, |
|
|
@ -525,37 +551,13 @@ const table = reactive({ |
|
|
|
}); |
|
|
|
provide('table', table); |
|
|
|
|
|
|
|
const expandIcon = computed(() => { |
|
|
|
const expandIconComputed = computed(() => { |
|
|
|
return table.treeExpand ? 'expand_less' : 'expand_more'; |
|
|
|
}); |
|
|
|
const expandLabel = computed(() => { |
|
|
|
return table.treeExpand ? '全部收起' : '全部展开'; |
|
|
|
const expandLabelI18nKeyComputed = computed(() => { |
|
|
|
return table.treeExpand ? 'action.expandUp' : 'action.expandDown'; |
|
|
|
}); |
|
|
|
|
|
|
|
/** |
|
|
|
* 内置按钮枚举 |
|
|
|
*/ |
|
|
|
enum ButtonEnum { |
|
|
|
query = 'query', //查询 |
|
|
|
moreQuery = 'moreQuery', //更多查询 |
|
|
|
reset = 'reset', //重置 |
|
|
|
refresh = 'refresh', //刷新 |
|
|
|
add = 'add', //新增 |
|
|
|
edit = 'edit', //编辑 |
|
|
|
clone = 'clone', //复制 |
|
|
|
remove = 'remove', //删除 |
|
|
|
removeAll = 'removeAll', //删除全部 |
|
|
|
view = 'view', //查看 |
|
|
|
export = 'export', //导出 |
|
|
|
addTop = 'addTop', // 新增顶级节点 |
|
|
|
addChild = 'addChild', // 新增子节点 |
|
|
|
expand = 'expand', // 展开?收起 所有节点 |
|
|
|
resetDefaultValues = 'resetDefaultValues', // 恢复默认值 |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 内置按钮 |
|
|
|
*/ |
|
|
|
const remove = () => { |
|
|
|
const ids = <any>[]; |
|
|
|
if (getTickedRowsComputed.value && getTickedRowsComputed.value.length > 0) { |
|
|
@ -597,19 +599,21 @@ const resetDefaultValues = () => { |
|
|
|
NotifyManager.error(t('tip.operationFailed')); |
|
|
|
}); |
|
|
|
}; |
|
|
|
const buttonObj = { |
|
|
|
const buttonObj = reactive({ |
|
|
|
separator: 'separator', |
|
|
|
query: { |
|
|
|
name: ButtonEnum.query, |
|
|
|
name: 'query', |
|
|
|
icon: IconEnum.查询, |
|
|
|
labelI18nKey: 'action.query', |
|
|
|
label: t('action.query'), |
|
|
|
click: () => { |
|
|
|
refresh(); |
|
|
|
}, |
|
|
|
}, |
|
|
|
moreQuery: { |
|
|
|
name: ButtonEnum.moreQuery, |
|
|
|
name: 'moreQuery', |
|
|
|
icon: IconEnum.更多查询, |
|
|
|
labelI18nKey: 'action.moreQueryConditions', |
|
|
|
label: t('action.moreQueryConditions'), |
|
|
|
enableIf: () => { |
|
|
|
if (props.queryFormFields.length <= table.queryFormFields.length && !table.moreQueryStatus) { |
|
|
@ -624,24 +628,27 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
reset: { |
|
|
|
name: ButtonEnum.reset, |
|
|
|
name: 'reset', |
|
|
|
icon: IconEnum.重置, |
|
|
|
labelI18nKey: 'action.reset', |
|
|
|
label: t('action.reset'), |
|
|
|
click: () => { |
|
|
|
queryFormRef.value.reset(); |
|
|
|
}, |
|
|
|
}, |
|
|
|
refresh: { |
|
|
|
name: ButtonEnum.refresh, |
|
|
|
name: 'refresh', |
|
|
|
icon: IconEnum.刷新, |
|
|
|
labelI18nKey: 'action.refresh', |
|
|
|
label: t('action.refresh'), |
|
|
|
click: () => { |
|
|
|
refresh(); |
|
|
|
}, |
|
|
|
}, |
|
|
|
add: { |
|
|
|
name: ButtonEnum.add, |
|
|
|
name: 'add', |
|
|
|
icon: IconEnum.新增, |
|
|
|
labelI18nKey: 'action.addNew', |
|
|
|
label: t('action.addNew'), |
|
|
|
click: () => { |
|
|
|
dialog.dialogTitle = t('action.addNew'); |
|
|
@ -653,8 +660,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
edit: { |
|
|
|
name: ButtonEnum.edit, |
|
|
|
name: 'edit', |
|
|
|
icon: IconEnum.编辑, |
|
|
|
labelI18nKey: 'action.edit', |
|
|
|
label: t('action.edit'), |
|
|
|
enableIf: (args) => { |
|
|
|
if (args.selected) { |
|
|
@ -677,8 +685,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
clone: { |
|
|
|
name: ButtonEnum.clone, |
|
|
|
name: 'clone', |
|
|
|
icon: 'content_copy', |
|
|
|
labelI18nKey: 'action.copy', |
|
|
|
label: t('action.copy'), |
|
|
|
enableIf: (args) => { |
|
|
|
if (args.selected) { |
|
|
@ -700,8 +709,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
remove: { |
|
|
|
name: ButtonEnum.remove, |
|
|
|
name: 'remove', |
|
|
|
icon: IconEnum.删除, |
|
|
|
labelI18nKey: 'action.remove', |
|
|
|
label: t('action.remove'), |
|
|
|
enableIf: (args) => { |
|
|
|
if (args.ticked) { |
|
|
@ -727,8 +737,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
view: { |
|
|
|
name: ButtonEnum.view, |
|
|
|
name: 'view', |
|
|
|
icon: IconEnum.查看, |
|
|
|
labelI18nKey: 'action.view', |
|
|
|
label: t('action.view'), |
|
|
|
enableIf: (args) => { |
|
|
|
if (args.selected) { |
|
|
@ -741,8 +752,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
export: { |
|
|
|
name: ButtonEnum.export, |
|
|
|
name: 'export', |
|
|
|
icon: 'file_download', |
|
|
|
labelI18nKey: 'action.export', |
|
|
|
label: t('action.export'), |
|
|
|
click: () => { |
|
|
|
const content = [tableColumns.value.map((col) => wrapCsvValue(col.label))] |
|
|
@ -767,8 +779,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
addTop: { |
|
|
|
name: ButtonEnum.addTop, |
|
|
|
name: 'addTop', |
|
|
|
icon: IconEnum.新增, |
|
|
|
labelI18nKey: 'action.addTop', |
|
|
|
label: t('action.addTop'), |
|
|
|
click: () => { |
|
|
|
dialog.dialogTitle = t('action.addTop'); |
|
|
@ -780,8 +793,9 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
addChild: { |
|
|
|
name: ButtonEnum.addChild, |
|
|
|
name: 'addChild', |
|
|
|
icon: 'playlist_add', |
|
|
|
labelI18nKey: 'action.addChild', |
|
|
|
label: t('action.addChild'), |
|
|
|
enableIf: (args) => { |
|
|
|
if (args.selected) { |
|
|
@ -799,17 +813,19 @@ const buttonObj = { |
|
|
|
}, |
|
|
|
}, |
|
|
|
expand: { |
|
|
|
name: ButtonEnum.expand, |
|
|
|
icon: expandIcon, |
|
|
|
label: expandLabel, |
|
|
|
name: 'expand', |
|
|
|
icon: expandIconComputed, |
|
|
|
labelI18nKey: expandLabelI18nKeyComputed, |
|
|
|
label: t(expandLabelI18nKeyComputed.value), |
|
|
|
click: () => { |
|
|
|
expandFun(table.rows, table.treeExpand); |
|
|
|
table.treeExpand = !table.treeExpand; |
|
|
|
}, |
|
|
|
}, |
|
|
|
resetDefaultValues: { |
|
|
|
name: ButtonEnum.resetDefaultValues, |
|
|
|
name: 'resetDefaultValues', |
|
|
|
icon: 'bi-copy', |
|
|
|
labelI18nKey: 'action.resetDefaultValues', |
|
|
|
label: t('action.resetDefaultValues'), |
|
|
|
click: (tips: boolean = true) => { |
|
|
|
if (!tips) { |
|
|
@ -826,7 +842,7 @@ const buttonObj = { |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
}); |
|
|
|
const expandFun = (arr, treeExpand) => { |
|
|
|
arr.forEach((item) => { |
|
|
|
if (props.tree && item.children && item.children.length > 0) { |
|
|
@ -857,18 +873,22 @@ const handleChildrenBtn = (arr) => { |
|
|
|
} |
|
|
|
return tempArr; |
|
|
|
}; |
|
|
|
props.toolbarActions.forEach((btn: any, index) => { |
|
|
|
if (typeof btn === 'string' && buttonObj[btn]) { |
|
|
|
buttons_.push(buttonObj[btn]); |
|
|
|
} else if (Array.isArray(btn) && btn.length > 0) { |
|
|
|
buttons_.push(handleChildrenBtn(btn)); |
|
|
|
} else if (typeof btn === 'object' && btn.extend && buttonObj[btn.extend]) { |
|
|
|
// 继承内置按钮 |
|
|
|
buttons_.push({ ...buttonObj[btn.extend], ...btn, _click: buttonObj[btn.extend].click }); |
|
|
|
} else { |
|
|
|
buttons_.push(btn); |
|
|
|
} |
|
|
|
}); |
|
|
|
const handleToolbarActions = () => { |
|
|
|
buttons_.splice(0, buttons_.length); |
|
|
|
props.toolbarActions.forEach((btn: any, index) => { |
|
|
|
if (typeof btn === 'string' && buttonObj[btn]) { |
|
|
|
buttons_.push(buttonObj[btn]); |
|
|
|
} else if (Array.isArray(btn) && btn.length > 0) { |
|
|
|
buttons_.push(handleChildrenBtn(btn)); |
|
|
|
} else if (typeof btn === 'object' && btn.extend && buttonObj[btn.extend]) { |
|
|
|
// 继承内置按钮 |
|
|
|
buttons_.push({ ...buttonObj[btn.extend], ...btn, _click: buttonObj[btn.extend].click }); |
|
|
|
} else { |
|
|
|
buttons_.push(btn); |
|
|
|
} |
|
|
|
}); |
|
|
|
}; |
|
|
|
handleToolbarActions(); |
|
|
|
|
|
|
|
const denseToolbarComputed = computed(() => { |
|
|
|
if (table.denseToolbar) { |
|
|
@ -988,6 +1008,7 @@ const dialog = reactive({ |
|
|
|
dialogButtons: [ |
|
|
|
{ |
|
|
|
icon: IconEnum.提交, |
|
|
|
labelI18nKey: 'action.submit', |
|
|
|
label: t('action.submit'), |
|
|
|
loading: false, |
|
|
|
click: () => { |
|
|
@ -996,6 +1017,12 @@ const dialog = reactive({ |
|
|
|
}, |
|
|
|
], |
|
|
|
}); |
|
|
|
const dialogButtonsComputed = computed(() => { |
|
|
|
if (props.editor?.dialog?.buttons) { |
|
|
|
return [...props.editor.dialog.buttons, ...dialog.dialogButtons]; |
|
|
|
} |
|
|
|
return dialog.dialogButtons; |
|
|
|
}); |
|
|
|
|
|
|
|
const viewInfo = reactive({ |
|
|
|
infoArray: <any>[], |
|
|
@ -1792,7 +1819,6 @@ const stickyHeaderColumn = (time = 500) => { |
|
|
|
} |
|
|
|
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableBodyPadding', bodyPadding); |
|
|
|
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableBodyHeight', (denseBodyComputed.value ? 24 : 48) + 'px'); |
|
|
|
|
|
|
|
if (denseBottomComputed.value && (!Tools.hasOwnProperty(attrs, 'hide-bottom') || attrs['hide-bottom'] === false)) { |
|
|
|
if (tableRef.value.$el.getElementsByClassName('q-table__bottom').length > 0) { |
|
|
|
tableRef.value.$el.getElementsByClassName('q-table__bottom')[0].style.setProperty('--tableBottomHeight', 33 + 'px'); |
|
|
|