Browse Source
1、dbClickOperation修改为配置按钮的name,触发事件为按钮的click。 2、表格第一列选择框全选只有勾选未选中与勾选单条行为不一致。 3、提供表格编辑模式,双击或者点击按钮直接在表格上编辑。main
43 changed files with 3763 additions and 3737 deletions
@ -0,0 +1,351 @@ |
|||
<template> |
|||
<template v-if="props.grid.props.tree"> |
|||
<TreeGridRow |
|||
:ref="(el) => setTreeRowComponentRef(el, scope.row)" |
|||
:grid="props.grid" |
|||
:columns-map="props.tableColumnsMap" |
|||
:row="props.scope.row" |
|||
:cols="props.scope.cols" |
|||
:row-key="props.rowKeyName" |
|||
:grid-row-click="props.rowClick" |
|||
:grid-row-db-click="props.rowDbClick" |
|||
:after-row-draggable="props.afterRowDraggable" |
|||
:get-row="props.getRow" |
|||
:url="props.url" |
|||
:get-row-component-refs="getRowComponentRefs" |
|||
:set-old-value="setOldValue" |
|||
:no-data-tr-colspan="noDataTrColspan" |
|||
></TreeGridRow> |
|||
</template> |
|||
<template v-else> |
|||
<q-tr |
|||
ref="trRef" |
|||
:class="props.scope.row[table.selectedField] ? 'selected' : ''" |
|||
:props="props.scope" |
|||
:draggable=" |
|||
((typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) || |
|||
(typeof props.grid.props.draggable === 'string' && props.grid.props.draggable === 'local')) && |
|||
table.bodyEditStatus === 'none' |
|||
? true |
|||
: false |
|||
" |
|||
@click.stop="rowClick($event, scope.row, scope.rowIndex)" |
|||
@dblclick.stop="rowDbClick($event, scope.row, scope.rowIndex)" |
|||
@dragenter="onDragEnter($event, scope)" |
|||
@dragleave="onDragLeave" |
|||
@dragover="onDragOver($event, scope)" |
|||
@drop="onDrop($event, scope)" |
|||
@dragstart="onDragStart($event, scope)" |
|||
> |
|||
<q-td v-if="table.checkboxSelection" class="text-center" style="padding: 0; width: 50px"> |
|||
<q-checkbox |
|||
v-model="props.getRow(table.rows, scope.row[props.rowKeyName], false)[table.tickedField]" |
|||
flat |
|||
:dense="props.denseBody" |
|||
@update:model-value="updateTicked($event, scope.row)" |
|||
/> |
|||
</q-td> |
|||
<template v-for="(col, index) in scope.cols" :key="index"> |
|||
<GridTd |
|||
:ref="(el) => setComponentRef(el, scope.row, col)" |
|||
:grid="props.grid" |
|||
:get-row="props.getRow" |
|||
:row-key-name="props.rowKeyName" |
|||
:scope="scope" |
|||
:col="col" |
|||
:value="col.value" |
|||
:is-selected-row="isSelectedRowComputed" |
|||
></GridTd> |
|||
</template> |
|||
</q-tr> |
|||
<GridEditToolbar |
|||
:grid="props.grid" |
|||
:url="props.url" |
|||
:row="props.scope.row" |
|||
:row-key-name="props.rowKeyName" |
|||
:get-row="props.getRow" |
|||
:get-row-component-refs="getRowComponentRefs" |
|||
:set-old-value="setOldValue" |
|||
:no-data-tr-colspan="noDataTrColspan" |
|||
></GridEditToolbar> |
|||
</template> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { computed, inject, ref, toRaw } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
import TreeGridRow from './TreeGridRow.vue'; |
|||
import GridTd from './GridTd.vue'; |
|||
import GridEditToolbar from './GridEditToolbar.vue'; |
|||
|
|||
const trRef = ref(); |
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
url: { |
|||
// 表格所有的url |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
scope: { |
|||
// 顶部插槽属性 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
tableColumnsMap: { |
|||
type: Map, |
|||
default: () => { |
|||
return new Map(); |
|||
}, |
|||
}, |
|||
rowKeyName: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
rowClick: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
rowDbClick: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
afterRowDraggable: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
denseBody: { |
|||
type: Boolean, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
getRow: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
setOldValue: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
noDataTrColspan: { |
|||
type: Number, |
|||
default: () => { |
|||
return 0; |
|||
}, |
|||
}, |
|||
}); |
|||
const table = inject('table'); |
|||
|
|||
const componentRef = ref({}); |
|||
const getRowComponentRefs = (rowKey: string | Array<string>) => { |
|||
const refs = <any>[]; |
|||
if (!Tools.isEmpty(componentRef.value)) { |
|||
const filterResult = Object.keys(componentRef.value).filter((item) => { |
|||
if (typeof rowKey === 'string') { |
|||
return item.startsWith(rowKey + '_'); |
|||
} else { |
|||
return true; |
|||
} |
|||
}); |
|||
if (filterResult.length > 0) { |
|||
filterResult.forEach((key) => { |
|||
refs.push(componentRef.value[key]); |
|||
}); |
|||
} |
|||
} |
|||
return refs; |
|||
}; |
|||
|
|||
const setComponentRef = (el, row, col) => { |
|||
if (el && !Tools.isEmpty(col.type)) { |
|||
componentRef.value[row[props.rowKeyName] + '_' + col.name] = el; |
|||
} |
|||
}; |
|||
|
|||
const setTreeRowComponentRef = (el, row) => { |
|||
if (el && !Tools.isEmpty(row)) { |
|||
componentRef.value[row[props.rowKeyName] + '_'] = el; |
|||
} |
|||
}; |
|||
|
|||
const isSelectedRowComputed = computed(() => { |
|||
const selected = props.grid.getSelectedRow(); |
|||
if (!Tools.isEmpty(selected)) { |
|||
return props.scope.row[props.rowKeyName] === props.grid.getSelectedRow()[props.rowKeyName]; |
|||
} |
|||
return false; |
|||
}); |
|||
|
|||
// 得到表格数据行的中间高度 |
|||
const gridTrMiddleHeightComputed = computed(() => { |
|||
if (trRef?.value) { |
|||
return trRef.value.$el.offsetHeight / 2; |
|||
} else { |
|||
return (table.dense || table.denseBody ? 24 : 48) / 2; |
|||
} |
|||
}); |
|||
|
|||
// 拖拽开始 |
|||
const onDragStart = (e, scope) => { |
|||
const currPageIndex = table.rows.findIndex((item) => { |
|||
return item[props.rowKeyName] === scope.row[props.rowKeyName]; |
|||
}); |
|||
const currPageStartIndex = scope.rowIndex - currPageIndex; |
|||
if (props.grid.props.pageable) { |
|||
table.dragRow = { row: { ...scope.row }, rowIndex: scope.rowIndex, currPageIndex: currPageIndex, currPageStartIndex }; |
|||
} else { |
|||
table.dragRow = { row: { ...scope.row }, rowIndex: scope.rowIndex, currPageIndex: scope.rowIndex, currPageStartIndex }; |
|||
} |
|||
e.dataTransfer.dropEffect = 'move'; |
|||
}; |
|||
const addDragTopStyle = (e) => { |
|||
if (e.target?.parentNode?.children) { |
|||
for (let i = 0; i < e.target.parentNode.children.length; i++) { |
|||
e.target.parentNode.children[i].style.borderTopWidth = '2px'; |
|||
e.target.parentNode.children[i].style.borderTopStyle = 'dashed'; |
|||
e.target.parentNode.children[i].style.borderTopColor = 'orange'; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const removeDragTopStyle = (e) => { |
|||
if (e.target?.parentNode?.children) { |
|||
for (let i = 0; i < e.target.parentNode.children.length; i++) { |
|||
e.target.parentNode.children[i].style.borderTopWidth = ''; |
|||
e.target.parentNode.children[i].style.borderTopStyle = ''; |
|||
e.target.parentNode.children[i].style.borderTopColor = ''; |
|||
} |
|||
} |
|||
}; |
|||
const addDragBottomStyle = (e) => { |
|||
if (e.target?.parentNode?.children) { |
|||
for (let i = 0; i < e.target.parentNode.children.length; i++) { |
|||
e.target.parentNode.children[i].style.borderBottomWidth = '2px'; |
|||
e.target.parentNode.children[i].style.borderBottomStyle = 'dashed'; |
|||
e.target.parentNode.children[i].style.borderBottomColor = 'orange'; |
|||
} |
|||
} |
|||
}; |
|||
const removeDragBottomStyle = (e) => { |
|||
if (e.target?.parentNode?.children) { |
|||
for (let i = 0; i < e.target.parentNode.children.length; i++) { |
|||
e.target.parentNode.children[i].style.borderBottomWidth = ''; |
|||
e.target.parentNode.children[i].style.borderBottomStyle = ''; |
|||
e.target.parentNode.children[i].style.borderBottomColor = ''; |
|||
} |
|||
} |
|||
}; |
|||
// 拖拽至可放置区域触发 |
|||
const onDragEnter = (e, scope) => { |
|||
if (table.dragRow.rowIndex !== scope.rowIndex && table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) { |
|||
// 最后一行 |
|||
addDragBottomStyle(e); |
|||
} else if (table.dragRow.rowIndex !== scope.rowIndex) { |
|||
addDragTopStyle(e); |
|||
} |
|||
}; |
|||
// 拖拽至不可放置区域触发 |
|||
const onDragLeave = (e) => { |
|||
removeDragTopStyle(e); |
|||
removeDragBottomStyle(e); |
|||
}; |
|||
// 拖拽过程触发 |
|||
const onDragOver = (e, scope) => { |
|||
if ( |
|||
e.offsetY >= gridTrMiddleHeightComputed.value && |
|||
table.dragRow.rowIndex !== scope.rowIndex && |
|||
table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1 |
|||
) { |
|||
removeDragTopStyle(e); |
|||
addDragBottomStyle(e); |
|||
} else if ( |
|||
e.offsetY < gridTrMiddleHeightComputed.value && |
|||
table.dragRow.rowIndex !== scope.rowIndex && |
|||
table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1 |
|||
) { |
|||
removeDragBottomStyle(e); |
|||
addDragTopStyle(e); |
|||
} |
|||
e.preventDefault(); |
|||
}; |
|||
// 拖拽放置时触发 |
|||
const onDrop = (e, scope) => { |
|||
e.preventDefault(); |
|||
if (table.dragRow.rowIndex === scope.rowIndex) { |
|||
return; |
|||
} |
|||
const dragRow = table.dragRow.row; |
|||
const currPageStartIndex = table.dragRow.currPageStartIndex; |
|||
table.rows.splice(table.dragRow.currPageIndex, 1); |
|||
if (e.offsetY < gridTrMiddleHeightComputed.value && table.dragRow.rowIndex < scope.rowIndex) { |
|||
table.rows.splice(scope.rowIndex - currPageStartIndex - 1, 0, dragRow); |
|||
} else { |
|||
table.rows.splice(scope.rowIndex - currPageStartIndex, 0, dragRow); |
|||
} |
|||
removeDragTopStyle(e); |
|||
removeDragBottomStyle(e); |
|||
|
|||
const updateData = <any>[]; |
|||
|
|||
table.rows.forEach((item, index) => { |
|||
if (!Tools.isEmpty(item)) { |
|||
item[props.grid.props.orderBy] = currPageStartIndex + index + 1; |
|||
updateData.push(toRaw(item)); |
|||
} |
|||
}); |
|||
|
|||
if (typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) { |
|||
// 访问后端更新排序 |
|||
props.grid.updates(updateData); |
|||
} |
|||
|
|||
props.afterRowDraggable(updateData); |
|||
}; |
|||
|
|||
// 处理当前页所有数据勾选状态 |
|||
const allTickedStatus = () => { |
|||
// 存在一条勾选的记录设置为 null |
|||
// 一条勾选的记录都没有设置为 false |
|||
// 全部勾选设置为 true |
|||
const ticked_ = <any>[]; |
|||
table.rows.forEach((item) => { |
|||
if (item[table.tickedField]) { |
|||
ticked_.push(item); |
|||
} |
|||
}); |
|||
if (ticked_.length === table.rows.length) { |
|||
table.allTicked = true; |
|||
} else if (ticked_.length > 0) { |
|||
table.allTicked = null; |
|||
} else { |
|||
table.allTicked = false; |
|||
} |
|||
}; |
|||
|
|||
const updateTicked = (evt: Event, row: any) => { |
|||
if (table.bodyEditStatus === 'none') { |
|||
props.getRow(table.rows, row[props.rowKeyName], false)[table.selectedField] = row[table.tickedField]; |
|||
allTickedStatus(); |
|||
if (props.grid.props.onUpdateTicked) { |
|||
props.grid.emit('updateTicked', evt, row); |
|||
} |
|||
} else { |
|||
props.getRow(table.rows, row[props.rowKeyName], false)[table.tickedField] = !props.getRow(table.rows, row[props.rowKeyName], false)[table.tickedField]; |
|||
} |
|||
}; |
|||
|
|||
defineExpose({ |
|||
allTickedStatus, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="css"></style> |
@ -0,0 +1,324 @@ |
|||
<template> |
|||
<q-tr v-if="showRowEditButtonComputed"> |
|||
<q-td :colspan="props.noDataTrColspan"> |
|||
<div class="editButton text-center"> |
|||
<w-toolbar |
|||
:dense="true" |
|||
align="center" |
|||
:grid="props.grid" |
|||
:buttons="[ |
|||
{ |
|||
label: '保存', |
|||
name: 'save', |
|||
icon: 'save', |
|||
color: 'primary', |
|||
outline: false, |
|||
click: async (args) => { |
|||
save(args); |
|||
}, |
|||
}, |
|||
{ |
|||
label: '取消', |
|||
name: 'cancel', |
|||
icon: 'close', |
|||
color: 'blue-grey', |
|||
outline: false, |
|||
click: (args) => { |
|||
if (table.bodyEditStatus === 'rowEdit') { |
|||
props.setOldValue(args.selected); |
|||
} else if (table.bodyEditStatus === 'rowsEdit') { |
|||
props.grid.getRows().forEach((item) => { |
|||
props.setOldValue(item); |
|||
}); |
|||
} |
|||
table.bodyEditStatus = 'none'; |
|||
}, |
|||
}, |
|||
]" |
|||
></w-toolbar> |
|||
</div> |
|||
</q-td> |
|||
</q-tr> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { computed, inject, ref, toRaw } from 'vue'; |
|||
import { Tools, NotifyManager, noErrorAxios, t } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
url: { |
|||
// 表格所有的url |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
rowKeyName: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
row: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
getRow: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
getRowComponentRefs: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
setOldValue: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
noDataTrColspan: { |
|||
type: Number, |
|||
default: () => { |
|||
return 0; |
|||
}, |
|||
}, |
|||
}); |
|||
const table = inject('table'); |
|||
|
|||
const validate = async (refs) => { |
|||
let result = true; |
|||
for (let i = 0; i < refs.length; i++) { |
|||
const component = refs[i].getComponentRef(); |
|||
if (!Tools.isEmpty(refs[i].getComponentOneRef)) { |
|||
const componentOne = refs[i].getComponentOneRef(); |
|||
if (!Tools.isEmpty(componentOne) && !Tools.isEmpty(componentOne.validate)) { |
|||
const componentOneValidateResult = await componentOne.validate(); |
|||
if (!componentOneValidateResult) { |
|||
result = false; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
if (props.grid.props.tree && !Tools.isEmpty(component)) { |
|||
const keys = Object.keys(component); |
|||
for (let k = 0; k < keys.length; k++) { |
|||
if (!Tools.isEmpty(component[keys[k]]?.validate)) { |
|||
const treeComponentValidateResult = await component[keys[k]].validate(); |
|||
if (!treeComponentValidateResult) { |
|||
result = false; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} else if (!Tools.isEmpty(component.validate)) { |
|||
const componentValidateResult = await component.validate(); |
|||
if (!componentValidateResult) { |
|||
result = false; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
}; |
|||
|
|||
const rowSave = (args) => { |
|||
let data = args.selected['_rowOldValue']; |
|||
let submitFlag = true; |
|||
let localeUpdateFlag = false; |
|||
let url = ''; |
|||
// 执行保存 |
|||
props.grid.emit('beforeEditorDataSubmit', data, (handlerRequestParams: any | boolean, localeUpdate: boolean = false) => { |
|||
if (typeof handlerRequestParams === 'boolean' && handlerRequestParams === false) { |
|||
submitFlag = false; |
|||
} else { |
|||
data = handlerRequestParams; |
|||
} |
|||
localeUpdateFlag = localeUpdate; |
|||
}); |
|||
if (localeUpdateFlag && submitFlag) { |
|||
// 只进行本地修改,不访问服务器 |
|||
props.grid.replaceRow(data); |
|||
table.bodyEditStatus = 'none'; |
|||
} else { |
|||
if (submitFlag) { |
|||
data = { ...args.selected, ...data }; |
|||
if (!Tools.isEmpty(props.url.editDataUrl)) { |
|||
url = props.url.editDataUrl + '/' + args.selected[props.grid.props.primaryKey]; |
|||
} else { |
|||
url = props.url.dataUrl + '/' + args.selected[props.grid.props.primaryKey]; |
|||
} |
|||
const requestParams = { |
|||
method: 'PUT', |
|||
headers: { 'content-type': 'application/json;charset=utf-8;' }, |
|||
data: data, |
|||
url: url, |
|||
}; |
|||
noErrorAxios(requestParams) |
|||
.then((resp) => { |
|||
props.grid.emit('afterEditorDataSubmit', resp.data); |
|||
NotifyManager.info(t('tip.operationSuccess')); |
|||
if (props.grid.props.refreshData || !props.grid.props.tree) { |
|||
props.grid.refresh(); |
|||
} else if (resp.data) { |
|||
props.grid.replaceRow(data); |
|||
} |
|||
// 保存成功后退出编辑状态 |
|||
table.bodyEditStatus = 'none'; |
|||
}) |
|||
.catch((error) => { |
|||
const response = error?.response; |
|||
const status = response?.status; |
|||
const data = response?.data; |
|||
if (data?.code === 1001) { |
|||
NotifyManager.error('服务器验证未通过'); |
|||
} else { |
|||
//其他错误 |
|||
if (status === 500) { |
|||
NotifyManager.error(t(data?.errorMessageI18nKey)); |
|||
} else { |
|||
NotifyManager.error(t(status)); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// 检查数据是否修改过 |
|||
const checkDataModified = (row) => { |
|||
const keys = Object.keys(row['_rowOldValue']); |
|||
return keys.some((key) => row[key] !== row['_rowOldValue'][key]); |
|||
}; |
|||
|
|||
const treeDataPush = (arr) => { |
|||
const data = <any>[]; |
|||
if (arr && arr.length > 0) { |
|||
arr.forEach((item) => { |
|||
if (checkDataModified(item)) { |
|||
data.push(item['_rowOldValue']); |
|||
} |
|||
const childrenData = treeDataPush(item.children); |
|||
if (childrenData.length > 0) { |
|||
data.push(...childrenData); |
|||
} |
|||
}); |
|||
} |
|||
return data; |
|||
}; |
|||
|
|||
const rowsSave = (args) => { |
|||
let data = <any>[]; |
|||
const rows = args.grid.getRows(); |
|||
const isTree = props.grid.props.tree; |
|||
rows.forEach((item) => { |
|||
if (checkDataModified(item)) { |
|||
data.push(item['_rowOldValue']); |
|||
} |
|||
if (isTree && item.children) { |
|||
const childrenData = treeDataPush(item.children); |
|||
if (childrenData.length > 0) { |
|||
data.push(...childrenData); |
|||
} |
|||
} |
|||
}); |
|||
let submitFlag = true; |
|||
let localeUpdateFlag = false; |
|||
// 执行保存 |
|||
props.grid.emit('beforeEditorDataSubmit', data, (handlerRequestParams: any | boolean, localeUpdate: boolean = false) => { |
|||
if (typeof handlerRequestParams === 'boolean' && handlerRequestParams === false) { |
|||
submitFlag = false; |
|||
} else { |
|||
data = handlerRequestParams; |
|||
} |
|||
localeUpdateFlag = localeUpdate; |
|||
}); |
|||
if (localeUpdateFlag && submitFlag) { |
|||
// 只进行本地修改,不访问服务器 |
|||
data.forEach((item) => { |
|||
props.grid.replaceRow(item); |
|||
}); |
|||
table.bodyEditStatus = 'none'; |
|||
} else { |
|||
if (submitFlag) { |
|||
props.grid.updates(data, (callbackData) => { |
|||
NotifyManager.info(t('tip.operationSuccess')); |
|||
if (props.grid.props.refreshData || !props.grid.props.tree) { |
|||
props.grid.refresh(); |
|||
} else if (!Tools.isEmpty(callbackData)) { |
|||
callbackData.forEach((item) => { |
|||
props.grid.replaceRow(item); |
|||
}); |
|||
} |
|||
// 保存成功后退出编辑状态 |
|||
table.bodyEditStatus = 'none'; |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const save = async (args) => { |
|||
const refs = props.getRowComponentRefs(table.bodyEditStatus === 'rowEdit' ? args.selected[props.rowKeyName] : []); |
|||
const result = await validate(refs); |
|||
if (!result) { |
|||
NotifyManager.error('验证未通过'); |
|||
} else { |
|||
if (table.bodyEditStatus === 'rowEdit') { |
|||
rowSave(args); |
|||
} else if (table.bodyEditStatus === 'rowsEdit') { |
|||
rowsSave(args); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const showRowEditButtonComputed = computed(() => { |
|||
if (table.bodyEditStatus === 'rowEdit' && isSelectedRowComputed.value) { |
|||
return true; |
|||
} else if (table.bodyEditStatus === 'rowsEdit' && table.rows.length > 0 && isLastRowComputed.value) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}); |
|||
|
|||
const checkLastRow = (row) => { |
|||
if (props.grid.props.tree && row['expand'] && !Tools.isEmpty(row.children) && row.children.length > 0) { |
|||
const childrenLastRow = row.children[row.children.length - 1]; |
|||
if (childrenLastRow['expand'] && !Tools.isEmpty(childrenLastRow.children) && childrenLastRow.children.length > 0) { |
|||
return checkLastRow(childrenLastRow); |
|||
} else { |
|||
return childrenLastRow[props.rowKeyName] === props.row[props.rowKeyName]; |
|||
} |
|||
} else { |
|||
return row[props.rowKeyName] === props.row[props.rowKeyName]; |
|||
} |
|||
}; |
|||
|
|||
const isLastRowComputed = computed(() => { |
|||
const lastRow = table.rows[table.rows.length - 1]; |
|||
return checkLastRow(lastRow); |
|||
}); |
|||
|
|||
const isSelectedRowComputed = computed(() => { |
|||
const selected = props.grid.getSelectedRow(); |
|||
if (!Tools.isEmpty(selected)) { |
|||
return props.row[props.rowKeyName] === props.grid.getSelectedRow()[props.rowKeyName]; |
|||
} |
|||
return false; |
|||
}); |
|||
|
|||
defineExpose({}); |
|||
</script> |
|||
|
|||
<style lang="css"> |
|||
.editButton { |
|||
position: sticky; |
|||
background-color: white; |
|||
left: 45%; |
|||
width: 150px; |
|||
} |
|||
</style> |
@ -0,0 +1,227 @@ |
|||
<template> |
|||
<w-dialog ref="dialogRef" :title="dialog.dialogTitle" v-bind="props.grid.props.editor.dialog" :buttons="dialogButtonsComputed"> |
|||
<w-form ref="dialogFormRef" v-bind="props.grid.props.editor.form" class="pt-1.5 px-1.5"></w-form> |
|||
</w-dialog> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, reactive, inject, computed } from 'vue'; |
|||
import { t, Tools, noErrorAxios, NotifyManager } from '@/platform'; |
|||
|
|||
const dialogRef = ref(); |
|||
const dialogFormRef = ref(); |
|||
|
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
url: { |
|||
// 表格所有的url |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
request: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
setRowDataExtraProperty: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
getRow: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
}); |
|||
const table = inject('table'); |
|||
|
|||
const dialogButtonsComputed = computed(() => { |
|||
if (props.grid.props.editor?.dialog?.buttons) { |
|||
return [...props.grid.props.editor.dialog.buttons, ...dialog.dialogButtons]; |
|||
} |
|||
return dialog.dialogButtons; |
|||
}); |
|||
|
|||
const save = async () => { |
|||
dialog.dialogButtons[0].loading = true; |
|||
const formStatus = dialogFormRef.value.getStatus(); |
|||
const validate = await dialogFormRef.value.validate(); |
|||
if (validate) { |
|||
let dialogFormData = dialogFormRef.value.getData(); |
|||
const selected = props.grid.getSelectedRow(); |
|||
const primaryKey = selected[props.grid.props.primaryKey]; |
|||
if (formStatus === 'edit' && selected) { |
|||
dialogFormData[props.grid.props.primaryKey] = primaryKey; |
|||
} |
|||
let submitFlag = true; |
|||
let closeDialog = true; |
|||
props.grid.emit('beforeEditorDataSubmit', dialogFormData, (handlerRequestParams: any | boolean, closeFlag: boolean = true) => { |
|||
if (typeof handlerRequestParams === 'boolean' && handlerRequestParams === false) { |
|||
submitFlag = false; |
|||
} else { |
|||
dialogFormData = handlerRequestParams; |
|||
} |
|||
closeDialog = closeFlag; |
|||
}); |
|||
if (submitFlag) { |
|||
if (formStatus === 'addTop') { |
|||
dialogFormData[props.grid.props.foreignKey] = null; |
|||
} else if (formStatus === 'addChild') { |
|||
dialogFormData[props.grid.props.foreignKey] = primaryKey; |
|||
} else if (formStatus === 'edit' && primaryKey) { |
|||
dialogFormData[props.grid.props.foreignKey] = primaryKey; |
|||
} else if (formStatus === 'clone' && primaryKey) { |
|||
dialogFormData[props.grid.props.foreignKey] = selected[props.grid.props.foreignKey]; |
|||
} |
|||
if (formStatus === 'edit') { |
|||
// 将行数据默认添加到传递给后端的数据中 |
|||
dialogFormData = { ...selected, ...dialogFormData }; |
|||
} |
|||
let requestParams = { |
|||
method: getMethod(formStatus), |
|||
headers: { 'content-type': 'application/json;charset=utf-8;' }, |
|||
data: dialogFormData, |
|||
url: getUrl(formStatus, selected), |
|||
}; |
|||
dialog.dialogButtons[0].loading = false; |
|||
noErrorAxios(requestParams) |
|||
.then((resp) => { |
|||
dialog.dialogButtons[0].loading = false; |
|||
props.grid.emit('afterEditorDataSubmit', resp.data); |
|||
NotifyManager.info(t('tip.operationSuccess')); |
|||
if (closeDialog) { |
|||
dialogRef.value.hide(); |
|||
} |
|||
if (props.grid.props.refreshData || !props.grid.props.tree) { |
|||
props.grid.refresh(); |
|||
} else if (resp.data && (formStatus === 'add' || formStatus === 'clone' || formStatus === 'addTop' || formStatus === 'addChild')) { |
|||
addData(resp.data); |
|||
} else if (resp.data) { |
|||
updateData(resp.data); |
|||
} |
|||
}) |
|||
.catch((error) => { |
|||
const response = error?.response; |
|||
const status = response?.status; |
|||
const data = response?.data; |
|||
if (data?.code === 1001) { |
|||
// 验证错误 |
|||
if (error.response.data.data) { |
|||
dialogFormRef.value.setValidationErrors(error.response.data.data); |
|||
} |
|||
} else { |
|||
//其他错误 |
|||
if (status === 500) { |
|||
NotifyManager.error(t(data?.errorMessageI18nKey)); |
|||
} else { |
|||
NotifyManager.error(t(status)); |
|||
} |
|||
} |
|||
dialog.dialogButtons[0].loading = false; |
|||
}); |
|||
} else { |
|||
dialog.dialogButtons[0].loading = false; |
|||
if (closeDialog) { |
|||
dialogRef.value.hide(); |
|||
} |
|||
} |
|||
} else { |
|||
dialog.dialogButtons[0].loading = false; |
|||
} |
|||
}; |
|||
|
|||
const dialog = reactive({ |
|||
dialogTitle: t('action.addNew'), |
|||
dialogButtons: [ |
|||
{ |
|||
icon: 'beenhere', |
|||
labelI18nKey: 'action.submit', |
|||
label: t('action.submit'), |
|||
loading: false, |
|||
click: () => { |
|||
save(); |
|||
}, |
|||
}, |
|||
], |
|||
}); |
|||
|
|||
// 新增树表格中的数据 |
|||
const addTreeRow = (row) => { |
|||
if (Tools.isEmpty(row[props.grid.props.foreignKey])) { |
|||
table.rows.push(row); |
|||
} else { |
|||
const parent = props.getRow(table.rows, row[props.grid.props.foreignKey], true); |
|||
if (parent) { |
|||
if (parent['children'] && Array.isArray(parent['children'])) { |
|||
parent['children'].push(row); |
|||
} else { |
|||
parent['children'] = [row]; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const addData = (rowData) => { |
|||
if (props.grid.props.tree) { |
|||
addTreeRow(rowData); |
|||
props.setRowDataExtraProperty(table.rows); |
|||
} else { |
|||
props.grid.addRow(rowData, false); |
|||
} |
|||
}; |
|||
const updateData = (rowData) => { |
|||
const selected = props.grid.getSelectedRow(); |
|||
rowData[props.grid.props.primaryKey] = selected[props.grid.props.primaryKey]; |
|||
rowData[props.grid.props.selectedField] = true; |
|||
if (selected['children']) { |
|||
rowData['children'] = selected['children']; |
|||
} |
|||
props.grid.replaceRow(rowData); |
|||
}; |
|||
|
|||
const getMethod = (formStatus: string) => { |
|||
if (formStatus === 'add' || formStatus === 'clone' || formStatus === 'addTop' || formStatus === 'addChild') { |
|||
return 'POST'; |
|||
} else { |
|||
return 'PUT'; |
|||
} |
|||
}; |
|||
|
|||
const getUrl = (formStatus: string, selected: any) => { |
|||
if (formStatus === 'add' || formStatus === 'clone' || formStatus === 'addTop' || formStatus === 'addChild') { |
|||
if (!Tools.isEmpty(props.url.addDataUrl)) { |
|||
return props.url.addDataUrl; |
|||
} else { |
|||
return props.url.dataUrl; |
|||
} |
|||
} else { |
|||
if (!Tools.isEmpty(props.url.editDataUrl)) { |
|||
return props.url.editDataUrl + '/' + selected[props.grid.props.primaryKey]; |
|||
} else { |
|||
return props.url.dataUrl + '/' + selected[props.grid.props.primaryKey]; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const resetButtonLabel = () => { |
|||
dialog.dialogButtons[0].label = t(dialog.dialogButtons[0].labelI18nKey); |
|||
}; |
|||
const getDialog = () => { |
|||
return dialogRef.value; |
|||
}; |
|||
const getForm = () => { |
|||
return dialogFormRef.value; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
resetButtonLabel, |
|||
getDialog, |
|||
getForm, |
|||
}); |
|||
</script> |
|||
<style lang="css"></style> |
@ -0,0 +1,539 @@ |
|||
<template> |
|||
<template v-if="columnTitleState.columnTitleRowNum > 1"> |
|||
<q-tr v-for="(r, rIndex) in columnTitleState.columnTitleArr" :key="rIndex"> |
|||
<q-th |
|||
v-if="rIndex === 0 && props.selection === 'multiple' && table.checkboxSelection && !props.grid.props.tree" |
|||
:rowspan="columnTitleState.columnTitleRowNum" |
|||
:style="moreColumnTitleTableSelectionStyle" |
|||
> |
|||
<q-checkbox v-model="table.allTicked" flat :dense="props.denseHeader" @update:model-value="allTickedUpdateFun" /> |
|||
</q-th> |
|||
<q-th |
|||
v-else-if="rIndex === 0 && table.checkboxSelection && !props.grid.props.tree" |
|||
:rowspan="columnTitleState.columnTitleRowNum" |
|||
:style="moreColumnTitleTableSelectionStyle" |
|||
></q-th> |
|||
<q-th |
|||
v-if="rIndex === 0 && table.sortNo && !props.grid.props.tree" |
|||
:rowspan="columnTitleState.columnTitleRowNum" |
|||
:style="moreColumnTitleTableSortNoStyle" |
|||
> |
|||
{{ $t('rownum') }} |
|||
</q-th> |
|||
<q-th |
|||
v-for="c in r" |
|||
:key="c.name" |
|||
:rowspan="c.rowspan" |
|||
:colspan="c.colspan" |
|||
:style="thStyleHandler(c, props.scope)" |
|||
:class="c.classes" |
|||
:props="titleScopeHandler(c, props.scope)" |
|||
style="font-weight: bold" |
|||
:title="c.title" |
|||
> |
|||
<span v-dompurify-html="Tools.isUndefinedOrNull(c.label) ? '' : c.label"></span> |
|||
</q-th> |
|||
</q-tr> |
|||
<q-tr v-if="table.rows.length === 0" :style="props.noDataTrHeightStyle" class="noDataTr"> |
|||
<q-td :colspan="props.noDataTrColspan" align="center" valian="middle"><q-icon size="2em" name="info" />{{ $t('tip.noData') }}</q-td> |
|||
</q-tr> |
|||
</template> |
|||
<template v-else> |
|||
<q-tr :props="scope"> |
|||
<q-th |
|||
v-if="props.selection === 'multiple' && table.checkboxSelection && !props.grid.props.tree" |
|||
:style="props.grid.props.tree ? '' : 'padding: 0; min-width: 50px;width: 50px;max-width:50px'" |
|||
> |
|||
<q-checkbox v-model="table.allTicked" flat :dense="props.denseHeader" @update:model-value="allTickedUpdateFun" |
|||
/></q-th> |
|||
<q-th |
|||
v-else-if="table.checkboxSelection && !props.grid.props.tree" |
|||
:style="props.grid.props.tree ? '' : 'padding: 0; min-width: 50px;width: 50px;max-width:50px'" |
|||
></q-th> |
|||
<template v-for="col in scope.cols" :key="col.name"> |
|||
<q-th |
|||
:props="scope" |
|||
:style="col.style + (col.name === '_sortNo_' ? 'padding: 0; min-width: 50px;width: 50px;max-width:50px' : '')" |
|||
:class="col.classes" |
|||
style="font-weight: bold" |
|||
:title="col.title" |
|||
> |
|||
<span v-dompurify-html="Tools.isUndefinedOrNull(col.label) ? '' : col.label"></span> |
|||
</q-th> |
|||
</template> |
|||
</q-tr> |
|||
<q-tr v-if="table.rows.length === 0" :style="props.noDataTrHeightStyle" class="noDataTr"> |
|||
<q-td :colspan="props.noDataTrColspan" align="center" valian="middle"><q-icon size="2em" name="info" />{{ $t('tip.noData') }}</q-td> |
|||
</q-tr> |
|||
</template> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { Tools } from '@/platform'; |
|||
import { computed, inject, reactive } from 'vue'; |
|||
|
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
scope: { |
|||
// 顶部插槽属性 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
selection: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
denseHeader: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
rawColumns: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
tableColumns: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
excludeColumnNum: { |
|||
type: Number, |
|||
default: () => { |
|||
return 0; |
|||
}, |
|||
}, |
|||
noDataTrHeightStyle: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
noDataTrColspan: { |
|||
type: Number, |
|||
default: () => { |
|||
return 0; |
|||
}, |
|||
}, |
|||
}); |
|||
const table = inject('table'); |
|||
|
|||
// 多行列标题相关变量 |
|||
const columnTitleState = reactive({ |
|||
columnTitleRowNum: 1, // 多行列标题总行数 |
|||
columnTitleArr: <any>[], // 多行列标题集合 |
|||
}); |
|||
// 多行列标题的处理类型 |
|||
type MoreColumnTitleType = { |
|||
name: string; // 列模型的name |
|||
title: string; // 列模型的title(鼠标移动上去显示内容) |
|||
label: string; // 列模型的label |
|||
parentLevel: number; // 父层级数 |
|||
childrenLevel: number; // 子层级数 |
|||
rowspan: number; // 跨行数 |
|||
colspan: number; // 跨列数 |
|||
rowIndex: number; // 列模型所处的行下标 |
|||
style: any; // 列模型配置的内嵌样式 |
|||
classes: any; // 列模型配置的 classes |
|||
parents: any; // 列模型的父name集合 |
|||
}; |
|||
// 多行列标题的记录 map |
|||
let moreColumnTitleMap = new Map<string, MoreColumnTitleType>(); |
|||
let allColumnMap = new Map(); |
|||
|
|||
const moreColumnTitleTableSelectionStyle = computed(() => { |
|||
if (table.stickyNum > 0) { |
|||
if (props.grid.props.tree) { |
|||
return 'z-index: 3;position: sticky;left: 0px;'; |
|||
} else { |
|||
return 'z-index: 3;position: sticky;left: 0px;padding: 0; width: 50px;min-width:50px;max-width:50px;'; |
|||
} |
|||
} |
|||
return 'padding: 0; width: 50px;min-width:50px;max-width:50px;'; |
|||
}); |
|||
|
|||
const moreColumnTitleTableSortNoStyle = computed(() => { |
|||
if (table.checkboxSelection && table.sortNo && table.stickyNum > 0) { |
|||
return 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);width: 50px;min-width:50px;max-width:50px;'; |
|||
} else if (table.sortNo && table.stickyNum > 0) { |
|||
return 'z-index: 3;position: sticky;left: 0px;width: 50px;min-width:50px;max-width:50px;'; |
|||
} |
|||
return 'width: 50px;min-width:50px;max-width:50px;'; |
|||
}); |
|||
|
|||
const allTickedUpdateFun = (value, evt) => { |
|||
if (table.bodyEditStatus === 'none') { |
|||
if (value) { |
|||
table.rows.forEach((item) => { |
|||
item[table.tickedField] = true; |
|||
item[table.selectedField] = true; |
|||
}); |
|||
} else { |
|||
table.rows.forEach((item) => { |
|||
item[table.tickedField] = false; |
|||
item[table.selectedField] = false; |
|||
}); |
|||
} |
|||
} else if (table.bodyEditStatus === 'rowEdit') { |
|||
table.allTicked = null; |
|||
} else if (table.bodyEditStatus === 'rowsEdit') { |
|||
table.allTicked = false; |
|||
} |
|||
}; |
|||
|
|||
const handlerStickyChildrenColumn = (item, columns) => { |
|||
columns.push(item); |
|||
if (item.columns && item.columns.length > 0) { |
|||
item.columns.forEach((children) => { |
|||
handlerStickyChildrenColumn(children, columns); |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const getStickyColumn = () => { |
|||
const columns = props.rawColumns.filter((item, index) => { |
|||
return index < table.stickyNum; |
|||
}); |
|||
const arr = []; |
|||
columns.forEach((item) => { |
|||
handlerStickyChildrenColumn(item, arr); |
|||
}); |
|||
return arr; |
|||
}; |
|||
|
|||
// 获取多行的列标题下标 |
|||
const getMoreRowColumnTitleIndex = (name: any) => { |
|||
let trIndex = -1; |
|||
let tdIndex = -1; |
|||
for (let tr = 0; tr < columnTitleState.columnTitleArr.length; tr++) { |
|||
const tdArr = columnTitleState.columnTitleArr[tr]; |
|||
let flag = false; |
|||
for (let td = 0; td < tdArr.length; td++) { |
|||
if (name === tdArr[td].name) { |
|||
trIndex = tr + 1; |
|||
tdIndex = td + 1; |
|||
flag = true; |
|||
break; |
|||
} |
|||
} |
|||
if (flag) { |
|||
break; |
|||
} |
|||
} |
|||
return { trIndex: trIndex, tdIndex: tdIndex }; |
|||
}; |
|||
|
|||
const thStickyLastNameComputed = computed(() => { |
|||
let result = <any>[]; |
|||
const stickyColumnArr = getStickyColumn(); |
|||
const lastColumn = getMoreRowColumnTitleIndex(stickyColumnArr[stickyColumnArr.length - 1]['name']); |
|||
if (lastColumn.trIndex === 1) { |
|||
// 多表头锁定列的结尾列如果行下标为1直接取最后一列 |
|||
result = [stickyColumnArr[stickyColumnArr.length - 1]]; |
|||
} else { |
|||
const map = new Map(); |
|||
stickyColumnArr.forEach((item) => { |
|||
const trtdIndex = getMoreRowColumnTitleIndex(item['name']); |
|||
if (map.has(trtdIndex.trIndex) && map.get(trtdIndex.trIndex)[0] < trtdIndex.tdIndex) { |
|||
map.set(trtdIndex.trIndex, [trtdIndex.tdIndex, item]); |
|||
} else if (!map.has(trtdIndex.trIndex)) { |
|||
map.set(trtdIndex.trIndex, [trtdIndex.tdIndex, item]); |
|||
} |
|||
}); |
|||
for (let key of map.keys()) { |
|||
result.push(map.get(key)[1]); |
|||
} |
|||
} |
|||
return result; |
|||
}); |
|||
|
|||
const thStyleHandler = (c: any, scope: any) => { |
|||
let style = ''; |
|||
if (!Tools.isEmpty(c.style)) { |
|||
if (c.style.substr(-1) !== ';') { |
|||
style = c.style + ';'; |
|||
} |
|||
style = c.style; |
|||
} |
|||
const stickyColumnArr = getStickyColumn(); |
|||
if ( |
|||
table.stickyNum > 0 && |
|||
stickyColumnArr.findIndex((item: any) => { |
|||
return item.name === c.name; |
|||
}) > -1 |
|||
) { |
|||
const stickyThArr = <any>[]; |
|||
const trtdIndex = getMoreRowColumnTitleIndex(c.name); |
|||
if (c.parents && c.parents.length > 0) { |
|||
// 存在父级节点,得到父级节点的列下标 |
|||
// 找到parent相同且tdIndex小于其的一共多少列 |
|||
for (let tr = 0; tr < trtdIndex.trIndex; tr++) { |
|||
const tdArr = columnTitleState.columnTitleArr[tr]; |
|||
for (let td = 0; td < trtdIndex.tdIndex - 1; td++) { |
|||
if (tdArr[td] && tdArr[td].parents && tdArr[td].parents.length > 0) { |
|||
const result = |
|||
tdArr[td].parents.length === c.parents.length && |
|||
tdArr[td].parents.every((a) => c.parents.some((b) => a === b)) && |
|||
c.parents.every((_b) => tdArr[td].parents.some((_a) => _a === _b)); |
|||
if (result) { |
|||
if (tr === 0) { |
|||
stickyThArr.push({ trIndex: tr + 1, tdIndex: td + props.excludeColumnNum + 1 }); |
|||
} else { |
|||
stickyThArr.push({ trIndex: tr + 1, tdIndex: td + 1 }); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
c.parents.forEach((parent) => { |
|||
const parentTrtdIndex = getMoreRowColumnTitleIndex(parent); |
|||
if (moreColumnTitleMap.get(parent)!.parents && moreColumnTitleMap.get(parent)!.parents.length > 0) { |
|||
const tdArr = columnTitleState.columnTitleArr[parentTrtdIndex.trIndex - 1]; |
|||
for (let td = 0; td < parentTrtdIndex.tdIndex - 1; td++) { |
|||
const result = |
|||
tdArr[td].parents.length === moreColumnTitleMap.get(parent)!.parents.length && |
|||
tdArr[td].parents.every((a) => moreColumnTitleMap.get(parent)!.parents.some((b) => a === b)) && |
|||
moreColumnTitleMap.get(parent)!.parents.every((_b) => tdArr[td].parents.some((_a) => _a === _b)); |
|||
if (result) { |
|||
stickyThArr.push({ trIndex: parentTrtdIndex.trIndex, tdIndex: td + 1 }); |
|||
} |
|||
} |
|||
} else { |
|||
const tdArr = columnTitleState.columnTitleArr[parentTrtdIndex.trIndex - 1]; |
|||
for (let td = 0; td < parentTrtdIndex.tdIndex - 1; td++) { |
|||
if ( |
|||
tdArr[td].parents && |
|||
tdArr[td].parents.length > 0 && |
|||
tdArr[td].parents.findIndex((item) => { |
|||
return item === parent; |
|||
}) > -1 |
|||
) { |
|||
stickyThArr.push({ trIndex: parentTrtdIndex.trIndex, tdIndex: td + props.excludeColumnNum + 1 }); |
|||
} else { |
|||
stickyThArr.push({ trIndex: parentTrtdIndex.trIndex, tdIndex: td + props.excludeColumnNum + 1 }); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
if (trtdIndex.tdIndex === 1 && stickyThArr.length === 0) { |
|||
stickyThArr.push({ trIndex: 0, tdIndex: 0 }); |
|||
} |
|||
} else { |
|||
if (trtdIndex.tdIndex === 1) { |
|||
if (props.excludeColumnNum === 2) { |
|||
return thStickyLastNameComputed.value.findIndex((item) => { |
|||
return item.name === c.name; |
|||
}) > -1 |
|||
? (style += 'z-index: 3;position: sticky;left: calc(var(--columnWidth-1-1) + var(--columnWidth-1-2));') |
|||
: (style += 'z-index: 3;position: sticky;left: calc(var(--columnWidth-1-1) + var(--columnWidth-1-2));'); |
|||
} else if (props.excludeColumnNum === 1) { |
|||
return thStickyLastNameComputed.value.findIndex((item) => { |
|||
return item.name === c.name; |
|||
}) > -1 |
|||
? (style += 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);') |
|||
: (style += 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);'); |
|||
} else { |
|||
return thStickyLastNameComputed.value.findIndex((item) => { |
|||
return item.name === c.name; |
|||
}) > -1 |
|||
? (style += 'z-index: 3;position: sticky;left: 0px;') |
|||
: (style += 'z-index: 3;position: sticky;left: 0px;'); |
|||
} |
|||
} else { |
|||
for (let i = 1; i < trtdIndex.tdIndex; i++) { |
|||
stickyThArr.push({ trIndex: 1, tdIndex: i + props.excludeColumnNum }); |
|||
} |
|||
} |
|||
} |
|||
if (props.excludeColumnNum === 2) { |
|||
stickyThArr.push({ trIndex: 1, tdIndex: 1 }); |
|||
stickyThArr.push({ trIndex: 1, tdIndex: 2 }); |
|||
} else if (props.excludeColumnNum === 1) { |
|||
stickyThArr.push({ trIndex: 1, tdIndex: 1 }); |
|||
} |
|||
if (stickyThArr && stickyThArr.length > 0) { |
|||
let left = ''; |
|||
stickyThArr.forEach((item) => { |
|||
left += '+ var(--columnWidth-' + item.trIndex + '-' + item.tdIndex + ') '; |
|||
}); |
|||
if (left) { |
|||
style += 'z-index: 3;position: sticky;left: calc(' + left.substring(1) + ')' + ';'; |
|||
} |
|||
} |
|||
} |
|||
return style; |
|||
}; |
|||
|
|||
const titleScopeHandler = (column: any, scope: any) => { |
|||
if (props.tableColumns?.length > 0) { |
|||
const i = props.tableColumns.findIndex((item: any) => item['name'] === column.name); |
|||
if (i > -1) { |
|||
return scope; |
|||
} |
|||
} |
|||
return undefined; |
|||
}; |
|||
|
|||
// 将所有列转换到 map 中 |
|||
const columnToMap = (column: any) => { |
|||
if (Tools.isEmpty(column.name)) { |
|||
column.name = Tools.uuid(); |
|||
} |
|||
if (Tools.isEmpty(column.label)) { |
|||
column.label = column.name; |
|||
} |
|||
if (column && column.columns && column.columns.length > 0) { |
|||
allColumnMap.set(column.name, column); |
|||
moreColumnTitleMap.set(column.name, { |
|||
name: column.name, |
|||
label: column.label, |
|||
title: column.title, |
|||
parentLevel: 0, |
|||
childrenLevel: 0, |
|||
rowspan: 0, |
|||
colspan: 0, |
|||
rowIndex: 0, |
|||
style: column.style, |
|||
classes: column.classes, |
|||
parents: [], |
|||
}); |
|||
column.columns.forEach((item) => { |
|||
columnToMap(item); |
|||
}); |
|||
} else { |
|||
allColumnMap.set(column.name, column); |
|||
moreColumnTitleMap.set(column.name, { |
|||
name: column.name, |
|||
label: column.label, |
|||
title: column.title, |
|||
parentLevel: 0, |
|||
childrenLevel: 0, |
|||
rowspan: 0, |
|||
colspan: 0, |
|||
rowIndex: 0, |
|||
style: column.style, |
|||
classes: column.classes, |
|||
parents: [], |
|||
}); |
|||
} |
|||
}; |
|||
let tmpColspan = 0; |
|||
const deepArr = []; |
|||
const getChildrenLevel = (column, deep, deepArr) => { |
|||
if (column && column.columns && column.columns.length > 0) { |
|||
deep++; |
|||
column.columns.forEach((item) => { |
|||
getChildrenLevel(item, deep, deepArr); |
|||
}); |
|||
} else if (column) { |
|||
// deep++; |
|||
deepArr.push(deep); |
|||
tmpColspan += 1; |
|||
} |
|||
}; |
|||
|
|||
// 根据子找所有父,返回值不包含查找的对象 |
|||
function findParents(arrData: any, name: any) { |
|||
if (arrData.length == 0) return; |
|||
for (let i = 0; i < arrData.length; i++) { |
|||
if (arrData[i].name == name) { |
|||
return []; |
|||
} else { |
|||
if (arrData[i].columns) { |
|||
const res = findParents(arrData[i].columns, name); |
|||
if (res !== undefined) { |
|||
return res.concat(arrData[i].name).reverse(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
const handlerMoreRowColumnTitle = () => { |
|||
moreColumnTitleMap = new Map<string, MoreColumnTitleType>(); |
|||
allColumnMap = new Map(); |
|||
props.rawColumns.forEach((tableColumn: any) => { |
|||
columnToMap(tableColumn); |
|||
}); |
|||
let maxColumnChildrenLevel = 0; |
|||
for (let key of allColumnMap.keys()) { |
|||
// 处理列的 childrenLevel |
|||
let tmpChildrenLevel = 0; |
|||
getChildrenLevel(allColumnMap.get(key), 0, deepArr); |
|||
tmpChildrenLevel = Math.max(...deepArr); |
|||
if (tmpChildrenLevel > maxColumnChildrenLevel) { |
|||
maxColumnChildrenLevel = tmpChildrenLevel; |
|||
} |
|||
deepArr.splice(0, deepArr.length); |
|||
moreColumnTitleMap.get(key)!.childrenLevel = tmpChildrenLevel; |
|||
|
|||
// 处理列的 colspan |
|||
moreColumnTitleMap.get(key)!.colspan = tmpColspan; |
|||
tmpColspan = 0; |
|||
|
|||
// 处理列的 parent |
|||
const parent = findParents(props.rawColumns, key); |
|||
moreColumnTitleMap.get(key)!.parents = parent; |
|||
|
|||
// 处理列的 parentLevel |
|||
moreColumnTitleMap.get(key)!.parentLevel = parent.length; |
|||
|
|||
// 处理列的 rowIndex |
|||
moreColumnTitleMap.get(key)!.rowIndex = parent.length; |
|||
} |
|||
if (maxColumnChildrenLevel > 0) { |
|||
// 更改列头总行数 = 最大子层级数 + 1 |
|||
columnTitleState.columnTitleRowNum = maxColumnChildrenLevel + 1; |
|||
} |
|||
|
|||
const map = new Map<number, [any]>(); |
|||
for (let key of moreColumnTitleMap.keys()) { |
|||
const value: any = moreColumnTitleMap.get(key); |
|||
// 得到列头总行数后处理列的 rowspan |
|||
if (value.parentLevel === 0 && value.childrenLevel === 0) { |
|||
value.rowspan = columnTitleState.columnTitleRowNum; |
|||
} else if (value.parentLevel === 0) { |
|||
value.rowspan = 1; |
|||
} else { |
|||
// 总行数 - 父层级数 - 子层级数 |
|||
value.rowspan = columnTitleState.columnTitleRowNum - value.parentLevel - value.childrenLevel; |
|||
} |
|||
if (map.has(value.rowIndex)) { |
|||
(map.get(value.rowIndex) as any).push(value); |
|||
} else { |
|||
map.set(value.rowIndex, [value]); |
|||
} |
|||
} |
|||
const arr = Array.from(map); |
|||
|
|||
columnTitleState.columnTitleArr = []; |
|||
arr.sort((a, b) => a[0] - b[0]); |
|||
arr.forEach((item) => { |
|||
columnTitleState.columnTitleArr.push(item[1]); |
|||
}); |
|||
}; |
|||
|
|||
const getColumnTitleState = () => { |
|||
return columnTitleState; |
|||
}; |
|||
const getMoreColumnTitleMap = () => { |
|||
return moreColumnTitleMap; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
handlerMoreRowColumnTitle, |
|||
getColumnTitleState, |
|||
getMoreColumnTitleMap, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="css"></style> |
@ -0,0 +1,73 @@ |
|||
<template> |
|||
<template v-if="props.grid.props.pageable && !props.grid.props.tree"> |
|||
<template v-if="props.state.refHeightWidth.middleWidth > 600"> |
|||
<q-pagination |
|||
v-model="page" |
|||
:boundary-links="props.state.pagination.config.boundaryLinks" |
|||
:boundary-numbers="props.state.pagination.config.boundaryNumbers" |
|||
:direction-links="props.state.pagination.config.directionLinks" |
|||
:ellipses="props.state.pagination.config.ellipses" |
|||
:max-pages="props.state.pagination.config.maxPages" |
|||
:min="1" |
|||
:max="props.scope.pagesNumber" |
|||
:size="props.denseBottom ? '10px' : ''" |
|||
@update:model-value="pageChange" |
|||
/> |
|||
</template> |
|||
<template v-else> |
|||
<q-pagination |
|||
v-model="page" |
|||
:boundary-links="props.state.pagination.config.boundaryLinks" |
|||
:boundary-numbers="props.state.pagination.config.boundaryNumbers" |
|||
:direction-links="props.state.pagination.config.directionLinks" |
|||
:ellipses="props.state.pagination.config.ellipses" |
|||
:max-pages="3" |
|||
:min="1" |
|||
:max="props.scope.pagesNumber" |
|||
:size="props.denseBottom ? '10px' : ''" |
|||
@update:model-value="pageChange" |
|||
/> |
|||
</template> |
|||
<span>{{ $t('tip.pagenation.totalRecord', { count: props.state.pagination.rowsNumber }) }}</span> |
|||
</template> |
|||
<template v-else> {{ $t('tip.pagenation.totalRecord', { count: props.state.pagination.rowsNumber }) }} </template> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
const page = defineModel({ type: Number, default: 1 }); |
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
scope: { |
|||
// 顶部插槽属性 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
state: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
denseBottom: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
request: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
}); |
|||
|
|||
const pageChange = (value) => { |
|||
page.value = value; |
|||
props.request(props.state); |
|||
}; |
|||
</script> |
|||
<style lang="css"></style> |
@ -0,0 +1,77 @@ |
|||
<template> |
|||
<q-td :key="col.name" :props="scope" :title="col.classes?.indexOf('truncate') > -1 && !Tools.isEmpty(value) && typeof value !== 'object' ? value : ''"> |
|||
<template v-if="col.name === '_sortNo_'"> |
|||
{{ scope.rowIndex + 1 }} |
|||
</template> |
|||
<template v-if="!Tools.isEmpty(col.type) && ((props.isSelectedRow && table.bodyEditStatus === 'rowEdit') || table.bodyEditStatus === 'rowsEdit')"> |
|||
<component |
|||
:is="col.type" |
|||
ref="componentRef" |
|||
v-bind="col.attrs" |
|||
v-model="props.getRow(table.rows, scope.row[props.rowKeyName], false)['_rowOldValue'][col.name]" |
|||
bg-color="light-green-1" |
|||
></component> |
|||
</template> |
|||
<template v-else> |
|||
<template v-if="!Tools.isEmpty(value) && typeof value === 'object' && value.componentType && value.bindModelValue"> |
|||
<component :is="value.componentType" v-bind="value.attrs" v-model="props.getRow(table.rows, scope.row[props.rowKeyName], false)[col.name]"></component> |
|||
</template> |
|||
<template v-else-if="!Tools.isEmpty(value) && typeof value === 'object' && value.componentType"> |
|||
<component :is="value.componentType" v-bind="value.attrs"></component> |
|||
</template> |
|||
<template v-else> |
|||
<span v-dompurify-html="Tools.isUndefinedOrNull(value) ? '' : value"></span> |
|||
</template> |
|||
</template> |
|||
</q-td> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { inject, computed, ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const componentRef = ref(); |
|||
const props = defineProps({ |
|||
grid: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
getRow: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
rowKeyName: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
scope: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
col: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
value: { |
|||
type: [Object, String, Number, Boolean], |
|||
default: '', |
|||
}, |
|||
isSelectedRow: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
}); |
|||
const table = inject('table'); |
|||
|
|||
const getComponentRef = () => { |
|||
return componentRef.value; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
getComponentRef, |
|||
}); |
|||
</script> |
|||
<style lang="css"></style> |
@ -0,0 +1,654 @@ |
|||
<template> |
|||
<div class="col"> |
|||
<w-form ref="formRef" v-bind="props.grid.props.queryFormAttrs" :fields="queryFormFieldsComputed" :cols-num="props.grid.props.queryFormColsNum"></w-form> |
|||
<div |
|||
v-if="props.grid.props.title || buttons_.length > 0 || props.grid.props.configButton || fields.length > 0" |
|||
class="flex flex-nowrap items-end" |
|||
:class="fields.length > 0 ? 'pt-2.5' : ''" |
|||
> |
|||
<div class="flex-none">{{ $t(props.grid.props.title ? props.grid.props.title : '') }}</div> |
|||
<div class="flex-1"> |
|||
<w-toolbar |
|||
ref="toolbarRef" |
|||
:dense="denseToolbarComputed" |
|||
v-bind="props.grid.props.toolbarConfigure" |
|||
:buttons="toolbarButtonsComputed" |
|||
:grid="props.grid" |
|||
></w-toolbar> |
|||
</div> |
|||
<div v-if="props.grid.props.configButton" class="flex-none pl-1"> |
|||
<q-btn round dense :size="denseToolbarComputed ? '13px' : undefined" icon="manage_accounts" unelevated outline> |
|||
<q-popup-proxy v-model="table.gridConfig"> |
|||
<GridConfig :scope="props.scope" :more-column-title-array="props.moreColumnTitleArray" :grid="props.grid"></GridConfig> |
|||
</q-popup-proxy> |
|||
</q-btn> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { computed, inject, ref, reactive, nextTick, onBeforeMount, toRaw } from 'vue'; |
|||
import { useQuasar, exportFile } from 'quasar'; |
|||
import { axios, Tools, t, NotifyManager } from '@/platform'; |
|||
import GridConfig from './GridConfig.vue'; |
|||
|
|||
const $q = useQuasar(); |
|||
|
|||
const formRef = ref(); |
|||
const toolbarRef = ref(); |
|||
const localeFlag = ref(false); |
|||
const fields = ref(<any>[]); |
|||
const buttons_ = ref(<any>[]); |
|||
const moreQueryStatus = ref(false); // 当前更多查询状态是否激活 |
|||
|
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
scope: { |
|||
// 顶部插槽属性 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
moreColumnTitleArray: { |
|||
// 多表头数组 |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
buildQueryCriterias: { |
|||
// 构建查询 |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
columns: { |
|||
// 表格列集合 |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
url: { |
|||
// 表格所有的url |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
}); |
|||
const table = inject('table'); |
|||
|
|||
const queryFormFieldsComputed = computed(() => { |
|||
localeFlag.value; |
|||
return fields.value; |
|||
}); |
|||
const toolbarButtonsComputed = computed(() => { |
|||
localeFlag.value; |
|||
return buttons_.value; |
|||
}); |
|||
const denseToolbarComputed = computed(() => { |
|||
if (table.denseToolbar) { |
|||
return true; |
|||
} else if (table.dense !== false) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}); |
|||
|
|||
const screenCols = { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 }; |
|||
const queryFormColsNumComputed = computed(() => { |
|||
if (typeof props.grid.props.queryFormColsNum === 'number' && props.grid.props.queryFormColsNum > 0) { |
|||
return props.grid.props.queryFormColsNum; |
|||
} else if (typeof props.grid.props.queryFormColsNum === 'object') { |
|||
const screen = { ...screenCols, ...props.grid.props.queryFormColsNum }; |
|||
return screen[$q.screen.name]; |
|||
} |
|||
return screenCols[$q.screen.name]; |
|||
}); |
|||
|
|||
// 处理查询form显示的字段 |
|||
const handlerQueryFormShowField = () => { |
|||
fields.value = []; |
|||
if (moreQueryStatus.value) { |
|||
props.grid.props.queryFormFields.forEach((item: any) => { |
|||
fields.value.push(item); |
|||
item.showIf = () => { |
|||
return true; |
|||
}; |
|||
}); |
|||
} else { |
|||
// 一行应该显示的字段个数 |
|||
const rowColsNum = queryFormColsNumComputed.value * (props.grid.props.queryFormRowNum || 1); |
|||
let currRowColsNum = 0; |
|||
props.grid.props.queryFormFields.forEach((item: any) => { |
|||
if (Tools.hasOwnProperty(item, 'colSpan')) { |
|||
currRowColsNum += item.colSpan; |
|||
} else { |
|||
currRowColsNum += 1; |
|||
} |
|||
if (currRowColsNum <= rowColsNum) { |
|||
fields.value.push(item); |
|||
item.showIf = (form) => { |
|||
return true; |
|||
}; |
|||
} else { |
|||
item.showIf = (form) => { |
|||
return false; |
|||
}; |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const edit = (selected) => { |
|||
if (!selected) { |
|||
NotifyManager.warn(t('action.edit.tip')); |
|||
} else { |
|||
props.grid.getEditorDialog().show(); |
|||
nextTick(() => { |
|||
props.grid.getEditorDialog().setTitle(t('action.edit')); |
|||
props.grid.getEditorForm().setStatus('edit'); |
|||
props.grid.getEditorForm().setData(selected); |
|||
props.grid.emit('afterEditorOpen', selected); |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const clone = (selected) => { |
|||
if (!selected) { |
|||
NotifyManager.warn(t('action.copy.tip')); |
|||
} else { |
|||
selected[props.grid.props.primaryKey] = undefined; |
|||
props.grid.getEditorDialog().show(); |
|||
nextTick(() => { |
|||
props.grid.getEditorDialog().setTitle(t('action.copy')); |
|||
props.grid.getEditorForm().setStatus('clone'); |
|||
props.grid.getEditorForm().setData(selected); |
|||
props.grid.emit('afterEditorOpen', selected); |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const remove = () => { |
|||
const ids = <any>[]; |
|||
const tickedRows = props.grid.getTickedRows(); |
|||
const selectedRows = props.grid.getSelectedRows(); |
|||
if (tickedRows?.length > 0) { |
|||
tickedRows.forEach((item) => { |
|||
ids.push(item[props.grid.props.primaryKey]); |
|||
}); |
|||
} else if (selectedRows?.length > 0) { |
|||
selectedRows.forEach((item) => { |
|||
ids.push(item[props.grid.props.primaryKey]); |
|||
}); |
|||
} |
|||
let requestParams: any = { |
|||
method: 'DELETE', |
|||
url: props.url.removeDataUrl || props.url.dataUrl, |
|||
data: ids, |
|||
}; |
|||
axios(requestParams) |
|||
.then((resp) => { |
|||
props.grid.emit('afterRemove', resp?.data); |
|||
NotifyManager.info(t('tip.operationSuccess')); |
|||
if (props.grid.props.refreshData || !props.grid.props.tree) { |
|||
props.grid.refresh(); |
|||
} else { |
|||
props.grid.removeRows(resp?.data); |
|||
} |
|||
}) |
|||
.catch((error) => { |
|||
console.error(error); |
|||
console.info('==========error==========', error); |
|||
}); |
|||
}; |
|||
|
|||
const getExportData = async () => { |
|||
let resultData = <any>[]; |
|||
const reqParams: any = { pageable: false }; |
|||
let urlSearchParams = props.buildQueryCriterias(reqParams); |
|||
const resp = await axios.get(props.url.fetchDataUrl || props.url.dataUrl, { params: urlSearchParams }); |
|||
if (resp && resp.data) { |
|||
const responseData = resp.data; |
|||
if (Array.isArray(responseData)) { |
|||
resultData = responseData; |
|||
} else if (typeof responseData === 'object' && responseData.content) { |
|||
resultData = responseData.content; |
|||
} |
|||
} |
|||
return resultData; |
|||
}; |
|||
|
|||
const wrapCsvValue = (val, formatFn, row) => { |
|||
let formatted = formatFn !== void 0 ? formatFn(val, row) : val; |
|||
formatted = formatted === void 0 || formatted === null ? '' : String(formatted); |
|||
formatted = formatted.split('"').join('""'); |
|||
/** |
|||
* Excel accepts \n and \r in strings, but some other CSV parsers do not |
|||
* Uncomment the next two lines to escape new lines |
|||
*/ |
|||
// .split('\n').join('\\n') |
|||
// .split('\r').join('\\r') |
|||
return `"${formatted}"`; |
|||
}; |
|||
|
|||
const resetDefaultValues = () => { |
|||
let requestParams: any = { |
|||
method: 'POST', |
|||
url: props.url.dataUrl + '/resetDefaultValues', |
|||
}; |
|||
axios(requestParams) |
|||
.then((resp) => { |
|||
NotifyManager.info(t('tip.operationSuccess')); |
|||
props.grid.refresh(); |
|||
}) |
|||
.catch((error) => { |
|||
console.error(error); |
|||
}); |
|||
}; |
|||
|
|||
const showLoading = (msg: string = '正在处理,请稍等...') => { |
|||
$q.loading.show({ |
|||
message: msg, |
|||
boxClass: 'bg-grey-2 text-grey-9', |
|||
spinnerColor: 'primary', |
|||
}); |
|||
}; |
|||
const hideLoading = () => { |
|||
$q.loading.hide(); |
|||
}; |
|||
|
|||
const buttonObj = reactive({ |
|||
separator: 'separator', |
|||
query: { |
|||
name: 'query', |
|||
icon: 'search', |
|||
labelI18nKey: 'action.query', |
|||
label: t('action.query'), |
|||
click: () => { |
|||
props.grid.refresh(); |
|||
}, |
|||
}, |
|||
moreQuery: { |
|||
name: 'moreQuery', |
|||
icon: 'zoom_in', |
|||
labelI18nKey: 'action.moreQueryConditions', |
|||
label: t('action.moreQueryConditions'), |
|||
enableIf: () => { |
|||
if (props.grid.props.queryFormFields.length <= fields.value.length && !moreQueryStatus.value) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
}, |
|||
click: () => { |
|||
moreQueryStatus.value = !moreQueryStatus.value; |
|||
handlerQueryFormShowField(); |
|||
}, |
|||
}, |
|||
reset: { |
|||
name: 'reset', |
|||
icon: 'restart_alt', |
|||
labelI18nKey: 'action.reset', |
|||
label: t('action.reset'), |
|||
click: () => { |
|||
formRef.value.reset(); |
|||
}, |
|||
}, |
|||
refresh: { |
|||
name: 'refresh', |
|||
icon: 'loop', |
|||
labelI18nKey: 'action.refresh', |
|||
label: t('action.refresh'), |
|||
click: () => { |
|||
props.grid.refresh(); |
|||
}, |
|||
}, |
|||
add: { |
|||
name: 'add', |
|||
icon: 'add', |
|||
labelI18nKey: 'action.addNew', |
|||
label: t('action.addNew'), |
|||
click: () => { |
|||
props.grid.getEditorDialog().show(); |
|||
nextTick(() => { |
|||
props.grid.getEditorDialog().setTitle(t('action.addNew')); |
|||
props.grid.getEditorForm().setStatus('add'); |
|||
props.grid.emit('afterEditorOpen'); |
|||
}); |
|||
}, |
|||
}, |
|||
edit: { |
|||
name: 'edit', |
|||
icon: 'edit', |
|||
labelI18nKey: 'action.edit', |
|||
label: t('action.edit'), |
|||
enableIf: (args) => { |
|||
if (args.selected) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
click: (args) => { |
|||
edit(args.selected); |
|||
}, |
|||
}, |
|||
rowEdit: { |
|||
name: 'rowEdit', |
|||
icon: 'border_color', |
|||
labelI18nKey: 'action.edit', |
|||
label: t('action.edit'), |
|||
enableIf: (args) => { |
|||
if (args.selected) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
click: (args) => { |
|||
table.bodyEditStatus = 'rowEdit'; |
|||
}, |
|||
}, |
|||
rowsEdit: { |
|||
name: 'rowsEdit', |
|||
icon: 'app_registration', |
|||
labelI18nKey: 'action.edit', |
|||
label: t('action.edit'), |
|||
click: (args) => { |
|||
table.bodyEditStatus = 'rowsEdit'; |
|||
// 清空勾选与选中 |
|||
props.grid.cleanSelected(); |
|||
props.grid.cleanTicked(); |
|||
table.allTicked = false; |
|||
}, |
|||
}, |
|||
clone: { |
|||
name: 'clone', |
|||
icon: 'content_copy', |
|||
labelI18nKey: 'action.copy', |
|||
label: t('action.copy'), |
|||
enableIf: (args) => { |
|||
if (args.selected) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
click: (args) => { |
|||
clone(args.selected); |
|||
}, |
|||
}, |
|||
remove: { |
|||
name: 'remove', |
|||
icon: 'delete', |
|||
labelI18nKey: 'action.remove', |
|||
label: t('action.remove'), |
|||
enableIf: (args) => { |
|||
if (args.ticked) { |
|||
return true; |
|||
} else if (args.selected) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
click: (tips: boolean = true) => { |
|||
if (!tips) { |
|||
remove(); |
|||
} else { |
|||
$q.dialog({ |
|||
title: t('confirm'), |
|||
message: t('action.remove.tip'), |
|||
cancel: { noCaps: true }, |
|||
ok: { noCaps: true }, |
|||
persistent: true, |
|||
}).onOk(() => { |
|||
remove(); |
|||
}); |
|||
} |
|||
}, |
|||
}, |
|||
view: { |
|||
name: 'view', |
|||
icon: 'visibility', |
|||
labelI18nKey: 'action.view', |
|||
label: t('action.view'), |
|||
enableIf: (args) => { |
|||
if (args.selected) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
props.grid.view(); |
|||
}, |
|||
}, |
|||
export: { |
|||
name: 'export', |
|||
icon: 'file_download', |
|||
labelI18nKey: 'action.export', |
|||
label: t('action.export'), |
|||
click: async () => { |
|||
showLoading(); |
|||
let exportData = props.grid.getRows(); |
|||
// 判断是否配置了 url, 以不分页形式请求后端获取全部数据一把导出。 |
|||
if (!Tools.isEmpty(props.grid.props.fetchDataUrl) || !Tools.isEmpty(props.grid.props.dataUrl)) { |
|||
const fetchResult = await getExportData(); |
|||
if (fetchResult && fetchResult.length > 0) { |
|||
exportData = fetchResult; |
|||
} |
|||
} |
|||
const content = [props.columns.map((col) => wrapCsvValue(col.label))] |
|||
.concat( |
|||
exportData.map((row) => |
|||
props.columns |
|||
.map((col) => wrapCsvValue(typeof col.field === 'function' ? col.field(row) : row[col.field === void 0 ? col.name : col.field], col.format, row)) |
|||
.join(','), |
|||
), |
|||
) |
|||
.join('\r\n'); |
|||
|
|||
const status = exportFile('table-export.csv', content, { |
|||
encoding: 'utf-8', |
|||
mimeType: 'text/csv', |
|||
byteOrderMark: '\uFEFF', // 解决乱码问题 |
|||
}); |
|||
|
|||
if (status !== true) { |
|||
NotifyManager.error(t('action.export.failed')); |
|||
} |
|||
hideLoading(); |
|||
}, |
|||
}, |
|||
addTop: { |
|||
name: 'addTop', |
|||
icon: 'add', |
|||
labelI18nKey: 'action.addTop', |
|||
label: t('action.addTop'), |
|||
click: () => { |
|||
props.grid.getEditorDialog().show(); |
|||
nextTick(() => { |
|||
props.grid.getEditorDialog().setTitle(t('action.addTop')); |
|||
props.grid.getEditorForm().setStatus('addTop'); |
|||
props.grid.emit('afterEditorOpen'); |
|||
}); |
|||
}, |
|||
}, |
|||
addChild: { |
|||
name: 'addChild', |
|||
icon: 'playlist_add', |
|||
labelI18nKey: 'action.addChild', |
|||
label: t('action.addChild'), |
|||
enableIf: (args) => { |
|||
if (args.selected) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
props.grid.getEditorDialog().show(); |
|||
nextTick(() => { |
|||
props.grid.getEditorDialog().setTitle(t('action.addChild')); |
|||
props.grid.getEditorForm().setStatus('addChild'); |
|||
props.grid.emit('afterEditorOpen'); |
|||
}); |
|||
}, |
|||
}, |
|||
expand: { |
|||
name: 'expand', |
|||
icon: (args) => { |
|||
return table.treeExpand ? 'expand_less' : 'expand_more'; |
|||
}, |
|||
label: (args) => { |
|||
return table.treeExpand ? t('action.collapseAll') : t('action.expandAll'); |
|||
}, |
|||
click: () => { |
|||
props.grid.expandFun(table.rows, table.treeExpand); |
|||
table.treeExpand = !table.treeExpand; |
|||
}, |
|||
}, |
|||
resetDefaultValues: { |
|||
name: 'resetDefaultValues', |
|||
icon: 'bi-copy', |
|||
labelI18nKey: 'action.resetDefaultValues', |
|||
label: t('action.resetDefaultValues'), |
|||
click: (tips: boolean = true) => { |
|||
if (!tips) { |
|||
resetDefaultValues(); |
|||
} else { |
|||
$q.dialog({ |
|||
title: t('confirm'), |
|||
message: t('action.resetDefaultValues.tip'), |
|||
cancel: { noCaps: true }, |
|||
ok: { noCaps: true }, |
|||
persistent: true, |
|||
}).onOk(() => { |
|||
resetDefaultValues(); |
|||
}); |
|||
} |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
// 处理toobar |
|||
const handleChildrenBtn = (arr, moreQueryShow) => { |
|||
const tempArr = <any>[]; |
|||
for (let i = 0; i < arr.length; i++) { |
|||
const btn = arr[i]; |
|||
if (Array.isArray(btn) && btn.length > 0) { |
|||
const handleResult = handleChildrenBtn(btn, moreQueryShow); |
|||
if (handleResult && handleResult.length > 0) { |
|||
tempArr.push(handleResult); |
|||
} |
|||
} else if (typeof btn === 'string' && buttonObj[btn]) { |
|||
if (btn === buttonObj.query.name && i === 0) { |
|||
// 查询按钮为第一个时,追加更多查询时直接追加到查询按钮当前所在下标的后面一个,不能追加为数组,否则按钮组取第一个为 QBtnDropdown 左边按钮时取到的是一个数组,会报错。 |
|||
// ['query', 'reset'] |
|||
tempArr.push(buttonObj[btn]); |
|||
tempArr.push(buttonObj[buttonObj.moreQuery.name]); |
|||
} else if (btn === buttonObj.query.name) { |
|||
tempArr.push([buttonObj[btn], buttonObj[buttonObj.moreQuery.name]]); |
|||
} else { |
|||
tempArr.push(buttonObj[btn]); |
|||
} |
|||
} else if (typeof btn === 'object' && btn.extend && buttonObj[btn.extend]) { |
|||
tempArr.push({ ...buttonObj[btn.extend], ...btn, _click: buttonObj[btn.extend].click }); |
|||
} else { |
|||
tempArr.push(btn); |
|||
} |
|||
} |
|||
return tempArr; |
|||
}; |
|||
const handleToolbarActions = () => { |
|||
buttons_.value.splice(0, buttons_.value.length); |
|||
// 处理查询按钮,符合条件时给其追加更多查询按钮 |
|||
let moreQueryShow = false; |
|||
const rowColsNum = queryFormColsNumComputed.value * (props.grid.props.queryFormRowNum || 1); |
|||
let currRowColsNum = 0; |
|||
let showQueryFormFieldNum = 0; |
|||
props.grid.props.queryFormFields.forEach((item: any) => { |
|||
if (Tools.hasOwnProperty(item, 'colSpan')) { |
|||
currRowColsNum += item.colSpan; |
|||
} else { |
|||
currRowColsNum += 1; |
|||
} |
|||
if (currRowColsNum <= rowColsNum) { |
|||
showQueryFormFieldNum += 1; |
|||
} |
|||
}); |
|||
if (showQueryFormFieldNum < props.grid.props.queryFormFields.length) { |
|||
moreQueryShow = true; |
|||
} |
|||
props.grid.props.toolbarActions.forEach((btn: any, index) => { |
|||
if (typeof btn === 'string' && buttonObj[btn]) { |
|||
if (btn === buttonObj.query.name && moreQueryShow) { |
|||
buttons_.value.push([buttonObj[btn], buttonObj[buttonObj.moreQuery.name]]); |
|||
} else { |
|||
buttons_.value.push(buttonObj[btn]); |
|||
} |
|||
} else if (Array.isArray(btn) && btn.length > 0) { |
|||
buttons_.value.push(handleChildrenBtn(btn, moreQueryShow)); |
|||
} else if (typeof btn === 'object' && btn.extend && buttonObj[btn.extend]) { |
|||
// 继承内置按钮 |
|||
buttons_.value.push({ ...buttonObj[btn.extend], ...btn, _click: buttonObj[btn.extend].click }); |
|||
} else { |
|||
buttons_.value.push(btn); |
|||
} |
|||
}); |
|||
if (buttons_.value.length > 0 && buttons_.value[buttons_.value.length - 1] !== 'separator' && props.grid.props.configButton) { |
|||
buttons_.value.push(buttonObj.separator); |
|||
} |
|||
}; |
|||
|
|||
const setLocaleFlag = () => { |
|||
localeFlag.value = !localeFlag.value; |
|||
}; |
|||
const resetLabel = () => { |
|||
Object.keys(buttonObj).forEach((btn) => { |
|||
if (typeof buttonObj[btn] === 'object' && buttonObj[btn].labelI18nKey) { |
|||
buttonObj[btn].label = t(buttonObj[btn].labelI18nKey); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
const buttonClick = (arr) => { |
|||
arr.forEach((button) => { |
|||
if (typeof button === 'object' && !Tools.isEmpty(button.click) && props.grid.props.dbClickOperation === button.name) { |
|||
toolbarRef.value.buttonClick(button); |
|||
} else if (Array.isArray(button) && button.length > 0) { |
|||
buttonClick(button); |
|||
} |
|||
}); |
|||
}; |
|||
const dbClickOperation = (row) => { |
|||
if (!Tools.isEmpty(row) && props.grid.props.dbClickOperation === buttonObj.expand.name) { |
|||
row['expand'] = Tools.isEmpty(row['expand']) ? true : !row['expand']; |
|||
} else { |
|||
buttonClick(buttons_.value); |
|||
} |
|||
}; |
|||
const getQueryForm = () => { |
|||
return formRef.value; |
|||
}; |
|||
|
|||
onBeforeMount(() => { |
|||
handleToolbarActions(); |
|||
}); |
|||
|
|||
defineExpose({ |
|||
setLocaleFlag, |
|||
edit, |
|||
handlerQueryFormShowField, |
|||
handleToolbarActions, |
|||
resetLabel, |
|||
dbClickOperation, |
|||
getQueryForm, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="css"></style> |
@ -0,0 +1,100 @@ |
|||
<template> |
|||
<w-drawer ref="drawerRef" :title="$t('action.view')" v-bind="props.grid.props.viewer.drawer"> |
|||
<div class="p-2.5"> |
|||
<w-info-panel ref="infoRef" v-bind="props.grid.props.viewer.panel" :info="infoArray"></w-info-panel> |
|||
</div> |
|||
</w-drawer> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { t, Tools, NotifyManager } from '@/platform'; |
|||
|
|||
const drawerRef = ref(); |
|||
const infoRef = ref(); |
|||
|
|||
const props = defineProps({ |
|||
grid: { |
|||
// 表格实例 |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
tableColumnsMap: { |
|||
type: Map, |
|||
default: () => { |
|||
return new Map(); |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
const infoArray = ref(<any>[]); |
|||
|
|||
const view = () => { |
|||
const selected = props.grid.getSelectedRow(); |
|||
if (!selected) { |
|||
NotifyManager.warn(t('action.view.tip')); |
|||
} else { |
|||
infoArray.value = []; |
|||
if (props.grid.props.viewer.panel.fields && props.grid.props.viewer.panel.fields.length > 0) { |
|||
for (let item of props.grid.props.viewer.panel.fields) { |
|||
if (item.format) { |
|||
let value = selected[item.name]; |
|||
try { |
|||
value = item.format(selected[item.name], selected[0]); |
|||
} catch (error) { |
|||
console.error('format error!'); |
|||
} |
|||
infoArray.value.push({ label: item.label, value: value, originalValue: selected[item.name] }); |
|||
} else { |
|||
let value = null; |
|||
if (props.tableColumnsMap.get(item.name) && !Tools.isEmpty(props.tableColumnsMap.get(item.name).format)) { |
|||
value = selected[item.name]; |
|||
try { |
|||
value = props.tableColumnsMap.get(item.name).format(selected[item.name], selected); |
|||
} catch (error) { |
|||
console.error('format error!'); |
|||
} |
|||
} else { |
|||
value = selected[item.name]; |
|||
} |
|||
infoArray.value.push({ label: item.label, value: value, originalValue: selected[item.name] }); |
|||
} |
|||
} |
|||
} else { |
|||
for (let item of props.tableColumnsMap) { |
|||
if (item[1].format) { |
|||
let value = selected[item[0]]; |
|||
try { |
|||
value = item[1].format(selected[item[0]], selected); |
|||
} catch (error) { |
|||
console.error('format error!'); |
|||
} |
|||
infoArray.value.push({ label: item[1].label, value: value, originalValue: selected[item.name] }); |
|||
} else { |
|||
infoArray.value.push({ |
|||
label: item[1].label, |
|||
value: selected[item[0]], |
|||
originalValue: selected[item.name], |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
drawerRef.value.show(); |
|||
} |
|||
}; |
|||
|
|||
const getViewerDrawer = () => { |
|||
return drawerRef.value; |
|||
}; |
|||
const getInfoPanel = () => { |
|||
return infoRef.value; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
getViewerDrawer, |
|||
getInfoPanel, |
|||
view, |
|||
}); |
|||
</script> |
|||
<style lang="css"></style> |
File diff suppressed because it is too large
@ -1,39 +0,0 @@ |
|||
<template> |
|||
<q-table :binary-state-sort="true" column-sort-order="ad" :v-bind="attrs"> |
|||
<template #top> |
|||
<div class="row"> |
|||
<div class="col">{{ attrs.title }}</div> |
|||
<div class="col items-end"> |
|||
<q-btn label="dksfj"></q-btn> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</q-table> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { useAttrs } from 'vue'; |
|||
import { useI18n } from 'vue-i18n'; |
|||
import { Tools } from '@/platform/utils/Tools'; |
|||
|
|||
const attrs = useAttrs(); |
|||
const { t } = useI18n(); |
|||
|
|||
for (const column of attrs.columns) { |
|||
if (Tools.isUndefinedOrNull(column.label)) { |
|||
column.label = t(column.name); |
|||
} |
|||
if (Tools.isUndefinedOrNull(column.field)) { |
|||
column.field = column.name; |
|||
} |
|||
if (Tools.isUndefinedOrNull(column.align)) { |
|||
column.align = 'left'; |
|||
} |
|||
if (Tools.isUndefinedOrNull(column.sortable)) { |
|||
column.sortable = true; |
|||
} |
|||
if (Tools.isUndefinedOrNull(column.sortOrder)) { |
|||
column.sortOrder = 'da'; |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,645 @@ |
|||
.w-grid .q-table__top { |
|||
padding: var(--tableTopPadding) var(--tableTopPadding); |
|||
} |
|||
.w-grid .q-table__middle .q-table th { |
|||
padding: var(--tableHeaderPadding) 8px; |
|||
border-left-width: 0px; |
|||
border-right-width: 1px; |
|||
border-top-width: 0px; |
|||
border-bottom-width: 1px; |
|||
} |
|||
.w-grid .q-table__middle .q-table th:last-child { |
|||
border-right-width: 0px; |
|||
} |
|||
.w-grid .q-table__middle .q-table td { |
|||
height: var(--tableBodyHeight); |
|||
padding: var(--tableBodyPadding) 8px; |
|||
border-left-width: 0px; |
|||
border-right-width: 1px; |
|||
border-top-width: 0px; |
|||
border-bottom-width: 1px; |
|||
} |
|||
.w-grid .q-table__middle .q-table td:last-child { |
|||
border-right-width: 0px; |
|||
} |
|||
.w-grid .q-table__bottom { |
|||
min-height: var(--tableBottomHeight); |
|||
border-color: rgba(0, 0, 0, 0.12); |
|||
border-style: solid; |
|||
border-top-width: 0px; |
|||
border-left-width: 1px; |
|||
border-right-width: 1px; |
|||
border-bottom-width: 1px; |
|||
} |
|||
.w-grid .q-table__control .q-field__control { |
|||
min-height: var(--tableBottomButtonHeight) !important; |
|||
} |
|||
.w-grid .q-table__control .q-field__control q-field__append { |
|||
height: var(--tableBottomButtonHeight) !important; |
|||
} |
|||
.w-grid .q-table__control .q-field__control-container .q-field__native { |
|||
min-height: var(--tableBottomButtonHeight) !important; |
|||
padding: 0 !important; |
|||
} |
|||
.w-grid .q-table__control .q-field__control .q-field__marginal { |
|||
height: var(--tableBottomButtonHeight) !important; |
|||
} |
|||
.w-grid .q-table__card .q-table__middle { |
|||
border-color: rgba(0, 0, 0, 0.12); |
|||
border-style: solid; |
|||
border-left-width: 1px; |
|||
border-right-width: 1px; |
|||
border-bottom-width: 1px; |
|||
} |
|||
|
|||
.sticky-header-column-table thead tr:not(.noDataTr) { |
|||
height: var(--tableColumnTitleHeight) !important; |
|||
} |
|||
|
|||
/** 表格所有th固定、设置默认index、背景设置 */ |
|||
.sticky-header-column-table tr th { |
|||
position: sticky; |
|||
z-index: 2; |
|||
background: var(--tableHeadBgColor); |
|||
} |
|||
|
|||
/** 固定表头后,修改top距离 */ |
|||
.sticky-header-column-table thead { |
|||
position: sticky; |
|||
z-index: 2; |
|||
top: 0; |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-1-1 tr:first-child th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-1-2 tr:first-child th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-2-rb tr:first-child th:nth-child(2) { |
|||
border-right-width: 1px; |
|||
} |
|||
.sticky-header-column-table-tr-1-3 tr:first-child th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-4 tr:first-child th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-5 tr:first-child th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-6 tr:first-child th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-7 tr:first-child th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-8 tr:first-child th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-9 tr:first-child th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-1-10 tr:first-child th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-2-1 tr:nth-child(2) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-2-2 tr:nth-child(2) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-3 tr:nth-child(2) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-4 tr:nth-child(2) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-5 tr:nth-child(2) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-6 tr:nth-child(2) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-7 tr:nth-child(2) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-8 tr:nth-child(2) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-9 tr:nth-child(2) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-2-10 tr:nth-child(2) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-3-1 tr:nth-child(3) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-3-2 tr:nth-child(3) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-3 tr:nth-child(3) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-4 tr:nth-child(3) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-5 tr:nth-child(3) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-6 tr:nth-child(3) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-7 tr:nth-child(3) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-8 tr:nth-child(3) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-9 tr:nth-child(3) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-3-10 tr:nth-child(3) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-4-1 tr:nth-child(4) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-4-2 tr:nth-child(4) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-3 tr:nth-child(4) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-4 tr:nth-child(4) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-5 tr:nth-child(4) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-6 tr:nth-child(4) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-7 tr:nth-child(4) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-8 tr:nth-child(4) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-9 tr:nth-child(4) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-4-10 tr:nth-child(4) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-5-1 tr:nth-child(5) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-5-2 tr:nth-child(5) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-3 tr:nth-child(5) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-4 tr:nth-child(5) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-5 tr:nth-child(5) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-6 tr:nth-child(5) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-7 tr:nth-child(5) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-8 tr:nth-child(5) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-9 tr:nth-child(5) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-5-10 tr:nth-child(5) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-6-1 tr:nth-child(6) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-6-2 tr:nth-child(6) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-3 tr:nth-child(6) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-4 tr:nth-child(6) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-5 tr:nth-child(6) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-6 tr:nth-child(6) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-7 tr:nth-child(6) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-8 tr:nth-child(6) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-9 tr:nth-child(6) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-6-10 tr:nth-child(6) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-7-1 tr:nth-child(7) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-7-2 tr:nth-child(7) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-3 tr:nth-child(7) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-4 tr:nth-child(7) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-5 tr:nth-child(7) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-6 tr:nth-child(7) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-7 tr:nth-child(7) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-8 tr:nth-child(7) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-9 tr:nth-child(7) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-7-10 tr:nth-child(7) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-8-1 tr:nth-child(8) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-8-2 tr:nth-child(8) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-3 tr:nth-child(8) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-4 tr:nth-child(8) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-5 tr:nth-child(8) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-6 tr:nth-child(8) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-7 tr:nth-child(8) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-8 tr:nth-child(8) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-9 tr:nth-child(8) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-8-10 tr:nth-child(8) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-9-1 tr:nth-child(9) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-9-2 tr:nth-child(9) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-3 tr:nth-child(9) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-4 tr:nth-child(9) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-5 tr:nth-child(9) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-6 tr:nth-child(9) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-7 tr:nth-child(9) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-8 tr:nth-child(9) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-9 tr:nth-child(9) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-9-10 tr:nth-child(9) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-tr-10-1 tr:nth-child(10) th:first-child { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-tr-10-2 tr:nth-child(10) th:nth-child(2) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-3 tr:nth-child(10) th:nth-child(3) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-4 tr:nth-child(10) th:nth-child(4) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-5 tr:nth-child(10) th:nth-child(5) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-6 tr:nth-child(10) th:nth-child(6) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-7 tr:nth-child(10) th:nth-child(7) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-8 tr:nth-child(10) th:nth-child(8) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-9 tr:nth-child(10) th:nth-child(9) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-tr-10-10 tr:nth-child(10) th:nth-child(10) { |
|||
z-index: 3; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
|||
|
|||
.sticky-header-column-table-td-1 td:first-child { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: 0px; |
|||
} |
|||
.sticky-header-column-table-td-2 td:nth-child(2) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column1Width); |
|||
} |
|||
.sticky-header-column-table-td-3 td:nth-child(3) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column2Width); |
|||
} |
|||
.sticky-header-column-table-td-4 td:nth-child(4) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column3Width); |
|||
} |
|||
.sticky-header-column-table-td-5 td:nth-child(5) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column4Width); |
|||
} |
|||
.sticky-header-column-table-td-6 td:nth-child(6) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column5Width); |
|||
} |
|||
.sticky-header-column-table-td-7 td:nth-child(7) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column6Width); |
|||
} |
|||
.sticky-header-column-table-td-8 td:nth-child(8) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column7Width); |
|||
} |
|||
.sticky-header-column-table-td-9 td:nth-child(9) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column8Width); |
|||
} |
|||
.sticky-header-column-table-td-10 td:nth-child(10) { |
|||
background-color: var(--stickyBgColor); |
|||
z-index: 1; |
|||
position: sticky; |
|||
left: var(--column9Width); |
|||
} |
@ -0,0 +1,59 @@ |
|||
import { Tools, t, componentRegistryName } from '@/platform'; |
|||
|
|||
// 列样式处理
|
|||
const columnStyle = (item: any) => { |
|||
let style = ''; |
|||
if (Tools.hasOwnProperty(item, 'style')) { |
|||
style = item.style; |
|||
} |
|||
if (Tools.hasOwnProperty(item, 'width')) { |
|||
if (typeof item.width === 'number') { |
|||
item.style = `min-width: ` + item.width + `px; width: ` + item.width + `px;max-width: ` + item.width + `px;` + style; |
|||
} else { |
|||
item.style = `min-width: ` + item.width + `; width: ` + item.width + `;max-width: ` + item.width + `;` + style; |
|||
} |
|||
delete item.width; |
|||
|
|||
if (Tools.hasOwnProperty(item, 'classes')) { |
|||
item.classes = item.classes + ' truncate'; |
|||
} else { |
|||
item.classes = 'truncate'; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// 孩子列处理
|
|||
const childrenHandler = (item: any, gridColumns: any) => { |
|||
if (item.columns && item.columns.length > 0) { |
|||
item.columns.forEach((column) => { |
|||
childrenHandler(column, gridColumns); |
|||
}); |
|||
} else { |
|||
columnStyle(item); |
|||
// 替换行编辑类型为注册名
|
|||
if (!Tools.isEmpty(item.type)) { |
|||
item.type = componentRegistryName(item.type); |
|||
} |
|||
const col = { |
|||
...{ align: 'left', label: item.name, field: item.name, name: item.name, sortable: true, hidden: false }, |
|||
...item, |
|||
}; |
|||
if (Tools.isEmpty(col.name)) { |
|||
col.name = Tools.uuid(); |
|||
} |
|||
gridColumns.push(col); |
|||
} |
|||
}; |
|||
|
|||
// 列的默认属性
|
|||
export const columnDefaultProps = (columns: any, sortNo: boolean = true) => { |
|||
const gridColumns = <any>[]; |
|||
if (columns && columns.length > 0) { |
|||
gridColumns.push({ name: '_sortNo_', align: 'center', label: t('rownum'), field: '_sortNo_', hidden: sortNo }); |
|||
columns.forEach((item: any) => { |
|||
childrenHandler(item, gridColumns); |
|||
}); |
|||
return gridColumns; |
|||
} |
|||
return []; |
|||
}; |
@ -1,334 +0,0 @@ |
|||
import { Tools } from '@/platform/utils'; |
|||
/** |
|||
* 抽取窗口组件属性 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 窗口组件属性 |
|||
*/ |
|||
export function extractDialogProps(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.persistent = props.persistent; // 设置后,用户在对话框外单击或按 ESC 键时不再关闭对话框;此外,应用程序路由更改也不会关闭它
|
|||
result.noEscDismiss = props.noEscDismiss; // 用户不能按 ESC 键关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
|
|||
result.noBackdropDismiss = props.noBackdropDismiss; // 用户不能通过单击对话框外部来关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
|
|||
result.noRouteDismiss = props.noRouteDismiss; // 更改路由应用程序不会关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
|
|||
result.autoClose = props.autoClose; // 对话框内的任何单击/点击都将关闭它
|
|||
result.noShake = props.noShake; // 不要晃动对话框来引起用户的注意。
|
|||
result.allowFocusOutside = props.allowFocusOutside; // 允许对话框外的元素可聚焦;出于辅助功能的原因,默认情况下 QDialog 不允许外部聚焦.
|
|||
result.seamless = props.seamless; // 使对话框进入无缝模式;不使用背景,因此用户也可以与页面的其他部分进行交互
|
|||
result.position = props.position; // 将对话框附着到一侧(默认:standard、top、right、bottom、left)
|
|||
result.square = props.square; // 强制内容具有方形边框
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 抽取form表单组件属性 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 表单组件属性 |
|||
*/ |
|||
export function extractFormProps(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.autofocus = props.autofocus; // 在初始组件渲染时将第一个可聚焦元素聚焦
|
|||
result.greedy = props.greedy; // 验证表单中的所有字段(默认情况下,它在通过同步的验证找到第一个无效字段后停止)
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 抽取表单项组件属性 |
|||
* @param {String} type 组件类型 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 表单项组件属性 |
|||
*/ |
|||
export function extractFormItemComponentProps(type: string, props: any) { |
|||
if ('dateRange' === type) { |
|||
return dateRange(props); |
|||
} else if ('date' === type) { |
|||
return date(props); |
|||
} else if ('select' === type) { |
|||
return select(props); |
|||
} else if ('checkbox' === type) { |
|||
return checkbox(props); |
|||
} else if ('optionGroup' === type) { |
|||
return optionGroup(props); |
|||
} else { |
|||
return input(props); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* input组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function input(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.prefix = props.prefix; // 前缀
|
|||
result.suffix = props.suffix; // 后缀
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.counter = props.counter; // 在右下角显示自动计数器(字符数)
|
|||
result.autogrow = props.autogrow; // 使字段及其内容自动增长(内容过长时组件变高,内容换行)
|
|||
result.maxlength = props.maxlength; // 指定模型的最大长度
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
result.type = props.type; // 组件类型
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 日期范围组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function dateRange(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 日期组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function date(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 下拉框组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function select(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.prefix = props.prefix; // 前缀
|
|||
result.suffix = props.suffix; // 后缀
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.counter = props.counter; // 在右下角显示自动计数器(字符数)
|
|||
result.useInput = props.useInput; // 使用一个输入标签,用户可以在其中输入
|
|||
result.autogrow = props.autogrow; // 使字段及其内容自动增长(内容过长时组件变高,内容换行)
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
result.multiple = props.multiple; // 支持多选
|
|||
result.options = props.options; // 下拉选项集合
|
|||
result.maxValues = props.maxValues; // 允许用户可以进行的最大选择数
|
|||
result.useChips = props.useChips; // 使用QChip显示当前选择的内容
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 复选框组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function checkbox(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.keepColor = props.keepColor; // 当组件未勾选/关闭时,是否应保留颜色?
|
|||
result.checkedIcon = props.checkedIcon; // 此图标将会在 model 值为 true 时被使用(代替默认的设计)
|
|||
result.uncheckedIcon = props.uncheckedIcon; // 此图标将会在 model 值为 false 时被使用(代替默认的设计)
|
|||
result.toggleIndeterminate = props.toggleIndeterminate ?? false; // 当用户点击组件时,除 true 和 false 外,是否还添加一个不确定(indeterminate)的状态?
|
|||
result.leftLabel = props.leftLabel; // 如有标签,应显示在组件的左侧
|
|||
result.trueValue = props.trueValue; // model 为何值时被视为选中/勾选/启用?
|
|||
result.falseValue = props.falseValue; // model 为何值时被视为未选中/未勾选/关闭?
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.size = props.size; // 带有 CSS 单位的尺寸大小,包括单位的名称或标准大小名称(xs | sm | md | lg | xl)
|
|||
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
|
|||
result.dense = props.dense; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 选项组组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function optionGroup(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.name = props.name; // 用于指定控件的名称;如果处理直接提交到 URL 的表单时很有用
|
|||
result.keepColor = props.keepColor; // 当组件未勾选/关闭时,是否应保留颜色?
|
|||
result.type = props.optionGroupType; // 要使用的输入组件类型,默认radio,可选:radio、checkbox、toggle
|
|||
result.leftLabel = props.leftLabel; // 如有标签,应显示在组件的左侧
|
|||
result.inline = props.inline ?? true; // 将输入组件显示为内联块,而不是每个组件都有自己的行
|
|||
result.options = props.options; //具有值、标签和禁用(可选)属性的对象数组,包含的属性:label、value、disable等
|
|||
result.disable = props.disable; // 将组件置于禁用模式下
|
|||
result.size = props.size; // 带有 CSS 单位的尺寸大小,包括单位的名称或标准大小名称(xs | sm | md | lg | xl)
|
|||
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
|
|||
result.dense = props.dense; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 抽取表格组件属性 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 表格组件属性 |
|||
*/ |
|||
export function extractTableProps(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
|
|||
result.dense = props.dense; // 密恐模式;
|
|||
result.dark = props.dark; // 设置组件背景为深色
|
|||
result.flat = props.flat; // 应用“平面”设计(无默认阴影)
|
|||
result.bordered = props.bordered; // 将默认边框应用于组件
|
|||
result.square = props.square; // 删除边框圆角(border-radius),使边框为正方形
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
function columnStyle(item: any) { |
|||
let style = ''; |
|||
if (Tools.hasOwnProperty(item, 'style')) { |
|||
style = item.style; |
|||
} |
|||
if (Tools.hasOwnProperty(item, 'width')) { |
|||
if (typeof item.width === 'number') { |
|||
item.style = `min-width: ` + item.width + `px; width: ` + item.width + `px;max-width: ` + item.width + `px;` + style; |
|||
} else { |
|||
item.style = `min-width: ` + item.width + `; width: ` + item.width + `;max-width: ` + item.width + `;` + style; |
|||
} |
|||
delete item.width; |
|||
|
|||
if (Tools.hasOwnProperty(item, 'classes')) { |
|||
item.classes = item.classes + ' truncate'; |
|||
} else { |
|||
item.classes = 'truncate'; |
|||
} |
|||
} |
|||
} |
|||
function columnChildrenHandler(item: any, gridColumns: any) { |
|||
if (item.columns && item.columns.length > 0) { |
|||
item.columns.forEach((column) => { |
|||
columnChildrenHandler(column, gridColumns); |
|||
}); |
|||
} else { |
|||
columnStyle(item); |
|||
gridColumns.push({ |
|||
...{ align: 'left', label: item.name, field: item.name, sortable: true, hidden: false }, |
|||
...item, |
|||
}); |
|||
} |
|||
} |
|||
/** |
|||
* 处理表格列属性 |
|||
*/ |
|||
export function extractTableColumnsProps(props: any) { |
|||
const gridColumns = <any>[]; |
|||
if (props.columns && props.columns.length > 0) { |
|||
gridColumns.push({ name: '_sortNo_', align: 'center', label: '序号', field: '_sortNo_', hidden: props.sortNo ? false : true }); |
|||
props.columns.forEach((item: any) => { |
|||
columnChildrenHandler(item, gridColumns); |
|||
}); |
|||
return gridColumns; |
|||
} |
|||
return []; |
|||
} |
|||
|
|||
const formColsScreenMap = new Map(); |
|||
formColsScreenMap.set(1, { xs: 1, sm: 1, md: 2, lg: 3, xl: 4 }); |
|||
formColsScreenMap.set(2, { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }); |
|||
formColsScreenMap.set(3, { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 }); |
|||
formColsScreenMap.set(4, { xs: 1, sm: 2, md: 4, lg: 4, xl: 6 }); |
|||
formColsScreenMap.set(5, { xs: 1, sm: 2, md: 5, lg: 6, xl: 6 }); |
|||
formColsScreenMap.set(6, { xs: 1, sm: 3, md: 6, lg: 6, xl: 6 }); |
|||
formColsScreenMap.set(7, { xs: 1, sm: 4, md: 7, lg: 7, xl: 7 }); |
|||
formColsScreenMap.set(8, { xs: 1, sm: 4, md: 8, lg: 8, xl: 8 }); |
|||
formColsScreenMap.set(9, { xs: 1, sm: 4, md: 9, lg: 9, xl: 9 }); |
|||
formColsScreenMap.set(10, { xs: 1, sm: 4, md: 10, lg: 10, xl: 10 }); |
|||
formColsScreenMap.set(11, { xs: 1, sm: 4, md: 11, lg: 11, xl: 11 }); |
|||
formColsScreenMap.set(12, { xs: 1, sm: 4, md: 12, lg: 12, xl: 12 }); |
|||
/** |
|||
* 根据设置的每列显示数、屏幕断点获取当前查询表单每行显示多少个字段 |
|||
* @param configColsNumber |
|||
* @param screen |
|||
*/ |
|||
export function getQueryFormColsNumberByScreen(configColsNumber: number, screen: any) { |
|||
return formColsScreenMap.get(configColsNumber)[screen]; |
|||
} |
|||
|
|||
/** |
|||
* 集合根据传入的key转map |
|||
* @param key |
|||
* @param array |
|||
*/ |
|||
export function arrayToMap(key, array) { |
|||
const map = new Map(); |
|||
array.forEach((item) => { |
|||
if (item.name !== '_sortNo_') { |
|||
map.set(item[key], item); |
|||
} |
|||
}); |
|||
return map; |
|||
} |
@ -0,0 +1,18 @@ |
|||
<template> |
|||
<template v-if="props.value && typeof props.value === 'object' && props.value.componentType"> |
|||
<component :is="props.value.componentType" v-bind="props.value.attrs"></component> |
|||
</template> |
|||
<template v-else-if="props.value"> |
|||
{{ props.value }} |
|||
{{ props.value }} |
|||
</template> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
const props = defineProps({ |
|||
value: { |
|||
type: [Object, String, Number, Boolean], |
|||
default: '', |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="css"></style> |
@ -1,752 +1,69 @@ |
|||
<!-- <template> |
|||
<q-splitter :model-value="65" class="w-full h-full"> |
|||
<template #before> |
|||
<div class="px-1"> |
|||
<w-grid |
|||
ref="userGridRef" |
|||
:title="$t('system.user.grid.title')" |
|||
selection="multiple" |
|||
:query-form-fields="[ |
|||
{ name: 'loginName', label: $t('loginName'), type: 'text' }, |
|||
{ name: 'userName', label: $t('userName'), type: 'text' }, |
|||
{ name: 'enable', label: $t('isEnable'), type: 'select', options: Options.yesNo() }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select', options: Options.enum(DataComeFromEnum) }, |
|||
]" |
|||
:toolbar-configure="{ noIcon: false }" |
|||
:toolbar-actions="[ |
|||
'query', |
|||
'refresh', |
|||
'separator', |
|||
'add', |
|||
'clone', |
|||
'edit', |
|||
'remove', |
|||
'separator', |
|||
{ |
|||
name: 'setPassword', |
|||
label: t('system.user.action.setPassword'), |
|||
icon: 'bi-shield-check', |
|||
enableIf: function (selecteds) { |
|||
return selecteds.length > 0; |
|||
}, |
|||
click: function (selecteds) { |
|||
setPasswordDialogRef.open('setPassword', selecteds); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'setAllPassword', |
|||
label: t('system.user.action.setAllPassword'), |
|||
icon: 'bi-shield', |
|||
enableIf: function (selecteds) { |
|||
return true; |
|||
}, |
|||
click: function () { |
|||
setPasswordDialogRef.open('setAllPassword'); |
|||
}, |
|||
}, |
|||
'separator', |
|||
{ |
|||
name: 'resetPassword', |
|||
label: t('system.user.action.resetPassword'), |
|||
icon: 'bi-shield-fill-check', |
|||
enableIf: function (selecteds) { |
|||
return selecteds.length > 0; |
|||
}, |
|||
click: function (selecteds) { |
|||
DialogManager.confirm(t('system.user.confirm.resetPassword'), () => { |
|||
const userIds = Tools.extractProperties(selecteds, 'id'); |
|||
axios.post(Environment.apiContextPath('/api/system/user/resetPassword'), userIds).then(() => { |
|||
NotifyManager.info(t('operationSuccess')); |
|||
}); |
|||
}); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'resetAllPassword', |
|||
label: t('system.user.action.resetAllPassword'), |
|||
icon: 'bi-shield-fill', |
|||
enableIf: function (selecteds) { |
|||
return true; |
|||
}, |
|||
click: function () { |
|||
DialogManager.confirm(t('system.user.confirm.resetAllPassword'), () => { |
|||
axios.post(Environment.apiContextPath('/api/system/user/resetAllPassword')).then(() => { |
|||
setPasswordDialogRef.value.hide(); |
|||
NotifyManager.info(t('operationSuccess')); |
|||
}); |
|||
}); |
|||
}, |
|||
}, |
|||
'separator', |
|||
'view', |
|||
'export', |
|||
]" |
|||
:data-url="Environment.apiContextPath('/api/system/user')" |
|||
row-key="id" |
|||
:columns="[ |
|||
{ name: 'loginName', label: t('loginName') }, |
|||
{ name: 'userName', label: t('userName') }, |
|||
{ |
|||
name: 'status', |
|||
label: t('status'), |
|||
format: (value, row) => { |
|||
return { |
|||
componentType: UserStatusTag, |
|||
attrs: row, |
|||
}; |
|||
}, |
|||
}, |
|||
{ name: 'dataComeFrom', label: t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ name: 'lastModifier', label: t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: t('lastModifyDate'), format: Formater.dateOnly() }, |
|||
]" |
|||
:editor="{ |
|||
dialog: { |
|||
width: '600px', |
|||
height: '610px', |
|||
}, |
|||
form: { |
|||
colsNum: 4, |
|||
fields: [ |
|||
{ name: 'loginName', label: t('loginName'), type: 'text', required: true, colspan: 4 }, |
|||
{ name: 'userName', label: t('userName'), type: 'text', required: true, colspan: 4 }, |
|||
{ name: 'description', label: t('description'), type: 'textarea', rows: 1, colspan: 4 }, |
|||
{ name: 'password', label: t('password'), type: 'password', colspan: 4 }, |
|||
{ |
|||
name: 'confirmPassword', |
|||
label: t('confirmPassword'), |
|||
type: 'password', |
|||
colspan: 4, |
|||
rules: [ |
|||
(value) => { |
|||
return Tools.stringEquals(userGridRef.getAddEditFormRef().value.getData().password, value) |
|||
? true |
|||
: t('passwordAndConfirmPasswordMustEqual'); |
|||
}, |
|||
], |
|||
}, |
|||
{ name: 'mobile', label: t('mobile'), type: 'text', colsFirst: true, colspan: 4 }, |
|||
{ name: 'phone', label: t('phone'), type: 'text', colsFirst: true, colspan: 4 }, |
|||
{ name: 'email', label: t('email'), type: 'text', colsFirst: true, colspan: 4 }, |
|||
{ name: 'weixin', label: t('weixin'), type: 'text', colsFirst: true, colspan: 4 }, |
|||
{ name: 'qq', label: t('qq'), type: 'text', colsFirst: true, colspan: 4 }, |
|||
|
|||
{ name: 'enable', label: t('enable'), type: 'checkbox', defaultValue: true }, |
|||
{ name: 'accountExpired', label: t('accountExpired'), type: 'checkbox', defaultValue: false }, |
|||
{ name: 'accountLocked', label: t('accountLocked'), type: 'checkbox', defaultValue: false }, |
|||
{ name: 'credentialsExpired', label: t('credentialsExpired'), type: 'checkbox', defaultValue: false }, |
|||
], |
|||
}, |
|||
}" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: t('id') }, |
|||
{ name: 'loginName', label: t('loginName') }, |
|||
{ name: 'userName', label: t('userName') }, |
|||
{ name: 'description', label: t('description') }, |
|||
{ name: 'enable', label: t('enable'), format: Formater.yesNo() }, |
|||
{ name: 'accountExpired', label: t('accountExpired'), format: Formater.yesNo() }, |
|||
{ name: 'accountLocked', label: t('accountLocked'), format: Formater.yesNo() }, |
|||
{ name: 'credentialsExpired', label: t('credentialsExpired'), format: Formater.yesNo() }, |
|||
{ name: 'email', label: t('email') }, |
|||
{ name: 'phone', label: t('phone') }, |
|||
{ name: 'mobile', label: t('mobile') }, |
|||
{ name: 'weixin', label: t('weixin') }, |
|||
{ name: 'qq', label: t('qq') }, |
|||
{ name: 'dataComeFrom', label: t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ name: 'creator', label: t('creator') }, |
|||
{ name: 'createDate', label: t('createDate') }, |
|||
{ name: 'lastModifier', label: t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
@row-click=" |
|||
(evt, row, index) => { |
|||
currentSelectedUserId = row.id; |
|||
roleQueryUrl = Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + currentSelectedUserId; |
|||
orgQueryUrl = Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + currentSelectedUserId; |
|||
roleGridRef?.refresh(); |
|||
orgTreeGridRef?.refresh(); |
|||
// if (roleGridRef) { |
|||
// roleGridRef.setFetchDataUrl(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + row.id); |
|||
// } |
|||
// if (orgTreeGridRef) { |
|||
// orgTreeGridRef.setFetchDataUrl(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + row.id); |
|||
// orgTreeGridRef.refresh(); |
|||
// } |
|||
} |
|||
" |
|||
></w-grid> |
|||
</div> |
|||
</template> |
|||
<template #after> |
|||
<div class="px-1"> |
|||
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0"> |
|||
<q-tab name="role" icon="bi-people" :label="$t('role')" /> |
|||
<q-tab name="org" icon="bi-diagram-3" :label="$t('org')" /> |
|||
</q-tabs> |
|||
|
|||
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive class=""> |
|||
<q-tab-panel name="role" class="p-0"> |
|||
<w-grid |
|||
ref="roleGridRef" |
|||
:title="$t('system.role.grid.title')" |
|||
:data-url="roleQueryUrl" |
|||
:auto-fetch-data="false" |
|||
selection="multiple" |
|||
:full-screen-button="false" |
|||
:toolbar-configure="{ noIcon: true }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
name: 'addRole', |
|||
label: $t('system.role.action.addRole'), |
|||
enableIf: () => { |
|||
if (userGridRef) { |
|||
return userGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
selectRoleDialog.open({ userId: userGridRef.getSelectedRows()[0].id, userGrid: userGridRef, roleGrid: roleGridRef }); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'addAllRole', |
|||
label: t('system.role.action.addAllRole'), |
|||
enableIf: () => { |
|||
if (userGridRef) { |
|||
return userGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
const selectedUser = userGridRef.getSelectedRows()[0]; |
|||
DialogManager.confirm( |
|||
t('system.role.action.addAllRole.confirm', { userLoginName: selectedUser.loginName, userName: selectedUser.userName }), |
|||
() => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/user/addAllRoles'), { |
|||
one: selectedUser.id, |
|||
many: [], |
|||
}) |
|||
.then((response) => { |
|||
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + selectedUser.id).then((response) => { |
|||
roleGridRef.replaceRows(response.data.content); |
|||
}); |
|||
}); |
|||
}, |
|||
); |
|||
}, |
|||
}, |
|||
'separator', |
|||
{ |
|||
name: 'removeRole', |
|||
label: t('system.role.action.removeRole'), |
|||
enableIf: () => { |
|||
if (userGridRef && roleGridRef) { |
|||
return userGridRef.getSelectedRows().length > 0 && roleGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: (selecteds) => { |
|||
const selectedUser = userGridRef.getSelectedRows()[0]; |
|||
const roleIds = Tools.extractProperties(selecteds, 'id'); |
|||
const messageKey = roleIds.length > 1 ? 'system.role.action.removeRole.confirms' : 'system.role.action.removeRole.confirm'; |
|||
DialogManager.confirm( |
|||
t(messageKey, { |
|||
userLoginName: selectedUser.loginName, |
|||
userName: selectedUser.userName, |
|||
roleCode: selecteds[0].code, |
|||
roleName: selecteds[0].name, |
|||
counter: selecteds.length, |
|||
}), |
|||
() => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/user/removeRoles'), { |
|||
one: selectedUser.id, |
|||
many: roleIds, |
|||
}) |
|||
.then((response) => { |
|||
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + selectedUser.id).then((response) => { |
|||
roleGridRef.replaceRows(response.data.content); |
|||
}); |
|||
}); |
|||
}, |
|||
); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'removeAllRole', |
|||
label: $t('system.role.action.removeAllRole'), |
|||
enableIf: () => { |
|||
if (userGridRef && roleGridRef) { |
|||
return userGridRef.getSelectedRows().length > 0 && roleGridRef.getRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
const selectedUser = userGridRef.getSelectedRows()[0]; |
|||
DialogManager.confirm( |
|||
t('system.role.action.removeAllRole.confirm', { userLoginName: selectedUser.loginName, userName: selectedUser.userName }), |
|||
() => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/user/removeAllRoles'), { |
|||
one: selectedUser.id, |
|||
many: [], |
|||
}) |
|||
.then((response) => { |
|||
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + selectedUser.id).then((response) => { |
|||
roleGridRef.replaceRows(response.data.content); |
|||
}); |
|||
}); |
|||
}, |
|||
); |
|||
}, |
|||
}, |
|||
'separator', |
|||
'view', |
|||
]" |
|||
:columns="[ |
|||
{ width: 100, name: 'code', label: $t('code') }, |
|||
{ width: 100, name: 'name', label: $t('name') }, |
|||
{ |
|||
width: 60, |
|||
name: 'status', |
|||
label: t('status'), |
|||
format: (value, row) => { |
|||
return { |
|||
componentType: RoleStatusTag, |
|||
attrs: row, |
|||
}; |
|||
}, |
|||
}, |
|||
]" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: t('id') }, |
|||
{ name: 'code', label: t('code') }, |
|||
{ name: 'name', label: t('name') }, |
|||
{ name: 'description', label: t('description') }, |
|||
{ name: 'enable', label: t('enable'), format: Formater.yesNo() }, |
|||
{ name: 'dataComeFrom', label: t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ name: 'creator', label: t('creator') }, |
|||
{ name: 'createDate', label: t('createDate') }, |
|||
{ name: 'lastModifier', label: t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
></w-grid> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="org" class="px-0"> |
|||
<w-grid |
|||
ref="orgTreeGridRef" |
|||
:tree="true" |
|||
:title="$t('system.org.grid.title')" |
|||
:data-url="orgQueryUrl" |
|||
selection="multiple" |
|||
:full-screen-button="false" |
|||
:toolbar-configure="{ noIcon: true }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
name: 'save', |
|||
label: $t('save'), |
|||
click: () => {}, |
|||
}, |
|||
'view', |
|||
]" |
|||
:pagination="{ |
|||
sortBy: 'name', |
|||
descending: false, |
|||
reqPageStart: 0, |
|||
rowsPerPage: 0, |
|||
}" |
|||
:columns="[ |
|||
{ width: 100, name: 'code', label: $t('code') }, |
|||
{ width: 100, name: 'name', label: $t('name') }, |
|||
{ |
|||
width: 60, |
|||
name: 'status', |
|||
label: t('status'), |
|||
format: (value, row) => { |
|||
return { |
|||
componentType: RoleStatusTag, |
|||
attrs: row, |
|||
}; |
|||
}, |
|||
}, |
|||
]" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: t('id') }, |
|||
{ name: 'code', label: t('code') }, |
|||
{ name: 'name', label: t('name') }, |
|||
{ name: 'description', label: t('description') }, |
|||
{ name: 'enable', label: t('enable'), format: Formater.yesNo() }, |
|||
{ name: 'dataComeFrom', label: t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ name: 'creator', label: t('creator') }, |
|||
{ name: 'createDate', label: t('createDate') }, |
|||
{ name: 'lastModifier', label: t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
></w-grid> |
|||
</q-tab-panel> |
|||
</q-tab-panels> |
|||
</div> |
|||
</template> |
|||
<SelectRoleDialog ref="selectRoleDialog"></SelectRoleDialog> |
|||
<SetPasswordDialog ref="setPasswordDialogRef"></SetPasswordDialog> |
|||
</q-splitter> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { useI18n } from 'vue-i18n'; |
|||
import { Environment, axios, EnumTools, NotifyManager, DialogManager, Formater, Options, Tools } from '@/platform'; |
|||
import SelectRoleDialog from './SelectRoleDialog.vue'; |
|||
import SetPasswordDialog from './SetPasswordDialog.vue'; |
|||
import UserStatusTag from './UserStatusTag.vue'; |
|||
import RoleStatusTag from './RoleStatusTag.vue'; |
|||
import { nextTick } from 'vue'; |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const userGridRef = ref(); |
|||
const roleGridRef = ref(); |
|||
const orgTreeGridRef = ref(); |
|||
|
|||
const selectRoleDialog = ref(); |
|||
const selectedTabRef = ref('role'); |
|||
const setPasswordDialogRef = ref(); |
|||
|
|||
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom'); |
|||
const currentSelectedUserId = ref(); |
|||
|
|||
const roleQueryUrl = ref(''); |
|||
const orgQueryUrl = ref(''); |
|||
|
|||
const orgConfigure = { |
|||
actions: [ |
|||
{ |
|||
name: 'save', |
|||
label: '保存', |
|||
click: () => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/user/updateOrgs'), { |
|||
one: userGridRef.value.getSelectedRows()[0].id, |
|||
many: orgTreeGridRef.value.getTicked(), |
|||
}) |
|||
.then((response) => {}); |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
</script> --> |
|||
|
|||
<template> |
|||
<q-splitter :model-value="60" class="w-full h-full"> |
|||
<template #before> |
|||
<div class="px-1"> |
|||
<w-grid |
|||
ref="roleGridRef" |
|||
:title="$t('system.role.grid.title')" |
|||
:data-url="Environment.apiContextPath('/api/system/role')" |
|||
selection="multiple" |
|||
:query-form-fields="[ |
|||
{ name: 'code', label: $t('code'), type: 'text' }, |
|||
{ name: 'name', label: $t('name'), type: 'text' }, |
|||
{ name: 'enable', label: $t('isEnable'), type: 'select', options: Options.yesNo() }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select', options: Options.enum(DataComeFromEnum) }, |
|||
]" |
|||
:toolbar-configure="{ noIcon: false }" |
|||
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator', 'view', 'export']" |
|||
:columns="[ |
|||
{ name: 'code', label: $t('code') }, |
|||
{ name: 'name', label: $t('name') }, |
|||
{ width: 80, name: 'status', label: $t('status'), format: Formater.enableTag() }, |
|||
{ width: 100, name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ width: 120, name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ width: 120, name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.dateOnly() }, |
|||
]" |
|||
:editor="{ |
|||
dialog: { |
|||
width: '600px', |
|||
height: '300px', |
|||
}, |
|||
form: { |
|||
colsNum: 1, |
|||
fields: [ |
|||
{ name: 'code', label: $t('code'), type: 'text', required: true }, |
|||
{ name: 'name', label: $t('name'), type: 'text', required: true }, |
|||
{ name: 'description', label: $t('description'), type: 'textarea', rows: 1 }, |
|||
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true }, |
|||
], |
|||
}, |
|||
}" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: $t('id') }, |
|||
{ name: 'code', label: $t('code') }, |
|||
{ name: 'name', label: $t('name') }, |
|||
{ name: 'description', label: $t('description') }, |
|||
{ name: 'enable', label: $t('enable'), format: Formater.yesNo() }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ name: 'creator', label: $t('creator') }, |
|||
{ name: 'createDate', label: $t('createDate') }, |
|||
{ name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: $t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
@row-click=" |
|||
(evt, row, index) => { |
|||
currentSelectedRoleId = row.id; |
|||
userGridRef?.refresh(); |
|||
menuTreeGridRef?.refresh(); |
|||
} |
|||
" |
|||
> |
|||
</w-grid> |
|||
</div> |
|||
</template> |
|||
<template #after> |
|||
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps> |
|||
<q-tab name="menu" icon="bi-people" :label="$t('menu')" /> |
|||
<q-tab name="user" icon="bi-diagram-3" :label="$t('user')" /> |
|||
</q-tabs> |
|||
|
|||
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive> |
|||
<q-tab-panel name="menu" class="px-0"> |
|||
<w-grid |
|||
ref="menuTreeGridRef" |
|||
:tree="true" |
|||
:title="$t('system.org.grid.title')" |
|||
:data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByRole?roleId=') + currentSelectedRoleId" |
|||
selection="multiple" |
|||
:pageable="false" |
|||
:full-screen-button="false" |
|||
:toolbar-configure="{ noIcon: true }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
name: 'save', |
|||
label: $t('save'), |
|||
click: () => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/updateMenus'), { |
|||
one: userGridRef.getSelectedRows()[0].id, |
|||
many: menuTreeGridRef.getTicked(), |
|||
}) |
|||
.then((response) => {}); |
|||
}, |
|||
}, |
|||
'view', |
|||
]" |
|||
:columns="[ |
|||
{ |
|||
width: 100, |
|||
name: 'titleI18nKey', |
|||
label: $t('name'), |
|||
format: (value, row) => { |
|||
return $t(value); |
|||
}, |
|||
}, |
|||
{ width: 60, name: 'enable', label: $t('status'), format: Formater.enableTag() }, |
|||
]" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: $t('id') }, |
|||
{ name: 'code', label: $t('code') }, |
|||
{ name: 'name', label: $t('name') }, |
|||
{ name: 'description', label: $t('description') }, |
|||
{ name: 'enable', label: $t('enable'), format: Formater.yesNo() }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) }, |
|||
{ name: 'creator', label: $t('creator') }, |
|||
{ name: 'createDate', label: $t('createDate') }, |
|||
{ name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: $t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
></w-grid> |
|||
</q-tab-panel> |
|||
|
|||
<q-tab-panel name="user" class="px-0"> |
|||
<w-grid |
|||
ref="userGridRef" |
|||
:title="$t('system.role.selectUser.grid.title')" |
|||
:fetch-data-url="Environment.apiContextPath('/api/system/user/queryUsersByRole?roleId=') + currentSelectedRoleId" |
|||
:auto-fetch-data="false" |
|||
selection="multiple" |
|||
:full-screen-button="false" |
|||
:toolbar-configure="{ noIcon: true }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
name: 'addUser', |
|||
label: $t('system.role.selectUser.grid.toolbar.addUser'), |
|||
enableIf: () => { |
|||
if (roleGridRef) { |
|||
return roleGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
selectUserDialog.open({ roleId: roleGridRef.getSelectedRows()[0].id, userGrid: userGridRef }); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'addAllUser', |
|||
label: $t('system.role.selectUser.grid.toolbar.addAllUser'), |
|||
enableIf: () => { |
|||
if (roleGridRef) { |
|||
return roleGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
const selectedRole = roleGridRef.getSelectedRows()[0]; |
|||
DialogManager.confirm($t('system.role.selectUser.grid.toolbar.addAllUser.tip'), () => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/addAllUsers'), { |
|||
one: selectedRole.id, |
|||
many: [], |
|||
}) |
|||
.then((response) => { |
|||
userGridRef?.refresh(); |
|||
}); |
|||
}); |
|||
}, |
|||
}, |
|||
'separator', |
|||
{ |
|||
name: 'removeUser', |
|||
label: $t('system.role.selectUser.grid.toolbar.removeUser'), |
|||
enableIf: () => { |
|||
if (roleGridRef && userGridRef) { |
|||
return roleGridRef.getSelectedRows().length > 0 && userGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: (selecteds) => { |
|||
const selectedRole = roleGridRef.getSelectedRows()[0]; |
|||
const userIds = Tools.extractProperties(selecteds, 'id'); |
|||
DialogManager.confirm($t('system.role.selectUser.grid.toolbar.removeUser.tip'), () => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/removeUsers'), { |
|||
one: selectedRole.id, |
|||
many: userIds, |
|||
}) |
|||
.then((response) => { |
|||
userGridRef?.refresh(); |
|||
}); |
|||
}); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'removeAllUser', |
|||
label: $t('system.role.selectUser.grid.toolbar.removeAllUser'), |
|||
enableIf: () => { |
|||
if (roleGridRef) { |
|||
return roleGridRef.getSelectedRows().length > 0; |
|||
} |
|||
return false; |
|||
}, |
|||
click: () => { |
|||
const selectedRole = roleGridRef.getSelectedRows()[0]; |
|||
DialogManager.confirm($t('system.role.selectUser.grid.toolbar.removeAllUser.tip'), () => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/removeAllUsers'), { |
|||
one: selectedRole.id, |
|||
many: [], |
|||
}) |
|||
.then((response) => { |
|||
userGridRef?.refresh(); |
|||
}); |
|||
}); |
|||
}, |
|||
}, |
|||
'separator', |
|||
'view', |
|||
]" |
|||
:columns="[ |
|||
{ width: 100, name: 'loginName', label: t('loginName') }, |
|||
{ width: 100, name: 'userName', label: t('userName') }, |
|||
{ |
|||
name: 'status', |
|||
label: $t('status'), |
|||
format: (value, row) => { |
|||
return { |
|||
componentType: UserStatusTag, |
|||
attrs: row, |
|||
}; |
|||
}, |
|||
}, |
|||
]" |
|||
> |
|||
</w-grid> |
|||
</q-tab-panel> |
|||
</q-tab-panels> |
|||
</template> |
|||
<SelectUserDialog ref="selectUserDialog"></SelectUserDialog> |
|||
</q-splitter> |
|||
<div class="q-pa-md"> |
|||
<q-table v-model:selected="selected" title="Treats" row-key="name" selection="multiple" :rows="rows" :columns="columns"> |
|||
<template #body="scope"> |
|||
<q-tr ref="trRef" class="selected" :props="scope"> |
|||
<q-td class="text-center" style="padding: 0; width: 50px"> |
|||
<q-checkbox v-model="scope.row['selected']" flat @update:model-value="updateTicked($event, scope.row)" /> |
|||
</q-td> |
|||
<q-td v-for="col in scope.cols" :key="col.name" :props="scope"> |
|||
<GridFormat :value="col.value"></GridFormat> |
|||
</q-td> |
|||
</q-tr> |
|||
</template> |
|||
</q-table> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { useI18n } from 'vue-i18n'; |
|||
import { Environment, axios, DialogManager, Tools, EnumTools, Options, Formater } from '@/platform'; |
|||
import SelectUserDialog from './SelectUserDialog.vue'; |
|||
import UserStatusTag from './UserStatusTag.vue'; |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom'); |
|||
import { Tools } from '@/platform'; |
|||
import GridFormat from './GridForamt.vue'; |
|||
|
|||
const roleGridRef = ref(); |
|||
const userGridRef = ref(); |
|||
const menuTreeGridRef = ref(); |
|||
const selected = ref([]); |
|||
|
|||
const selectUserDialog = ref(); |
|||
const selectedTabRef = ref('user'); |
|||
const currentSelectedRoleId = ref(''); |
|||
const updateTicked = (event, row) => { |
|||
row['selected'] = !row['selected']; |
|||
}; |
|||
|
|||
const menuConfigure = { |
|||
actions: [ |
|||
{ |
|||
name: 'save', |
|||
label: '保存', |
|||
click: () => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/updateMenus'), { |
|||
one: roleGridRef.value.getSelectedRows()[0].id, |
|||
many: menuTreeGridRef.value.getTicked(), |
|||
}) |
|||
.then((response) => {}); |
|||
}, |
|||
const columns = [ |
|||
{ |
|||
name: 'name', |
|||
required: true, |
|||
label: 'Dessert (100g serving)', |
|||
align: 'left', |
|||
field: (row) => row.name, |
|||
sortable: true, |
|||
}, |
|||
{ name: 'calories', align: 'center', label: 'Calories', field: 'calories', sortable: true }, |
|||
{ |
|||
name: 'fat', |
|||
label: 'Fat (g)', |
|||
field: 'fat', |
|||
sortable: true, |
|||
format: (val, row) => { |
|||
console.info('format.val====', val); |
|||
return val; |
|||
}, |
|||
], |
|||
}; |
|||
}, |
|||
{ name: 'carbs', label: 'Carbs (g)', field: 'carbs' }, |
|||
{ name: 'protein', label: 'Protein (g)', field: 'protein' }, |
|||
{ name: 'sodium', label: 'Sodium (mg)', field: 'sodium' }, |
|||
{ name: 'calcium', label: 'Calcium (%)', field: 'calcium', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) }, |
|||
{ name: 'iron', label: 'Iron (%)', field: 'iron', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) }, |
|||
]; |
|||
|
|||
const rows = [ |
|||
{ |
|||
name: 'Frozen Yogurt', |
|||
calories: 159, |
|||
fat: 6.0, |
|||
carbs: 24, |
|||
protein: 4.0, |
|||
sodium: 87, |
|||
calcium: '14%', |
|||
iron: '1%', |
|||
selected: false, |
|||
}, |
|||
]; |
|||
</script> |
|||
|
@ -1,178 +0,0 @@ |
|||
<template> |
|||
<div style="height: 100%"> |
|||
<w-grid |
|||
ref="gridRef" |
|||
:title="$t('re.resources.designer.processor.grid.title')" |
|||
dense-body |
|||
class="px-1" |
|||
hide-bottom |
|||
:config-button="false" |
|||
selection="multiple" |
|||
:checkbox-selection="true" |
|||
:tree="false" |
|||
:fetch-data-url="Environment.apiContextPath('/api/re/model/parameter/processor/findByParameterId?parameterId=' + parameterId)" |
|||
:data-url="Environment.apiContextPath('/api/re/model/parameter/processor')" |
|||
:pageable="false" |
|||
:toolbar-configure="{ noIcon: false }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
extend: 'edit', |
|||
enableIf: (arg) => { |
|||
return arg.selected; |
|||
}, |
|||
}, |
|||
{ |
|||
extend: 'remove', |
|||
enableIf: (arg) => { |
|||
return !readOnly && arg.selected; |
|||
}, |
|||
}, |
|||
'separator', |
|||
'view', |
|||
'separator', |
|||
'export', |
|||
]" |
|||
:columns="[ |
|||
{ width: 80, name: 'enable', label: $t('isEnable'), align: 'center', sortable: false, format: Formater.enableTag() }, |
|||
{ width: 60, name: 'order', label: $t('order'), sortable: false, align: 'right' }, |
|||
{ width: 150, name: 'type', label: $t('type'), sortable: false, format: Formater.enum(Enums.ProcessorType) }, |
|||
{ |
|||
width: '100%', |
|||
name: 'content', |
|||
label: $t('re.resources.designer.processor.grid.entity.content'), |
|||
sortable: false, |
|||
format: (value, row) => { |
|||
const type = row.type; |
|||
if ('MATH_FORMULA' === type) { |
|||
return { |
|||
componentType: 'w-expression', |
|||
attrs: { |
|||
modelValue: row.mathFormula, |
|||
readOnly: true, |
|||
zoom: 2, |
|||
}, |
|||
}; |
|||
} |
|||
}, |
|||
}, |
|||
]" |
|||
:editor="{ |
|||
dialog: { |
|||
width: '1024px', |
|||
}, |
|||
form: { |
|||
colsNum: 1, |
|||
fields: [ |
|||
{ name: 'parameter', label: 'parameter', type: 'text', defaultValue: parameterId, hidden: true }, |
|||
{ name: 'id', label: $t('id'), type: 'text', hidden: true }, |
|||
{ name: 'order', label: $t('order'), type: 'number', hidden: true }, |
|||
{ name: 'type', label: $t('type'), type: 'text', hidden: true }, |
|||
{ name: 'description', label: $t('description'), type: 'text', hidden: true }, |
|||
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true, hidden: true }, |
|||
{ |
|||
name: 'mathFormula', |
|||
label: $t('re.resources.designer.processor.grid.entity.mathFormula'), |
|||
type: 'expression', |
|||
showIf: (arg) => { |
|||
return 'MATH_FORMULA' === arg.form.getFieldValue('type'); |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
}" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'order', label: $t('order') }, |
|||
{ name: 'id', label: $t('id'), primaryKey: true }, |
|||
{ name: 'parameter', label: $t('parameter') }, |
|||
{ name: 'description', label: $t('description') }, |
|||
{ name: 'enable', label: $t('enable') }, |
|||
{ name: 'type', label: $t('type') }, |
|||
{ name: 'optionCode', label: $t('re.resources.designer.processor.grid.entity.optionCode') }, |
|||
{ name: 'arithmetic', label: $t('re.resources.designer.processor.grid.entity.arithmetic') }, |
|||
{ name: 'ternaryCondition', label: $t('re.resources.designer.processor.grid.entity.ternaryCondition') }, |
|||
{ name: 'ternaryTrue', label: $t('re.resources.designer.processor.grid.entity.ternaryTrue') }, |
|||
{ name: 'ternaryFalse', label: $t('re.resources.designer.processor.grid.entity.ternaryFalse') }, |
|||
{ name: 'when', label: $t('re.resources.designer.processor.grid.entity.when') }, |
|||
{ name: 'then', label: $t('re.resources.designer.processor.grid.entity.then') }, |
|||
{ name: 'isWhenThenShorted', label: $t('re.resources.designer.processor.grid.entity.isWhenThenShorted') }, |
|||
{ name: 'rule', label: $t('re.resources.designer.processor.grid.entity.rule') }, |
|||
{ name: 'singleRule', label: $t('re.resources.designer.processor.grid.entity.singleRule') }, |
|||
{ name: 'numberRange', label: $t('re.resources.designer.processor.grid.entity.numberRange') }, |
|||
{ name: 'conditionRange', label: $t('re.resources.designer.processor.grid.entity.conditionRange') }, |
|||
{ name: 'decisionTable2C', label: $t('re.resources.designer.processor.grid.entity.decisionTable2C') }, |
|||
{ name: 'decisionTable', label: $t('re.resources.designer.processor.grid.entity.decisionTable') }, |
|||
{ name: 'groovyScript', label: $t('re.resources.designer.processor.grid.entity.groovyScript') }, |
|||
|
|||
{ name: 'sqlDatasourceName', label: $t('re.resources.designer.processor.grid.entity.sqlDatasourceName') }, |
|||
{ name: 'sql', label: $t('re.resources.designer.processor.grid.entity.sql') }, |
|||
{ name: 'sqlParameterValues', label: $t('re.resources.designer.processor.grid.entity.sqlParameterValues') }, |
|||
{ name: 'sqlFieldMapping', label: $t('re.resources.designer.processor.grid.entity.sqlFieldMapping') }, |
|||
|
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom') }, |
|||
{ name: 'creator', label: $t('creator') }, |
|||
{ name: 'createDate', label: $t('createDate') }, |
|||
{ name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() }, |
|||
], |
|||
}, |
|||
}" |
|||
@before-editor-data-submit=" |
|||
(data, callback) => { |
|||
console.log(data); |
|||
} |
|||
" |
|||
></w-grid> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, onMounted } from 'vue'; |
|||
import { axios, Environment, Formater, Tools, EnumTools, Options } from '@/platform'; |
|||
import { ComponentContainer } from '@univerjs/ui'; |
|||
import { RowHeaderLayout } from '@univerjs/engine-render'; |
|||
|
|||
const props = defineProps({ |
|||
fetchDataUrl: { type: String, default: '' }, |
|||
dataUrl: { type: String, default: '' }, |
|||
parameter: { type: Object, default: undefined }, |
|||
readOnly: { type: Boolean, default: false }, |
|||
}); |
|||
|
|||
const emit = defineEmits<{ |
|||
(e: 'rowClick', evt: Event, row: any, index: number): void; |
|||
(e: 'beforeRequestData', requestParams: URLSearchParams | any, callback: any): void; |
|||
}>(); |
|||
|
|||
const gridRef = ref(); |
|||
const autoCompletionOptionsRef = ref([]); |
|||
const optionOptionsRef = ref([]); |
|||
const decisionTreeDialogRef = ref(); |
|||
const executionFlowDialogRef = ref(); |
|||
const parameterId = '8c114166-aae3-4590-b63a-6daa64eb15ac'; |
|||
|
|||
const transfromContent = (xml) => { |
|||
const div = document.createElement('div'); |
|||
div.textContent = xml; |
|||
const result = div.outerHTML; |
|||
div.parentNode?.removeChild(div); |
|||
return result; |
|||
}; |
|||
|
|||
const refresh = () => { |
|||
gridRef.value.refresh(); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
gridRef.value.refresh(); |
|||
}); |
|||
|
|||
defineExpose({ |
|||
refresh, |
|||
}); |
|||
|
|||
const Enums = await EnumTools.fetch(['io.sc.engine.rule.core.enums.ProcessorType']); |
|||
</script> |
Loading…
Reference in new issue