|
|
@ -1,135 +1,156 @@ |
|
|
|
import html, { getProp } from "html"; |
|
|
|
import AppForm from "../form/index.js"; |
|
|
|
import { get, post } from "../../request/index.js"; |
|
|
|
import { ref, reactive } from "vue"; |
|
|
|
import { useRoute } from "vue-router"; |
|
|
|
import request, { get, post } from "../../request/index.js"; |
|
|
|
import { defineAsyncComponent, ref, reactive, onMounted } from "vue"; |
|
|
|
import { useRoute, useRouter } from "vue-router"; |
|
|
|
import { useI18n } from "vue-i18n"; |
|
|
|
import SvgIcon from "../../components/icon/index.js"; |
|
|
|
import { schemaToModel } from "../../utils/index.js"; |
|
|
|
import { listToTree, schemaToModel } from "../../utils/index.js"; |
|
|
|
import qs from "../../lib/qs/shim.js"; |
|
|
|
import AppFormInput from "../form/form-input.js"; |
|
|
|
import VueOfficeExcel from "@vue-office/excel"; |
|
|
|
import { camelCase, capitalize } from "lodash"; |
|
|
|
|
|
|
|
export default { |
|
|
|
components: { AppForm, SvgIcon, AppFormInput, VueOfficeExcel }, |
|
|
|
name: "AppList", |
|
|
|
components: { |
|
|
|
AppForm: defineAsyncComponent(() => import("../form/index.js")), |
|
|
|
SvgIcon: defineAsyncComponent(() => import("../../components/icon/index.js")), |
|
|
|
AppFormInput: defineAsyncComponent(() => import("../form/form-input.js")), |
|
|
|
VueOfficeExcel, |
|
|
|
}, |
|
|
|
template: html` |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<app-form |
|
|
|
inline |
|
|
|
mode="query" |
|
|
|
label-position="left" |
|
|
|
:schema="queryFromSchema" |
|
|
|
v-model="data.query" |
|
|
|
@submit="load" |
|
|
|
:hideButton="true" |
|
|
|
:isQueryForm="true" |
|
|
|
/> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row style="padding-bottom:20px;"> |
|
|
|
<el-col> |
|
|
|
<template v-for="item in $route.meta.buttons"> |
|
|
|
<el-button |
|
|
|
:class="item.meta.htmlClass??'el-button--primary'" |
|
|
|
v-if="item.meta.isTop" |
|
|
|
@click="click(item,selectedRows)" |
|
|
|
> |
|
|
|
<el-icon v-if="item.meta.icon"><svg-icon :name="item.meta.icon" /></el-icon> |
|
|
|
<span>{{item.meta.title}}</span> |
|
|
|
<div v-loading="tableLoading"> |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<app-form |
|
|
|
inline |
|
|
|
mode="query" |
|
|
|
label-position="left" |
|
|
|
:schema="querySchema" |
|
|
|
v-model="queryModel" |
|
|
|
@submit="load" |
|
|
|
:hideButton="true" |
|
|
|
:isQueryForm="true" |
|
|
|
v-if="querySchema" |
|
|
|
/> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row style="padding-bottom:20px;"> |
|
|
|
<el-col> |
|
|
|
<template v-for="item in buttons"> |
|
|
|
<el-button |
|
|
|
:class="item.meta.htmlClass??'el-button--primary'" |
|
|
|
v-if="item.meta.isTop" |
|
|
|
@click="click(item,selectedRows)" |
|
|
|
> |
|
|
|
<el-icon v-if="item.meta.icon"><svg-icon :name="item.meta.icon" /></el-icon> |
|
|
|
<span>{{item.meta.title}}</span> |
|
|
|
</el-button> |
|
|
|
</template> |
|
|
|
<el-button @click="click('filter',selectedRows)"> |
|
|
|
<el-icon><ep-filter /></el-icon> |
|
|
|
<span>{{$t('筛选')}}</span> |
|
|
|
</el-button> |
|
|
|
</template> |
|
|
|
<slot name="tableButtons" :rows="selectedRows"></slot> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<el-scrollbar> |
|
|
|
<el-table |
|
|
|
ref="tableRef" |
|
|
|
v-loading="tableLoading" |
|
|
|
row-key="id" |
|
|
|
table-layout="auto" |
|
|
|
border |
|
|
|
fit |
|
|
|
:data="data.items" |
|
|
|
@selection-change="handleSelectionChange" |
|
|
|
@sort-change="sortChange" |
|
|
|
:header-cell-class-name="getClass" |
|
|
|
v-if="data.items" |
|
|
|
> |
|
|
|
<el-table-column fixed="left" type="selection" /> |
|
|
|
<el-table-column type="index" :label="$t('rowIndex')"> |
|
|
|
<template #default="scope"> {{ (data.pageIndex - 1) * data.pageSize + scope.$index + 1 }} </template> |
|
|
|
</el-table-column> |
|
|
|
<template v-for="(item,key) in tableSchema.items.properties"> |
|
|
|
<template v-if="key==='properties'"> |
|
|
|
<el-table-column :label="subKey" v-for="(subItem,subKey) in item.properties"> |
|
|
|
<template #default="scope">{{ scope.row[key][subKey] }} </template> |
|
|
|
</el-table-column> |
|
|
|
</template> |
|
|
|
<template v-else-if="item.navigation"> |
|
|
|
<el-table-column :prop="key" :label="item.title"> |
|
|
|
<template #default="scope">{{getProp(scope.row,item.navigation)}}</template> |
|
|
|
</el-table-column> |
|
|
|
</template> |
|
|
|
<template v-else> |
|
|
|
<template v-if="showColumn(item,key)"> |
|
|
|
<el-table-column :prop="key" sortable="custom" :sort-orders="['descending', 'ascending', null]"> |
|
|
|
<template #header="scope">{{item.title}}</template> |
|
|
|
<slot name="tableButtons" :rows="selectedRows"></slot> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<el-scrollbar> |
|
|
|
<el-table |
|
|
|
:key="tableKey" |
|
|
|
ref="tableRef" |
|
|
|
:tree-props="treeProps" |
|
|
|
:data="tableData" |
|
|
|
@selection-change="handleSelectionChange" |
|
|
|
@sort-change="sortChange" |
|
|
|
:header-cell-class-name="getClass" |
|
|
|
row-key="id" |
|
|
|
table-layout="auto" |
|
|
|
border |
|
|
|
fit |
|
|
|
> |
|
|
|
<el-table-column fixed="left" type="selection" /> |
|
|
|
<el-table-column type="index" :label="$t('rowIndex')"> |
|
|
|
<template #default="scope"> |
|
|
|
{{ (pageModel.pageIndex - 1) * pageModel.pageSize + scope.$index + 1 }} |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
<template v-for="(item,key) in config.table.schema.properties"> |
|
|
|
<template v-if="key==='properties'"> |
|
|
|
<el-table-column :label="subKey" v-for="(subItem,subKey) in item.properties"> |
|
|
|
<template #default="scope">{{ scope.row[key][subKey] }} </template> |
|
|
|
</el-table-column> |
|
|
|
</template> |
|
|
|
<template v-else-if="item.navigation"> |
|
|
|
<el-table-column :prop="key" :label="item.title"> |
|
|
|
<template #default="scope">{{getProp(scope.row,item.navigation)}}</template> |
|
|
|
</el-table-column> |
|
|
|
</template> |
|
|
|
<template v-else-if="item.oneToMany"> |
|
|
|
<el-table-column :prop="key" :label="item.title"> |
|
|
|
<template #default="scope"> |
|
|
|
<app-form-input :isReadOnly="true" :schema="item" :prop="key" v-model="scope.row" /> |
|
|
|
<el-link type="primary" @click="showList(scope.row[key],item.oneToMany)"> |
|
|
|
<app-form-input :isReadOnly="true" :schema="item" :prop="key" v-model="scope.row" /> |
|
|
|
</el-link> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
<slot name="columns"></slot> |
|
|
|
<el-table-column fixed="right"> |
|
|
|
<template #header> |
|
|
|
<el-button @click="filterDrawer = true"> |
|
|
|
{{$t('operations')}} |
|
|
|
<el-icon class="el-icon--right"><ep-filter /></el-icon> |
|
|
|
</el-button> |
|
|
|
</template> |
|
|
|
<template #default="scope"> |
|
|
|
<div class="flex"> |
|
|
|
<template v-for="item in $route.meta.buttons"> |
|
|
|
<el-button |
|
|
|
:class="item.meta.htmlClass??'el-button--primary'" |
|
|
|
v-if="!item.meta.isTop" |
|
|
|
@click="click(item,[scope.row])" |
|
|
|
> |
|
|
|
<el-icon v-if="item.meta.icon"><svg-icon :name="item.meta.icon" /></el-icon> |
|
|
|
<span>{{item.meta.title}}</span> |
|
|
|
</el-button> |
|
|
|
<template v-else> |
|
|
|
<template v-if="showColumn(item,key)"> |
|
|
|
<el-table-column :prop="key" sortable="custom" :sort-orders="['descending', 'ascending', null]"> |
|
|
|
<template #header="scope">{{item.title}}</template> |
|
|
|
<template #default="scope"> |
|
|
|
<app-form-input :isReadOnly="true" :schema="item" :prop="key" v-model="scope.row" /> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
</template> |
|
|
|
<slot name="rowButtons" :rows="[scope.row]"></slot> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
</el-table> |
|
|
|
</el-scrollbar> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<el-pagination |
|
|
|
v-if="data.items&&data.pageSize<data.totalCount" |
|
|
|
v-model:currentPage="data.pageIndex" |
|
|
|
v-model:page-size="data.pageSize" |
|
|
|
:total="data.totalCount" |
|
|
|
:page-sizes="[20, 50, 100]" |
|
|
|
class="justify-end" |
|
|
|
:background="true" |
|
|
|
layout="total, sizes, prev, pager, next, jumper" |
|
|
|
@size-change="onPageSizeChange" |
|
|
|
@current-change="onPageIndexChange" |
|
|
|
style="margin-top:20px" |
|
|
|
/> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<slot name="columns"></slot> |
|
|
|
<el-table-column fixed="right"> |
|
|
|
<template #header> |
|
|
|
<el-button @click="filterDrawer = true"> |
|
|
|
{{$t('operations')}} |
|
|
|
<el-icon class="el-icon--right"><ep-filter /></el-icon> |
|
|
|
</el-button> |
|
|
|
</template> |
|
|
|
<template #default="scope"> |
|
|
|
<div class="flex"> |
|
|
|
<template v-for="item in buttons"> |
|
|
|
<el-button |
|
|
|
:class="item.meta.htmlClass??'el-button--primary'" |
|
|
|
v-if="!item.meta.isTop" |
|
|
|
@click="click(item,[scope.row])" |
|
|
|
> |
|
|
|
<el-icon v-if="item.meta.icon"><svg-icon :name="item.meta.icon" /></el-icon> |
|
|
|
<span>{{item.meta.title}}</span> |
|
|
|
</el-button> |
|
|
|
</template> |
|
|
|
<slot name="rowButtons" :rows="[scope.row]"></slot> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
</el-table> |
|
|
|
</el-scrollbar> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<el-pagination |
|
|
|
v-if="tableData.length&&pageModel.pageSize<pageModel.totalCount" |
|
|
|
v-model:currentPage="pageModel.pageIndex" |
|
|
|
v-model:page-size="pageModel.pageSize" |
|
|
|
:total="pageModel.total" |
|
|
|
:page-sizes="pageModel.sizeList" |
|
|
|
class="justify-end" |
|
|
|
:background="true" |
|
|
|
layout="total, sizes, prev, pager, next, jumper" |
|
|
|
@size-change="onPageSizeChange" |
|
|
|
@current-change="onPageIndexChange" |
|
|
|
style="margin-top:20px" |
|
|
|
/> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</div> |
|
|
|
<el-drawer v-model="filterDrawer" destroy-on-close @close="tableRef.doLayout()"> |
|
|
|
<template #header> <span class="el-dialog__title"> {{$t('filter')}} </span> </template> |
|
|
|
<el-scrollbar> |
|
|
@ -151,30 +172,138 @@ export default { |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-scrollbar> |
|
|
|
|
|
|
|
<template #footer> |
|
|
|
<span class="dialog-footer"> |
|
|
|
<el-button type="primary" @click="filterDrawer=false"> {{$t('confirm')}} </el-button> |
|
|
|
</span> |
|
|
|
</template> |
|
|
|
</el-drawer> |
|
|
|
<el-dialog v-model="dialogVisible" align-center destroy-on-close width="700"> |
|
|
|
<el-drawer v-model="subDrawer" destroy-on-close size="50%"> |
|
|
|
<el-scrollbar> |
|
|
|
<app-list |
|
|
|
v-if="subDrawer" |
|
|
|
:controller="subListQuery.controller" |
|
|
|
:query="subListQuery.query" |
|
|
|
:buttons="subListQuery.buttons" |
|
|
|
/> |
|
|
|
</el-scrollbar> |
|
|
|
<template #footer> |
|
|
|
<span class="dialog-footer"> |
|
|
|
<el-button type="primary" @click="subDrawer=false"> {{$t('confirm')}} </el-button> |
|
|
|
</span> |
|
|
|
</template> |
|
|
|
</el-drawer> |
|
|
|
<el-dialog |
|
|
|
v-model="dialogVisible" |
|
|
|
align-center |
|
|
|
destroy-on-close |
|
|
|
style="width:auto;min-width:500px;max-width:1000px;" |
|
|
|
> |
|
|
|
<template #header> <span class="el-dialog__title"> {{editFormTitle}} </span> </template> |
|
|
|
<el-row> |
|
|
|
<el-col style="max-height:calc(100vh - 180px );"> |
|
|
|
<el-row v-loading="editFormloading"> |
|
|
|
<el-col style="max-height:calc(100vh - 180px );min-height:100%;"> |
|
|
|
<el-scrollbar> |
|
|
|
<app-form |
|
|
|
v-loading="editFormloading" |
|
|
|
:disabled="editFormMode==='details'" |
|
|
|
:mode="editFormMode" |
|
|
|
ref="editFormRef" |
|
|
|
inline |
|
|
|
label-position="left" |
|
|
|
:hideButton="true" |
|
|
|
:schema="editFormSchema" |
|
|
|
v-model="editFormModel" |
|
|
|
v-if="editFormMode!=='import'" |
|
|
|
/> |
|
|
|
<template v-if="editFormMode==='create'||editFormMode==='update'||editFormMode==='details'"> |
|
|
|
<app-form |
|
|
|
:disabled="editFormMode==='details'" |
|
|
|
:mode="editFormMode" |
|
|
|
ref="editFormRef" |
|
|
|
inline |
|
|
|
label-position="left" |
|
|
|
:hideButton="true" |
|
|
|
:schema="editFormSchema" |
|
|
|
v-model="editFormModel" |
|
|
|
v-if="editFormSchema&&editFormMode" |
|
|
|
/> |
|
|
|
</template> |
|
|
|
<template v-else-if="editFormMode==='export'"> |
|
|
|
<el-form :model="exportModel"> |
|
|
|
<el-form-item :label="$t('全部')"> |
|
|
|
<el-switch v-model="exportModel.includeAll" /> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item :label="$t('已删除')"> |
|
|
|
<el-switch v-model="exportModel.includeDeleted" /> |
|
|
|
</el-form-item> |
|
|
|
</el-form> |
|
|
|
</template> |
|
|
|
<template v-else-if="editFormMode==='import'"> |
|
|
|
<el-form :model="importModel" inline> |
|
|
|
<el-form-item :label="$t('部分成功')"> |
|
|
|
<el-switch v-model="importModel.partial" /> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item :label="$t('全部替换')"> |
|
|
|
<el-switch v-model="importModel.replace" /> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item :label="$t('导入模板')"> |
|
|
|
<el-link type="primary" @click="getImportTemplate">{{$t('下载')}}</el-link> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item :label="$t('文件')"> |
|
|
|
<el-upload |
|
|
|
ref="uploadRef" |
|
|
|
drag |
|
|
|
accept=".xlsx" |
|
|
|
:disabled="fileList.length===1" |
|
|
|
:limit="1" |
|
|
|
:auto-upload="false" |
|
|
|
:on-change="handleChange" |
|
|
|
> |
|
|
|
<el-icon class="el-icon--upload"><ep-upload-filled /></el-icon> |
|
|
|
</el-upload> |
|
|
|
</el-form-item> |
|
|
|
</el-form> |
|
|
|
</template> |
|
|
|
<template v-else-if="editFormMode==='filter'"> |
|
|
|
<el-form :model="queryList" inline class="filter"> |
|
|
|
<el-row v-for="(item,index) in queryList"> |
|
|
|
<el-col :span="6"> |
|
|
|
<el-select v-model="item.property" :placeholder="$t('字段')"> |
|
|
|
<el-option v-for="(value, prop) in querySchema.properties" :value="prop" :label="value.title" /> |
|
|
|
</el-select> |
|
|
|
</el-col> |
|
|
|
<el-col :span="6"> |
|
|
|
<el-select v-model="item.operator" :placeholder="$t('操作符')"> |
|
|
|
<el-option value="{0}=@0" :label="$t('等于')" /> |
|
|
|
<el-option value="{0}!=@0" :label="$t('不等于')" /> |
|
|
|
<el-option value="{0}>@0" :label="$t('大于')" /> |
|
|
|
<el-option value="{0}>=@0" :label="$t('大于等于')" /> |
|
|
|
<el-option value="{0}<@0" :label="$t('小于')" /> |
|
|
|
<el-option value="{0}<=@0" :label="$t('小于等于')" /> |
|
|
|
<el-option value="{0}.Contains(@0)" :label="$t('包含')" /> |
|
|
|
<el-option value="{0}.StartsWith(@0)" :label="$t('开始于')" /> |
|
|
|
<el-option value="{0}.StartsWith(@0)" :label="$t('结束于')" /> |
|
|
|
</el-select> |
|
|
|
</el-col> |
|
|
|
<el-col :span="6"> |
|
|
|
<el-input v-model="item.value" :placeholder="$t('值')" /> |
|
|
|
</el-col> |
|
|
|
<!-- <el-col :span="4"> |
|
|
|
<el-select v-model="item.logic" :placeholder="$t('关系')"> |
|
|
|
<el-option value="and" :label="$t('且')" /> |
|
|
|
<el-option value="or" :label="$t('或')" /> |
|
|
|
</el-select> |
|
|
|
</el-col> --> |
|
|
|
<el-col :span="2"> |
|
|
|
<el-button circle @click="queryList.splice(index, 1)"> |
|
|
|
<template #icon> |
|
|
|
<ep-close /> |
|
|
|
</template> |
|
|
|
</el-button> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
<el-row> |
|
|
|
<el-col> |
|
|
|
<el-button circle @click="pushQueryList"> |
|
|
|
<template #icon> |
|
|
|
<ep-plus /> |
|
|
|
</template> |
|
|
|
</el-button> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-form> |
|
|
|
</template> |
|
|
|
<template v-else> |
|
|
|
<slot :name="editFormMode"></slot> |
|
|
|
</template> |
|
|
|
</el-scrollbar> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
@ -185,25 +314,66 @@ export default { |
|
|
|
</template> |
|
|
|
</el-dialog> |
|
|
|
`,
|
|
|
|
props: ["modelValue"], |
|
|
|
styles: html`<style>
|
|
|
|
.el-form.filter .el-col { |
|
|
|
padding: 5px; |
|
|
|
} |
|
|
|
</style>`, |
|
|
|
props: ["modelValue", "config", "querySchema", "controller", "query", "buttons"], |
|
|
|
emits: ["command"], |
|
|
|
async setup(props, context) { |
|
|
|
// 变量定义
|
|
|
|
//// 配置
|
|
|
|
const config = ref(props.config); |
|
|
|
//// 分页
|
|
|
|
const pageModel = reactive({ |
|
|
|
sizeList: [20, 50, 100], |
|
|
|
pageIndex: 1, |
|
|
|
pageSize: 10, |
|
|
|
total: 0, |
|
|
|
}); |
|
|
|
const treeProps = reactive({ |
|
|
|
children: "children", |
|
|
|
}); |
|
|
|
const tableKey = ref(false); |
|
|
|
const tableRef = ref(null); |
|
|
|
const uploadRef = ref(null); |
|
|
|
const columns = ref([]); |
|
|
|
const filterDrawer = ref(false); |
|
|
|
const tableLoading = ref(false); |
|
|
|
const subDrawer = ref(false); |
|
|
|
const subListQuery = ref({}); |
|
|
|
const tableLoading = ref(true); |
|
|
|
const selectedRows = ref([]); |
|
|
|
const dialogVisible = ref(false); |
|
|
|
const route = useRoute(); |
|
|
|
const router = useRouter(); |
|
|
|
const { t } = useI18n(); |
|
|
|
const baseUrl = `${route.meta.path}`.substring(1); |
|
|
|
const indexUrl = `${baseUrl}/index`; |
|
|
|
const vm = (await get(indexUrl)).data; |
|
|
|
const schema = vm.schema; |
|
|
|
const data = reactive(vm.model ?? schemaToModel(schema)); |
|
|
|
const buttons = ref(props.buttons ?? route.meta.children); |
|
|
|
const baseUrl = props.controller ?? `${route.meta.path}`; |
|
|
|
const indexUrl = props.indexUrl ?? `${baseUrl}/index`; |
|
|
|
const queryModel = ref({}); |
|
|
|
const sortColumns = ref(new Map()); |
|
|
|
const querySchema = ref(props.querySchema); |
|
|
|
const queryList = ref([]); |
|
|
|
const tableSchema = ref({}); |
|
|
|
const tableData = ref([]); |
|
|
|
const editFormRef = ref(null); |
|
|
|
const editFormloading = ref(false); |
|
|
|
const editFormMode = ref(null); |
|
|
|
const editFormTitle = ref(""); |
|
|
|
const editFormSchema = ref(null); |
|
|
|
const editFormModel = ref(null); |
|
|
|
const exportModel = reactive({ |
|
|
|
includeAll: false, |
|
|
|
includeDeleted: false, |
|
|
|
}); |
|
|
|
const importModel = reactive({ |
|
|
|
partial: true, |
|
|
|
replace: false, |
|
|
|
}); |
|
|
|
const fileList = ref([]); |
|
|
|
const getSortModel = (model) => { |
|
|
|
const orderBy = model.orderBy |
|
|
|
model.orderBy |
|
|
|
.split(",") |
|
|
|
.map((o) => o.trim()) |
|
|
|
.filter((o) => o) |
|
|
@ -212,32 +382,30 @@ export default { |
|
|
|
order: (o.split(" ").filter((o) => o)[1] ?? "asc") + "ending", |
|
|
|
})) |
|
|
|
.forEach((o) => sortColumns.value.set(o.prop, o.order)); |
|
|
|
return orderBy; |
|
|
|
}; |
|
|
|
const sortModel = reactive(getSortModel(data)); |
|
|
|
const getColumns = (schema) => { |
|
|
|
Object.keys(schema.properties).forEach((propertyName) => { |
|
|
|
const property = schema.properties[propertyName]; |
|
|
|
if (property.type !== "object" && property.type !== "array" && !property.hidden && property.showForList) { |
|
|
|
columns.value.push({ name: propertyName, title: property.title, checked: true }); |
|
|
|
} |
|
|
|
}); |
|
|
|
}; |
|
|
|
const getClass = ({ row, column }) => { |
|
|
|
if (column.property) { |
|
|
|
column.order = sortColumns.value.get(column.property); |
|
|
|
} |
|
|
|
}; |
|
|
|
const sortChange = ({ column, prop, order }) => { |
|
|
|
const sortChange = async ({ column, prop, order }) => { |
|
|
|
if (order === null) { |
|
|
|
sortColumns.value.delete(prop); |
|
|
|
} else { |
|
|
|
sortColumns.value.set(prop, order); |
|
|
|
} |
|
|
|
data.orderBy = Array.from(sortColumns.value) |
|
|
|
queryModel.value.orderBy = Array.from(sortColumns.value) |
|
|
|
.map((o) => capitalize(o[0]) + (o[1] === "ascending" ? "" : ` DESC`)) |
|
|
|
.join(","); |
|
|
|
load(indexUrl); |
|
|
|
}; |
|
|
|
const getColumns = (schema) => { |
|
|
|
Object.keys(schema.properties).forEach((propertyName) => { |
|
|
|
const property = schema.properties[propertyName]; |
|
|
|
if (property.type !== "object" && property.type !== "array" && !property.hidden) { |
|
|
|
columns.value.push({ name: propertyName, title: property.title, checked: true }); |
|
|
|
} |
|
|
|
}); |
|
|
|
await load(indexUrl); |
|
|
|
}; |
|
|
|
const showColumn = (item, prop) => { |
|
|
|
return ( |
|
|
@ -247,63 +415,62 @@ export default { |
|
|
|
columns.value.findIndex((o) => o.name === prop && o.checked) >= 0 |
|
|
|
); |
|
|
|
}; |
|
|
|
getColumns(schema.properties.query); |
|
|
|
const queryFromSchema = schema.properties.query; |
|
|
|
const tableSchema = schema.properties.items; |
|
|
|
const editFormRef = ref(null); |
|
|
|
const editFormloading = ref(false); |
|
|
|
const editFormMode = ref(null); |
|
|
|
const editFormTitle = ref(""); |
|
|
|
const editFormSchema = reactive({}); |
|
|
|
const editFormModel = reactive({}); |
|
|
|
const exportModel = reactive({ |
|
|
|
includeAll: false, |
|
|
|
includeDeleted: false, |
|
|
|
}); |
|
|
|
|
|
|
|
const handleSelectionChange = (rows) => (selectedRows.value = rows); |
|
|
|
const load = async (url) => { |
|
|
|
tableLoading.value = true; |
|
|
|
try { |
|
|
|
const postData = JSON.parse(JSON.stringify(data)); |
|
|
|
delete postData["Id"]; |
|
|
|
delete postData["items"]; |
|
|
|
Object.assign(data, (await post(url, postData)).data); |
|
|
|
const url = config.value.query.url; |
|
|
|
const postData = JSON.parse(JSON.stringify(queryModel.value)); |
|
|
|
postData.filters = queryList.value.filter((o) => o.property && o.value); |
|
|
|
if (postData.items) { |
|
|
|
delete postData["items"]; |
|
|
|
} |
|
|
|
if (postData.query?.id) { |
|
|
|
delete postData.query["id"]; |
|
|
|
} |
|
|
|
const listData = (await request(url, postData, { method: config.value.query.method.toUpperCase() })).data; |
|
|
|
const items = listData.items; |
|
|
|
if (tableSchema.value.isTree) { |
|
|
|
items = listToTree(listData.items); |
|
|
|
} |
|
|
|
tableData.value = items; |
|
|
|
//data.value = listData;
|
|
|
|
queryModel.tableKey.value = !tableKey.value; |
|
|
|
} catch (error) { |
|
|
|
console.log(error); |
|
|
|
} finally { |
|
|
|
tableLoading.value = false; |
|
|
|
} |
|
|
|
}; |
|
|
|
const onPageIndexChange = () => load(indexUrl); |
|
|
|
const onPageSizeChange = () => load(indexUrl); |
|
|
|
const onPageIndexChange = async () => { |
|
|
|
await load(indexUrl); |
|
|
|
}; |
|
|
|
const onPageSizeChange = async () => await load(indexUrl); |
|
|
|
const click = async (item, rows) => { |
|
|
|
editFormMode.value = item.path; |
|
|
|
editFormloading.value = true; |
|
|
|
editFormMode.value = item.path ?? item; |
|
|
|
context.emit("command", item, rows); |
|
|
|
if (item.path === "index") { |
|
|
|
//list
|
|
|
|
await load(indexUrl); |
|
|
|
} else if (item.path === "details") { |
|
|
|
//details
|
|
|
|
const detailsUrl = `${baseUrl}/${item.path}?${qs.stringify({ id: rows[0].id })}`; |
|
|
|
Object.assign(editFormSchema, schema.properties.items.items); |
|
|
|
Object.assign(editFormModel, (await post(detailsUrl)).data); |
|
|
|
editFormTitle.value = `${t("details")}${schema.title}`; |
|
|
|
const url = `${baseUrl}/${item.path}?${qs.stringify({ id: rows[0].id })}`; |
|
|
|
editFormSchema.value = (await get(url)).data; |
|
|
|
editFormModel.value = (await post(url)).data; |
|
|
|
editFormTitle.value = `${querySchema.value?.title}${t("details")}`; |
|
|
|
dialogVisible.value = true; |
|
|
|
} else if (item.path === "create") { |
|
|
|
} else if (item.path === "create" || item.path === "update") { |
|
|
|
//create
|
|
|
|
const url = `${baseUrl}/${item.path}`; |
|
|
|
let url = `${baseUrl}/${item.path}`; |
|
|
|
if (item.path === "update") { |
|
|
|
url = `${url}?${qs.stringify({ id: rows[0].id })}`; |
|
|
|
} |
|
|
|
const vm = (await get(url)).data; |
|
|
|
Object.assign(editFormSchema, vm.schema); |
|
|
|
Object.assign(editFormModel, vm.model); |
|
|
|
editFormTitle.value = `${t("create")}${schema.title}`; |
|
|
|
dialogVisible.value = true; |
|
|
|
} else if (item.path === "update") { |
|
|
|
//update
|
|
|
|
const url = `${baseUrl}/${item.path}`; |
|
|
|
const vm = (await get(url, { id: rows[0].id })).data; |
|
|
|
Object.assign(editFormSchema, vm.schema); |
|
|
|
Object.assign(editFormModel, vm.model); |
|
|
|
editFormTitle.value = `${t("update")}${schema.title}`; |
|
|
|
editFormSchema.value = vm.schema; |
|
|
|
editFormModel.value = vm.model; |
|
|
|
editFormTitle.value = `${t(item.path)}${querySchema.value?.title}`; |
|
|
|
dialogVisible.value = true; |
|
|
|
} else if (item.path === "delete") { |
|
|
|
//delete
|
|
|
@ -318,15 +485,19 @@ export default { |
|
|
|
await load(indexUrl); |
|
|
|
} else if (item.path === "export") { |
|
|
|
//export
|
|
|
|
const url = `${baseUrl}/${item.path}`; |
|
|
|
const exportUrl = `${url}?${qs.stringify(exportModel)}`; |
|
|
|
await load(exportUrl); |
|
|
|
editFormTitle.value = `${t(item.path)}${querySchema.value?.title}`; |
|
|
|
dialogVisible.value = true; |
|
|
|
} else if (item.path === "import") { |
|
|
|
//import
|
|
|
|
const url = `${baseUrl}/${item.path}`; |
|
|
|
editFormTitle.value = `${t("import")}${schema.title}`; |
|
|
|
editFormTitle.value = `${t(item.path)}${querySchema.value?.title}`; |
|
|
|
fileList.value = []; |
|
|
|
dialogVisible.value = true; |
|
|
|
} else if (item === "filter") { |
|
|
|
editFormTitle.value = t("自定义查询"); |
|
|
|
dialogVisible.value = true; |
|
|
|
} |
|
|
|
editFormloading.value = false; |
|
|
|
}; |
|
|
|
const submit = async () => { |
|
|
|
if (editFormMode.value === "create" || editFormMode.value === "update") { |
|
|
@ -335,7 +506,7 @@ export default { |
|
|
|
if (valid) { |
|
|
|
editFormloading.value = true; |
|
|
|
const url = `${baseUrl}/${editFormMode.value}`; |
|
|
|
const result = await post(url, editFormModel); |
|
|
|
const result = await post(url, editFormModel.value); |
|
|
|
if (result.errors) { |
|
|
|
model.errors = result.errors; //??
|
|
|
|
} else { |
|
|
@ -345,46 +516,154 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error(error); |
|
|
|
console.log(error); |
|
|
|
} finally { |
|
|
|
editFormloading.value = false; |
|
|
|
} |
|
|
|
} else if (editFormMode.value === "details") { |
|
|
|
load(indexUrl); |
|
|
|
dialogVisible.value = false; |
|
|
|
editFormMode.value = null; |
|
|
|
} else if (editFormMode.value === "export") { |
|
|
|
const postData = JSON.parse(JSON.stringify(queryModel.value)); |
|
|
|
postData.filters = queryList.value.filter((o) => o.property && o.value); |
|
|
|
delete postData.query["items"]; |
|
|
|
delete postData.query["id"]; |
|
|
|
const url = `${baseUrl}/${editFormMode.value}?${qs.stringify(exportModel)}`; |
|
|
|
const response = await post(url, postData); |
|
|
|
download(response); |
|
|
|
dialogVisible.value = false; |
|
|
|
} else if (editFormMode.value === "import") { |
|
|
|
editFormloading.value = true; |
|
|
|
const url = `${baseUrl}/${editFormMode.value}`; |
|
|
|
const formData = new FormData(); |
|
|
|
formData.append("partial", importModel.partial); |
|
|
|
formData.append("replace", importModel.replace); |
|
|
|
formData.append("file", fileList.value[0]?.raw); |
|
|
|
console.log(uploadRef.value); |
|
|
|
const response = await post(url, formData); |
|
|
|
editFormloading.value = false; |
|
|
|
dialogVisible.value = false; |
|
|
|
await load(indexUrl); |
|
|
|
} else if (editFormMode.value === "filter") { |
|
|
|
await load(indexUrl); |
|
|
|
dialogVisible.value = false; |
|
|
|
} |
|
|
|
}; |
|
|
|
await load(indexUrl); |
|
|
|
const showList = (value, nav) => { |
|
|
|
if (!subDrawer.value) { |
|
|
|
const controller = nav.substr(0, nav.lastIndexOf(".")).toLowerCase(); |
|
|
|
const findRoute = (tree) => { |
|
|
|
for (const item of tree) { |
|
|
|
if (item.meta.controller === controller) { |
|
|
|
return item; |
|
|
|
} |
|
|
|
if (item.children) { |
|
|
|
return findRoute(item.children); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
const targetRoute = router.getRoutes().find((o) => o.meta?.controller === controller); |
|
|
|
subListQuery.value = { |
|
|
|
controller, |
|
|
|
query: { [camelCase(nav.substr(nav.lastIndexOf(".") + 1))]: value }, |
|
|
|
buttons: targetRoute.meta.buttons, |
|
|
|
}; |
|
|
|
subDrawer.value = true; |
|
|
|
} |
|
|
|
}; |
|
|
|
const pushQueryList = () => { |
|
|
|
queryList.value.push({ |
|
|
|
property: "", |
|
|
|
operator: "{0}=@0", |
|
|
|
value: "", |
|
|
|
logic: "and", |
|
|
|
}); |
|
|
|
}; |
|
|
|
const download = (response) => { |
|
|
|
const downloadUrl = window.URL.createObjectURL(response.data); |
|
|
|
const filename = response.filename; |
|
|
|
let link = document.createElement("a"); |
|
|
|
link.href = downloadUrl; |
|
|
|
link.download = filename; |
|
|
|
link.click(); |
|
|
|
window.URL.revokeObjectURL(downloadUrl); |
|
|
|
}; |
|
|
|
const getImportTemplate = async () => { |
|
|
|
const url = `${baseUrl}/${editFormMode.value}`; |
|
|
|
const response = await get(url); |
|
|
|
download(response); |
|
|
|
}; |
|
|
|
const handleChange = (uploadFile, uploadFiles) => { |
|
|
|
fileList.value = uploadFiles; |
|
|
|
}; |
|
|
|
onMounted(async () => { |
|
|
|
pushQueryList(); |
|
|
|
// if (!querySchema.value) {
|
|
|
|
// const vm = (await get(indexUrl)).data;
|
|
|
|
// querySchema.value = vm.schema.properties.query;
|
|
|
|
// tableSchema.value = vm.schema.properties.items.items;
|
|
|
|
// data.value = vm.model ?? schemaToModel(vm.schema);
|
|
|
|
// if (props.query) {
|
|
|
|
// Object.assign(data.value.query, props.query);
|
|
|
|
// }
|
|
|
|
// getSortModel(data.value);
|
|
|
|
// getColumns(vm.schema.properties.query);
|
|
|
|
// }
|
|
|
|
if (!config.value) { |
|
|
|
//
|
|
|
|
} |
|
|
|
getColumns(config.value.table.schema); |
|
|
|
queryModel.value = schemaToModel(config.value.query.schema); |
|
|
|
if (props.query) { |
|
|
|
Object.assign(queryModel.value.query, props.query); |
|
|
|
} |
|
|
|
// getSortModel(data.value);
|
|
|
|
// getColumns(vm.schema.properties.query);
|
|
|
|
await load(indexUrl); |
|
|
|
}); |
|
|
|
return { |
|
|
|
route, |
|
|
|
config, |
|
|
|
queryModel, |
|
|
|
pageModel, |
|
|
|
treeProps, |
|
|
|
tableKey, |
|
|
|
tableRef, |
|
|
|
uploadRef, |
|
|
|
tableLoading, |
|
|
|
columns, |
|
|
|
showColumn, |
|
|
|
filterDrawer, |
|
|
|
subDrawer, |
|
|
|
dialogVisible, |
|
|
|
selectedRows, |
|
|
|
schema, |
|
|
|
queryFromSchema, |
|
|
|
querySchema, |
|
|
|
queryList, |
|
|
|
tableSchema, |
|
|
|
data, |
|
|
|
sortModel, |
|
|
|
buttons, |
|
|
|
tableData, |
|
|
|
getClass, |
|
|
|
sortChange, |
|
|
|
getProp, |
|
|
|
getImportTemplate, |
|
|
|
editFormRef, |
|
|
|
editFormloading, |
|
|
|
editFormMode, |
|
|
|
editFormTitle, |
|
|
|
editFormSchema, |
|
|
|
editFormModel, |
|
|
|
exportModel, |
|
|
|
importModel, |
|
|
|
onPageSizeChange, |
|
|
|
onPageIndexChange, |
|
|
|
handleSelectionChange, |
|
|
|
load, |
|
|
|
click, |
|
|
|
submit, |
|
|
|
showList, |
|
|
|
subListQuery, |
|
|
|
pushQueryList, |
|
|
|
fileList, |
|
|
|
handleChange, |
|
|
|
}; |
|
|
|
}, |
|
|
|
}; |
|
|
|