1122
This commit is contained in:
841
cdTMP/src/components/ma-crud/index.vue
Normal file
841
cdTMP/src/components/ma-crud/index.vue
Normal file
@@ -0,0 +1,841 @@
|
||||
<template>
|
||||
<a-layout-content class="flex flex-col lg:h-full relative w-full">
|
||||
<div class="_crud-header flex flex-col mb-2" ref="crudHeaderRef">
|
||||
<a-tabs
|
||||
v-if="isArray(options.tabs.data) && options.tabs.data.length > 0"
|
||||
v-model:active-key="options.tabs.defaultKey"
|
||||
:trigger="options.tabs.trigger"
|
||||
:type="options.tabs.type"
|
||||
:hide-content="true"
|
||||
@change="tabChange"
|
||||
@tab-click="maEvent.customeEvent(options.tabs, $event, 'onClick')"
|
||||
class="ma-tabs mb-5"
|
||||
>
|
||||
<template #extra><slot name="tabExtra"></slot></template>
|
||||
<a-tab-pane :key="item.value" :title="item.label" v-for="item in options.tabs.data"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<ma-search @search="searchSubmitHandler" class="__search-panel" ref="crudSearchRef">
|
||||
<template v-for="(slot, slotIndex) in searchSlots" :key="slotIndex" #[slot]="{ searchForm, component }">
|
||||
<slot :name="`search-${slot}`" v-bind="{ searchForm, component }" />
|
||||
</template>
|
||||
<template #searchBeforeButtons>
|
||||
<slot name="searchBeforeButtons"></slot>
|
||||
</template>
|
||||
<template #searchButtons>
|
||||
<slot name="searchButtons"></slot>
|
||||
</template>
|
||||
<template #searchAfterButtons>
|
||||
<slot name="searchAfterButtons"></slot>
|
||||
</template>
|
||||
</ma-search>
|
||||
</div>
|
||||
<div class="_crud-content">
|
||||
<div class="operation-tools lg:flex justify-between mb-3" ref="crudOperationRef">
|
||||
<a-space class="lg:flex block lg:inline-block">
|
||||
<slot name="tableBeforeButtons"></slot>
|
||||
<slot name="tableButtons">
|
||||
<a-button
|
||||
v-if="options.add.show"
|
||||
@click="addAction"
|
||||
type="primary"
|
||||
class="w-full lg:w-auto mt-2 lg:mt-0"
|
||||
>
|
||||
<template #icon><icon-plus /></template>{{ options.add.text || "新增" }}
|
||||
</a-button>
|
||||
|
||||
<a-popconfirm content="确定要删除数据吗?" position="bottom" @ok="deletesMultipleAction">
|
||||
<a-button
|
||||
v-if="options.delete.show"
|
||||
type="primary"
|
||||
status="danger"
|
||||
class="w-full lg:w-auto mt-2 lg:mt-0"
|
||||
>
|
||||
<template #icon><icon-delete /></template>
|
||||
{{ isRecovery ? options.delete.realText || "删除" : options.delete.text || "删除" }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-popconfirm content="确定要恢复数据吗?" position="bottom" @ok="recoverysMultipleAction">
|
||||
<a-button
|
||||
v-if="options.recovery.show && isRecovery"
|
||||
type="primary"
|
||||
status="success"
|
||||
class="w-full lg:w-auto mt-2 lg:mt-0"
|
||||
>
|
||||
<template #icon><icon-undo /></template>{{ options.recovery.text || "恢复" }}</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button v-if="options.import.show" @click="importAction" class="w-full lg:w-auto mt-2 lg:mt-0"
|
||||
><template #icon><icon-upload /></template>{{ options.import.text || "导入" }}</a-button
|
||||
>
|
||||
|
||||
<a-button v-if="options.export.show" @click="exportAction" class="w-full lg:w-auto mt-2 lg:mt-0"
|
||||
><template #icon><icon-download /></template>{{ options.export.text || "导出" }}</a-button
|
||||
>
|
||||
|
||||
<a-button
|
||||
type="secondary"
|
||||
@click="handlerExpand"
|
||||
v-if="options.isExpand"
|
||||
class="w-full lg:w-auto mt-2 lg:mt-0"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-expand v-if="!expandState" />
|
||||
<icon-shrink v-else />
|
||||
</template>
|
||||
{{ expandState ? " 折叠" : " 展开" }}
|
||||
</a-button>
|
||||
</slot>
|
||||
<slot name="tableAfterButtons"></slot>
|
||||
</a-space>
|
||||
<a-space class="lg:mt-0 mt-2" v-if="options.showTools">
|
||||
<slot name="tools"></slot>
|
||||
<a-tooltip
|
||||
:content="isRecovery ? '显示正常数据' : '显示回收站数据'"
|
||||
v-if="options.recycleApi && isFunction(options.recycleApi)"
|
||||
>
|
||||
<a-button shape="circle" @click="switchDataType"><icon-swap /></a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip content="刷新表格"
|
||||
><a-button shape="circle" @click="refresh"><icon-refresh /></a-button
|
||||
></a-tooltip>
|
||||
<a-tooltip content="显隐搜索"
|
||||
><a-button shape="circle" @click="toggleSearch"><icon-search /></a-button
|
||||
></a-tooltip>
|
||||
<a-tooltip content="打印表格"
|
||||
><a-button shape="circle" @click="printTable"><icon-printer /></a-button
|
||||
></a-tooltip>
|
||||
<a-tooltip content="设置"
|
||||
><a-button shape="circle" @click="tableSetting"><icon-settings /></a-button
|
||||
></a-tooltip>
|
||||
</a-space>
|
||||
</div>
|
||||
<div ref="crudContentRef">
|
||||
<slot name="content" v-bind="tableData">
|
||||
<a-table
|
||||
v-bind="$attrs"
|
||||
ref="tableRef"
|
||||
:key="options.pk"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:sticky-header="options.stickyHeader"
|
||||
:pagination="options.tablePagination"
|
||||
:stripe="options.stripe"
|
||||
:bordered="options.bordered"
|
||||
:rowSelection="options.rowSelection || undefined"
|
||||
:row-key="options?.rowSelection?.key ?? options.pk"
|
||||
:scroll="options.scroll"
|
||||
:column-resizable="options.resizable"
|
||||
:size="options.size"
|
||||
:row-class="options.rowClass"
|
||||
:hide-expand-button-on-empty="options.hideExpandButtonOnEmpty"
|
||||
:default-expand-all-rows="options.expandAllRows"
|
||||
:summary="options.customerSummary || __summary || options.showSummary"
|
||||
@selection-change="setSelecteds"
|
||||
@sorter-change="handlerSort"
|
||||
>
|
||||
<template #tr="{ record }">
|
||||
<tr
|
||||
class="ma-crud-table-tr"
|
||||
:class="
|
||||
isFunction(options.rowCustomClass)
|
||||
? options.rowCustomClass(record, rowIndex) ?? []
|
||||
: options.rowCustomClass
|
||||
"
|
||||
@contextmenu.prevent="openContextMenu($event, record)"
|
||||
@dblclick="dbClickOpenEdit(record)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #expand-row="record" v-if="options.showExpandRow">
|
||||
<slot name="expand-row" v-bind="record"></slot>
|
||||
</template>
|
||||
<template #columns>
|
||||
<ma-column
|
||||
ref="crudColumnRef"
|
||||
v-if="reloadColumn"
|
||||
:columns="props.columns"
|
||||
:isRecovery="isRecovery"
|
||||
:crudFormRef="crudFormRef"
|
||||
@refresh="() => refresh()"
|
||||
@showImage="showImage"
|
||||
>
|
||||
<template #operationBeforeExtend="{ record, column, rowIndex }">
|
||||
<slot name="operationBeforeExtend" v-bind="{ record, column, rowIndex }"></slot>
|
||||
</template>
|
||||
|
||||
<template #operationCell="{ record, column, rowIndex }">
|
||||
<slot name="operationCell" v-bind="{ record, column, rowIndex }"></slot>
|
||||
</template>
|
||||
|
||||
<template #operationAfterExtend="{ record, column, rowIndex }">
|
||||
<slot name="operationAfterExtend" v-bind="{ record, column, rowIndex }"></slot>
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-for="(slot, slotIndex) in slots"
|
||||
:key="slotIndex"
|
||||
#[slot]="{ record, column, rowIndex }"
|
||||
>
|
||||
<slot :name="`${slot}`" v-bind="{ record, column, rowIndex }" />
|
||||
</template>
|
||||
</ma-column>
|
||||
</template>
|
||||
<template
|
||||
#summary-cell="{ column, record, rowIndex }"
|
||||
v-if="options.customerSummary || options.showSummary"
|
||||
>
|
||||
<slot name="summaryCell" v-bind="{ record, column, rowIndex }">{{
|
||||
record[column.dataIndex]
|
||||
}}</slot>
|
||||
</template>
|
||||
</a-table>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_crud-footer mt-3 text-right"
|
||||
ref="crudFooterRef"
|
||||
v-if="total > 0 && openPagination && !options.tablePagination"
|
||||
>
|
||||
<a-pagination
|
||||
:total="total"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
:page-size-options="options.pageSizeOption"
|
||||
@page-size-change="pageSizeChangeHandler"
|
||||
@change="pageChangeHandler"
|
||||
v-model:current="requestParams[config.request.page]"
|
||||
:page-size="requestParams[config.request.pageSize]"
|
||||
style="display: inline-flex"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ma-setting ref="crudSettingRef" />
|
||||
|
||||
<ma-form ref="crudFormRef" @success="requestSuccess">
|
||||
<template v-for="slot in Object.keys($slots)" #[slot]="component">
|
||||
<slot :name="slot" v-bind="component" />
|
||||
</template>
|
||||
</ma-form>
|
||||
|
||||
<ma-import ref="crudImportRef" />
|
||||
|
||||
<ma-context-menu ref="crudContextMenuRef" @execCommand="execContextMenuCommand" />
|
||||
|
||||
<a-image-preview :src="imgUrl" v-model:visible="imgVisible" />
|
||||
</a-layout-content>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import config from "@/config/crud"
|
||||
import { ref, watch, provide, nextTick, onMounted, onUnmounted } from "vue"
|
||||
import defaultOptions from "./js/defaultOptions"
|
||||
import { loadDict } from "@cps/ma-form/js/networkRequest.js"
|
||||
import ColumnService from "./js/columnService"
|
||||
|
||||
import MaSearch from "./components/search.vue"
|
||||
import MaForm from "./components/form.vue"
|
||||
import MaSetting from "./components/setting.vue"
|
||||
import MaImport from "./components/import.vue"
|
||||
import MaColumn from "./components/column.vue"
|
||||
import MaContextMenu from "./components/contextMenu.vue"
|
||||
import checkAuth from "@/directives/auth/auth"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
import { request } from "@/utils/request"
|
||||
import tool from "@/utils/tool"
|
||||
import Print from "@/utils/print"
|
||||
import { isArray, isFunction, isObject, isUndefined } from "lodash"
|
||||
import { maEvent } from "@cps/ma-form/js/formItemMixin.js"
|
||||
import globalColumn from "@/config/column.js"
|
||||
import { useFormStore } from "@/store/index"
|
||||
|
||||
const formStore = useFormStore()
|
||||
const props = defineProps({
|
||||
// 表格数据
|
||||
data: { type: [Function, Array], default: () => null },
|
||||
// 增删改查设置
|
||||
options: { type: Object, default: {} },
|
||||
crud: { type: Object, default: {} },
|
||||
// 字段列设置
|
||||
columns: { type: Array, default: [] }
|
||||
})
|
||||
|
||||
const loading = ref(true)
|
||||
const dicts = ref({})
|
||||
const cascaders = ref([])
|
||||
|
||||
const reloadColumn = ref(true)
|
||||
const openPagination = ref(false)
|
||||
const imgVisible = ref(false)
|
||||
const imgUrl = ref(import.meta.env.VITE_APP_BASE + "not-image.png")
|
||||
const total = ref(0)
|
||||
const requestParams = ref({})
|
||||
const slots = ref([])
|
||||
const searchSlots = ref([])
|
||||
const isRecovery = ref(false)
|
||||
const expandState = ref(false)
|
||||
|
||||
const crudHeaderRef = ref()
|
||||
const crudOperationRef = ref()
|
||||
const crudContentRef = ref()
|
||||
const crudFooterRef = ref()
|
||||
const crudSearchRef = ref()
|
||||
const crudSettingRef = ref()
|
||||
const crudFormRef = ref()
|
||||
const crudImportRef = ref()
|
||||
const crudColumnRef = ref()
|
||||
const crudContextMenuRef = ref()
|
||||
|
||||
const options = ref(Object.assign(JSON.parse(JSON.stringify(defaultOptions)), props.options, props.crud))
|
||||
|
||||
const columns = ref(props.columns)
|
||||
const headerHeight = ref(0)
|
||||
const selecteds = ref([])
|
||||
const tableData = ref([])
|
||||
const tableRef = ref()
|
||||
const currentApi = ref()
|
||||
|
||||
// 初始化
|
||||
const init = async () => {
|
||||
// 设置 组件id
|
||||
if (isUndefined(options.value.id)) {
|
||||
options.value.id = "MaCrud_" + Math.floor(Math.random() * 100000 + Math.random() * 20000 + Math.random() * 5000)
|
||||
}
|
||||
|
||||
// 收集数据
|
||||
props.columns.map((item) => {
|
||||
if (item.cascaderItem && item.cascaderItem.length > 0) {
|
||||
cascaders.value.push(...item.cascaderItem)
|
||||
}
|
||||
})
|
||||
|
||||
await props.columns.map(async (item) => {
|
||||
// 字典
|
||||
if (!cascaders.value.includes(item.dataIndex) && item.dict) {
|
||||
await loadDict(dicts.value, item)
|
||||
}
|
||||
})
|
||||
await tabsHandler()
|
||||
}
|
||||
|
||||
const dictTrans = (dataIndex, value) => {
|
||||
if (dicts.value[dataIndex] && dicts.value[dataIndex].tran) {
|
||||
return dicts.value[dataIndex].tran[value]
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
const dictColors = (dataIndex, value) => {
|
||||
if (dicts.value[dataIndex] && dicts.value[dataIndex].colors) {
|
||||
return dicts.value[dataIndex].colors[value]
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
// 公用模板
|
||||
columns.value.map((item, index) => {
|
||||
if (item.common && globalColumn[item.dataIndex]) {
|
||||
columns.value[index] = globalColumn[item.dataIndex]
|
||||
item = columns.value[index]
|
||||
}
|
||||
!item.width && (item.width = options.value.columnWidth)
|
||||
})
|
||||
|
||||
provide("options", options.value)
|
||||
provide("columns", props.columns)
|
||||
provide("layout", props.layout)
|
||||
provide("dicts", dicts.value)
|
||||
provide("dictColors", dictColors.value)
|
||||
provide("requestParams", requestParams.value)
|
||||
provide("dictTrans", dictTrans)
|
||||
provide("dictColors", dictColors)
|
||||
provide("isRecovery", isRecovery)
|
||||
|
||||
watch(
|
||||
() => props.options.api,
|
||||
(vl) => (options.value.api = vl)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.crud.api,
|
||||
(vl) => (options.value.api = vl)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => openPagination.value,
|
||||
() => options.value.pageLayout === "fixed" && settingFixedPage()
|
||||
)
|
||||
|
||||
watch(
|
||||
() => formStore.crudList[options.value.id],
|
||||
async (vl) => {
|
||||
vl === true && (await requestData())
|
||||
formStore.crudList[options.value.id] = false
|
||||
}
|
||||
)
|
||||
|
||||
const getSlot = (cls = []) => {
|
||||
let sls = []
|
||||
cls.map((item) => {
|
||||
if (item.children && item.children.length > 0) {
|
||||
let tmp = getSlot(item.children)
|
||||
sls.push(...tmp)
|
||||
} else if (item.dataIndex) {
|
||||
sls.push(item.dataIndex)
|
||||
}
|
||||
})
|
||||
return sls
|
||||
}
|
||||
|
||||
const showImage = (url) => {
|
||||
imgUrl.value = url
|
||||
imgVisible.value = true
|
||||
}
|
||||
|
||||
const getSearchSlot = () => {
|
||||
let sls = []
|
||||
props.columns.map((item) => {
|
||||
if (item.search && item.search === true) {
|
||||
sls.push(item.dataIndex)
|
||||
}
|
||||
})
|
||||
return sls
|
||||
}
|
||||
|
||||
slots.value = getSlot(props.columns)
|
||||
searchSlots.value = getSearchSlot(props.columns)
|
||||
|
||||
const requestData = async () => {
|
||||
await init()
|
||||
if (options.value.showIndex && columns.value.length > 0 && columns.value[0].dataIndex !== "__index") {
|
||||
columns.value.unshift({
|
||||
title: options.value.indexLabel,
|
||||
dataIndex: "__index",
|
||||
width: options.value.indexColumnWidth,
|
||||
fixed: options.value.indexColumnFixed
|
||||
})
|
||||
}
|
||||
if (
|
||||
options.value.operationColumn &&
|
||||
columns.value.length > 0 &&
|
||||
columns.value[columns.value.length - 1].dataIndex !== "__operation"
|
||||
) {
|
||||
columns.value.push({
|
||||
title: options.value.operationColumnText,
|
||||
dataIndex: "__operation",
|
||||
width: options.value.operationColumnWidth ?? options.value.operationWidth,
|
||||
align: options.value.operationColumnAlign,
|
||||
fixed: options.value.operationColumnFixed
|
||||
})
|
||||
}
|
||||
|
||||
initRequestParams()
|
||||
if (!options.value.tabs?.dataIndex && !options.value.tabs.data) {
|
||||
await refresh()
|
||||
} else {
|
||||
options.value.tabs.defaultKey = options.value.tabs?.defaultKey ?? options.value.tabs.data[0].value
|
||||
await tabChange(options.value.tabs?.defaultKey)
|
||||
}
|
||||
}
|
||||
|
||||
const initRequestParams = () => {
|
||||
requestParams.value[config.request.page] = 1
|
||||
requestParams.value[config.request.pageSize] = options.value.pageSize ?? 10
|
||||
if (options.value.requestParamsLabel) {
|
||||
requestParams.value[options.value.requestParamsLabel] = options.value.requestParams
|
||||
} else {
|
||||
requestParams.value = Object.assign(requestParams.value, options.value.requestParams)
|
||||
}
|
||||
}
|
||||
|
||||
const requestHandle = async () => {
|
||||
loading.value = true
|
||||
isFunction(options.value.beforeRequest) && options.value.beforeRequest(requestParams.value)
|
||||
if (isFunction(currentApi.value)) {
|
||||
const response = config.parseResponseData(await currentApi.value(requestParams.value))
|
||||
if (response.rows) {
|
||||
tableData.value = response.rows
|
||||
if (response.pageInfo) {
|
||||
total.value = response.pageInfo.total
|
||||
openPagination.value = true
|
||||
} else {
|
||||
openPagination.value = false
|
||||
}
|
||||
} else {
|
||||
tableData.value = response
|
||||
}
|
||||
} else {
|
||||
console.error(`ma-crud error:crud.api not is Function.`)
|
||||
}
|
||||
isFunction(options.value.afterRequest) && options.value.afterRequest(tableData.value)
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const refresh = async () => {
|
||||
if (props.data) {
|
||||
loading.value = true
|
||||
const data = isArray(props.data) ? props.data : config.parseResponseData(await props.data(requestParams.value))
|
||||
if (data.rows) {
|
||||
tableData.value = data.rows
|
||||
openPagination.value = true
|
||||
} else {
|
||||
tableData.value = data
|
||||
}
|
||||
loading.value = false
|
||||
} else {
|
||||
currentApi.value =
|
||||
isRecovery.value && options.value.recycleApi && isFunction(options.value.recycleApi)
|
||||
? options.value.recycleApi
|
||||
: options.value.api
|
||||
await requestHandle()
|
||||
}
|
||||
}
|
||||
|
||||
const searchSubmitHandler = async (formData) => {
|
||||
if (options.value.requestParamsLabel && requestParams.value[options.value.requestParamsLabel]) {
|
||||
requestParams.value[options.value.requestParamsLabel] = Object.assign(
|
||||
requestParams.value[options.value.requestParamsLabel],
|
||||
formData
|
||||
)
|
||||
} else if (options.value.requestParamsLabel) {
|
||||
requestParams.value[options.value.requestParamsLabel] = Object.assign({}, formData)
|
||||
} else {
|
||||
requestParams.value = Object.assign(requestParams.value, formData)
|
||||
}
|
||||
if (options.value.beforeSearch && isFunction(options.value.beforeSearch)) {
|
||||
options.value.beforeSearch(requestParams.value)
|
||||
}
|
||||
await pageChangeHandler(1)
|
||||
if (options.value.afterSearch && isFunction(options.value.afterSearch)) {
|
||||
options.value.afterSearch(requestParams.value)
|
||||
}
|
||||
}
|
||||
|
||||
const pageSizeChangeHandler = async (pageSize) => {
|
||||
requestParams.value[config.request.page] = 1
|
||||
requestParams.value[config.request.pageSize] = pageSize
|
||||
await refresh()
|
||||
}
|
||||
|
||||
const pageChangeHandler = async (currentPage) => {
|
||||
requestParams.value[config.request.page] = currentPage
|
||||
await refresh()
|
||||
}
|
||||
|
||||
const toggleSearch = async () => {
|
||||
const dom = crudHeaderRef.value?.style
|
||||
if (dom) {
|
||||
crudSearchRef.value.showSearch ? crudSearchRef.value.setSearchHidden() : crudSearchRef.value.setSearchDisplay()
|
||||
|
||||
await nextTick(() => {
|
||||
headerHeight.value = crudHeaderRef.value.offsetHeight
|
||||
options.value.pageLayout === "fixed" && settingFixedPage()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const settingFixedPage = () => {
|
||||
const workAreaHeight = document.querySelector(".work-area").offsetHeight
|
||||
const tableHeight = workAreaHeight - headerHeight.value - (openPagination.value ? 152 : 108)
|
||||
crudContentRef.value.style.height = tableHeight + "px"
|
||||
}
|
||||
|
||||
const tableSetting = () => {
|
||||
crudSettingRef.value.open()
|
||||
}
|
||||
|
||||
const requestSuccess = async (response) => {
|
||||
if (response && response.code && response.code === 200) {
|
||||
options.value.dataCompleteRefresh && (await refresh())
|
||||
if (reloadColumn.value) {
|
||||
reloadColumn.value = false
|
||||
await nextTick(() => {
|
||||
reloadColumn.value = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const addAction = () => {
|
||||
if (isFunction(options.value.beforeOpenAdd) && !options.value.beforeOpenAdd()) {
|
||||
return false
|
||||
}
|
||||
if (options.value.add.action && isFunction(options.value.add.action)) {
|
||||
options.value.add.action()
|
||||
} else {
|
||||
crudFormRef.value.add()
|
||||
}
|
||||
}
|
||||
|
||||
const editAction = (record) => {
|
||||
if (isFunction(options.value.beforeOpenEdit) && !options.value.beforeOpenEdit(record)) {
|
||||
return false
|
||||
}
|
||||
if (options.value.edit.action && isFunction(options.value.edit.action)) {
|
||||
options.value.edit.action(record)
|
||||
} else {
|
||||
crudFormRef.value.edit(record)
|
||||
}
|
||||
}
|
||||
|
||||
const dbClickOpenEdit = (record) => {
|
||||
if (options.value.isDbClickEdit) {
|
||||
if (isRecovery.value) {
|
||||
Message.error("回收站数据不可编辑")
|
||||
return
|
||||
}
|
||||
|
||||
if (options.value.edit.api && isFunction(options.value.edit.api)) {
|
||||
editAction(record)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const importAction = () => crudImportRef.value.open()
|
||||
|
||||
const exportAction = () => {
|
||||
Message.info("请求服务器下载文件中...")
|
||||
const data = options.value.requestParamsLabel
|
||||
? requestParams.value[options.value.requestParamsLabel]
|
||||
: requestParams.value
|
||||
const download = (url) => request({ url, data, method: "post", timeout: 60 * 1000, responseType: "blob" })
|
||||
|
||||
download(options.value.export.url)
|
||||
.then((res) => {
|
||||
tool.download(res)
|
||||
Message.success("请求成功,文件开始下载")
|
||||
})
|
||||
.catch(() => {
|
||||
Message.error("请求服务器错误,下载失败")
|
||||
})
|
||||
}
|
||||
|
||||
const deletesMultipleAction = async () => {
|
||||
if (selecteds.value && selecteds.value.length > 0) {
|
||||
const api = isRecovery.value ? options.value.delete.realApi : options.value.delete.api
|
||||
let data = {}
|
||||
if (isFunction(options.value.beforeDelete) && !(data = options.value.beforeDelete(selecteds.value))) {
|
||||
return false
|
||||
}
|
||||
const response = await api(Object.assign({ ids: selecteds.value }, data))
|
||||
if (options.value.afterDelete && isFunction(options.value.afterDelete)) {
|
||||
options.value.afterDelete(response)
|
||||
}
|
||||
response.success && Message.success(response.message || `删除成功!`)
|
||||
await refresh()
|
||||
} else {
|
||||
Message.error("至少选择一条数据")
|
||||
}
|
||||
}
|
||||
|
||||
const recoverysMultipleAction = async () => {
|
||||
if (selecteds.value && selecteds.value.length > 0) {
|
||||
const response = await options.value.recovery.api({ ids: selecteds.value })
|
||||
response.success && Message.success(response.message || `恢复成功!`)
|
||||
await refresh()
|
||||
} else {
|
||||
Message.error("至少选择一条数据")
|
||||
}
|
||||
}
|
||||
|
||||
const setSelecteds = (key) => {
|
||||
selecteds.value = key
|
||||
}
|
||||
|
||||
const switchDataType = async () => {
|
||||
isRecovery.value = !isRecovery.value
|
||||
currentApi.value =
|
||||
isRecovery.value && options.value.recycleApi && isFunction(options.value.recycleApi)
|
||||
? options.value.recycleApi
|
||||
: options.value.api
|
||||
await requestData()
|
||||
}
|
||||
|
||||
const handlerExpand = () => {
|
||||
expandState.value = !expandState.value
|
||||
expandState.value ? tableRef.value.expandAll(true) : tableRef.value.expandAll(false)
|
||||
}
|
||||
|
||||
const handlerSort = async (name, type) => {
|
||||
const col = columns.value.find((item) => name === item.dataIndex)
|
||||
if (col.sortable && col.sortable.sorter) {
|
||||
if (type) {
|
||||
requestParams.value.orderBy = name
|
||||
requestParams.value.orderType = type === "ascend" ? "asc" : "desc"
|
||||
} else {
|
||||
requestParams.value.orderBy = undefined
|
||||
requestParams.value.orderType = undefined
|
||||
}
|
||||
await refresh()
|
||||
}
|
||||
}
|
||||
|
||||
const getTableData = () => {
|
||||
return tableData.value
|
||||
}
|
||||
|
||||
const __summary = ({ data }) => {
|
||||
if (options.value.showSummary && isArray(options.value.summary)) {
|
||||
const summary = options.value.summary
|
||||
let summaryData = {}
|
||||
let summaryPrefixText = {}
|
||||
let summarySuffixText = {}
|
||||
let length = data.length || 0
|
||||
summary.map((item) => {
|
||||
summaryData[item.dataIndex] = 0
|
||||
summaryPrefixText[item.dataIndex] = item?.prefixText ?? ""
|
||||
summarySuffixText[item.dataIndex] = item?.suffixText ?? ""
|
||||
data.map((record) => {
|
||||
if (record[item.dataIndex]) {
|
||||
if (item.action && item.action === "sum") {
|
||||
summaryData[item.dataIndex] += parseFloat(record[item.dataIndex])
|
||||
}
|
||||
if (item.action && item.action === "avg") {
|
||||
summaryData[item.dataIndex] += parseFloat(record[item.dataIndex]) / length
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
for (let i in summaryData) {
|
||||
summaryData[i] =
|
||||
summaryPrefixText[i] + tool.groupSeparator(summaryData[i].toFixed(2)) + summarySuffixText[i]
|
||||
}
|
||||
|
||||
return [summaryData]
|
||||
}
|
||||
}
|
||||
|
||||
const resizeHandler = () => {
|
||||
headerHeight.value = crudHeaderRef.value.offsetHeight
|
||||
settingFixedPage()
|
||||
}
|
||||
|
||||
const tabChange = async (value) => {
|
||||
const searchKey = options.value.tabs?.searchKey ?? options.value.tabs?.dataIndex ?? "tabValue"
|
||||
const params = {}
|
||||
params[searchKey] = value
|
||||
requestParams.value = Object.assign(requestParams.value, params)
|
||||
await maEvent.customeEvent(options.value.tabs, value, "onChange")
|
||||
await refresh()
|
||||
}
|
||||
|
||||
const printTable = () => {
|
||||
new Print(crudContentRef.value)
|
||||
}
|
||||
|
||||
const openContextMenu = (ev, record) => {
|
||||
options.value?.contextMenu?.enabled === true && crudContextMenuRef.value.openContextMenu(ev, record)
|
||||
}
|
||||
|
||||
const execContextMenuCommand = async (args) => {
|
||||
const item = args.contextItem
|
||||
const record = args.record
|
||||
switch (item.operation) {
|
||||
case "print":
|
||||
await printTable()
|
||||
break
|
||||
case "refresh":
|
||||
await refresh()
|
||||
break
|
||||
case "add":
|
||||
addAction()
|
||||
break
|
||||
case "edit":
|
||||
editAction(record)
|
||||
break
|
||||
case "delete":
|
||||
crudColumnRef.value.deleteAction(record)
|
||||
break
|
||||
default:
|
||||
await maEvent.customeEvent(item, args, "onCommand")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const tabsHandler = async () => {
|
||||
// 处理tabs
|
||||
const tabs = options.value.tabs
|
||||
if (isFunction(tabs.data) || isArray(tabs.data)) {
|
||||
tabs.data = isFunction(tabs.data) ? await tabs.data() : tabs.data
|
||||
} else if (!isUndefined(tabs.dataIndex)) {
|
||||
const col = props.columns.find((item) => item.dataIndex === tabs.dataIndex)
|
||||
if (col.search === true && isObject(col.dict)) {
|
||||
tabs.data = dicts.value[tabs.dataIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (typeof options.value.autoRequest == "undefined" || options.value.autoRequest) {
|
||||
await requestData()
|
||||
}
|
||||
|
||||
if (!options.value.expandSearch && crudSearchRef.value) {
|
||||
crudSearchRef.value.setSearchHidden()
|
||||
}
|
||||
|
||||
if (options.value.pageLayout === "fixed") {
|
||||
window.addEventListener("resize", resizeHandler, false)
|
||||
headerHeight.value = crudHeaderRef.value.offsetHeight
|
||||
settingFixedPage()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (options.value.pageLayout === "fixed") {
|
||||
window.removeEventListener("resize", resizeHandler, false)
|
||||
}
|
||||
})
|
||||
|
||||
const getCurrentAction = () => crudFormRef.value.currentAction
|
||||
const getFormData = () => crudFormRef.value.form
|
||||
|
||||
const getFormColumns = async (type = "add") => {
|
||||
return await crudFormRef.value.getFormColumns(type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取column属性服务类
|
||||
* @returns ColumnService
|
||||
*/
|
||||
const getColumnService = (strictMode = true) => {
|
||||
return new ColumnService({ columns: columns.value, cascaders: cascaders.value, dicts: dicts.value }, strictMode)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
refresh,
|
||||
requestData,
|
||||
addAction,
|
||||
editAction,
|
||||
getTableData,
|
||||
setSelecteds,
|
||||
getCurrentAction,
|
||||
getFormData,
|
||||
getFormColumns,
|
||||
getColumnService,
|
||||
requestParams,
|
||||
isRecovery,
|
||||
tableRef,
|
||||
crudFormRef,
|
||||
crudSearchRef,
|
||||
crudImportRef,
|
||||
crudSettingRef
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.__search-panel {
|
||||
transition: display 1s;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
._crud-footer {
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user