页组件
parent
9b8af50aa9
commit
9d4b5956ad
|
|
@ -209,6 +209,10 @@ const displayData = computed(() => {
|
|||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.drop-table {
|
||||
width 100%;
|
||||
}
|
||||
|
||||
.clear-btn {
|
||||
cursor: pointer;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-wrapper">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.page-wrapper {
|
||||
height 100%
|
||||
width 100%;
|
||||
overflow hidden
|
||||
padding 0 5px 5px 5px
|
||||
contain: layout paint;
|
||||
transform: translateZ(0);
|
||||
box-sizing border-box
|
||||
display grid
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
/* @jsxImportSource vue */
|
||||
import APage from '@/components/a-page/APage.vue'
|
||||
import styles from '@/components/a-page/a-table-page/a-table-page.module.styl'
|
||||
import {
|
||||
ElButton,
|
||||
ElDropdown,
|
||||
ElDropdownItem,
|
||||
ElDropdownMenu,
|
||||
ElForm,
|
||||
ElLoading,
|
||||
ElPagination,
|
||||
ElPopconfirm,
|
||||
ElScrollbar,
|
||||
ElTable,
|
||||
ElTableColumn,
|
||||
ElTooltip,
|
||||
type TableColumnCtx,
|
||||
type TableProps,
|
||||
} from 'element-plus'
|
||||
import {
|
||||
defineComponent,
|
||||
withDirectives,
|
||||
withModifiers,
|
||||
} from 'vue'
|
||||
import type { R } from '@/common/utils/http-util.ts'
|
||||
import {
|
||||
elIcons,
|
||||
type ElIconType,
|
||||
} from '@/common/element/element.ts'
|
||||
import type { DefaultRow } from 'element-plus/es/components/table/src/table/defaults'
|
||||
import type { FormProps } from 'element-plus/es/components/form/src/form'
|
||||
import Utils, { type ResetAble } from '@/common/utils'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import { saveFile } from '@/common/app'
|
||||
import Colls from '@/common/utils/colls.ts'
|
||||
import type { SetupContext } from '@vue/runtime-core'
|
||||
|
||||
interface ColumnScopeType<T> {
|
||||
row: T,
|
||||
column: TableColumnCtx,
|
||||
$index: number
|
||||
}
|
||||
|
||||
export interface TableActionType<T> {
|
||||
icon?: ElIconType
|
||||
type?: 'text' | 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
|
||||
label?: string | ((data: ColumnScopeType<T>) => string)
|
||||
tooltip?: string | ((data: ColumnScopeType<T>) => string)
|
||||
loading?: boolean
|
||||
textBtn?: boolean
|
||||
show?: (data: ColumnScopeType<T>) => boolean
|
||||
action: (data: ColumnScopeType<T>) => Promise<boolean> | void
|
||||
confirm?: {
|
||||
title: string | ((data: ColumnScopeType<T>) => string)
|
||||
width?: string
|
||||
confirmButtonText?: string
|
||||
cancelButtonText?: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ActionColumnType<T> {
|
||||
width?: string
|
||||
tableActions: TableActionType<T>[]
|
||||
}
|
||||
|
||||
export interface ToolType {
|
||||
icon?: ElIconType
|
||||
type?: 'text' | 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
|
||||
label?: string
|
||||
action: () => void
|
||||
}
|
||||
|
||||
export interface ToolBarType {
|
||||
leftTools: ToolType[]
|
||||
rightTools: Required<Omit<ToolType, 'type' | 'label'>>[]
|
||||
}
|
||||
|
||||
export type TablePropsType<T extends DefaultRow, F extends object> = Omit<TableProps<T>, 'data' | 'headerRowClassName' | 'cellClassName' | 'context'> & {
|
||||
treeLoad?: (param: F, row: T, expanded: any, resolve?: (data: T[]) => void) => void
|
||||
actionColumn: ActionColumnType<T>
|
||||
}
|
||||
export type FormPropsType<P, T> = {
|
||||
paging?: (param: P) => Promise<R<G.PageResult<T>>>
|
||||
export?: (param: P) => Promise<R<{ content: Blob, filename: string }>>
|
||||
defaultData: P
|
||||
highForm?: Partial<FormProps> & { colCount?: number, vgap?: string, hgap?: string }
|
||||
simpleForm?: Partial<FormProps>
|
||||
}
|
||||
|
||||
interface PageLayoutType {
|
||||
/* columns: string[]
|
||||
rows: string[] */
|
||||
dataListHeight: string
|
||||
}
|
||||
|
||||
export interface ATablePageType<P extends object, T extends DefaultRow> {
|
||||
pageLayout: PageLayoutType
|
||||
searchForm: FormPropsType<P, T>
|
||||
toolBar: ToolBarType
|
||||
table: TablePropsType<T, P>
|
||||
}
|
||||
|
||||
function buildSearchForm<P, T>(searchForm: Partial<FormPropsType<P, T>> = {}) {
|
||||
if (searchForm.defaultData == null) {
|
||||
searchForm.defaultData = {} as P
|
||||
}
|
||||
return searchForm
|
||||
}
|
||||
|
||||
|
||||
function buildPageLayout(pageLayout: Partial<PageLayoutType> = {}) {
|
||||
/* if (pageLayout.columns == null) {
|
||||
pageLayout.columns = [ '1fr' ]
|
||||
}
|
||||
|
||||
if (pageLayout.rows == null) {
|
||||
pageLayout.rows = [ '1fr', '9fr' ]
|
||||
} */
|
||||
if (pageLayout.dataListHeight == null) {
|
||||
pageLayout.dataListHeight = '9fr'
|
||||
}
|
||||
|
||||
return pageLayout
|
||||
}
|
||||
|
||||
function buildTable<P extends object, T extends DefaultRow>(table: Partial<TablePropsType<T, P>> = {}) {
|
||||
if (table.actionColumn == null) {
|
||||
table.actionColumn = {
|
||||
tableActions: [],
|
||||
}
|
||||
}
|
||||
if (table.actionColumn.tableActions == null) {
|
||||
table.actionColumn.tableActions = []
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
function buildToolBar(toolBar: Partial<ToolBarType> = {}) {
|
||||
if (toolBar.leftTools == null) toolBar.leftTools = []
|
||||
if (toolBar.rightTools == null) toolBar.rightTools = []
|
||||
|
||||
return toolBar
|
||||
}
|
||||
|
||||
export interface PropsTplType<P extends G.PageParam, T extends DefaultRow> {
|
||||
pageLayout?: Partial<PageLayoutType>
|
||||
searchForm?: Partial<FormPropsType<P, T>>
|
||||
toolBar?: Partial<ToolBarType>
|
||||
table?: Partial<TablePropsType<T, P>>
|
||||
}
|
||||
|
||||
export function buildProps<P extends G.PageParam, T extends DefaultRow>({pageLayout, searchForm, toolBar, table}: PropsTplType<P, T>) {
|
||||
return reactive({
|
||||
pageLayout: buildPageLayout(pageLayout),
|
||||
searchForm: buildSearchForm(searchForm),
|
||||
toolBar: buildToolBar(toolBar),
|
||||
table: buildTable(table),
|
||||
})
|
||||
}
|
||||
|
||||
interface Exposed extends Record<string, any> {
|
||||
doSearch: () => void
|
||||
}
|
||||
|
||||
const component = defineComponent(
|
||||
<P extends G.PageParam, T extends DefaultRow>(props: ATablePageType<P, T>, {slots, expose}: SetupContext) => {
|
||||
const formData = Utils.resetAble(reactive<P>({
|
||||
...(props.searchForm.defaultData),
|
||||
current: 1,
|
||||
size: 20,
|
||||
})) as ResetAble<P>
|
||||
const tableData = Utils.resetAble(reactive<T[]>([])) as ResetAble<T[]>
|
||||
|
||||
const totalCount = ref(0)
|
||||
const loading = ref<boolean>(false)
|
||||
const showHighForm = ref<boolean>(true)
|
||||
|
||||
const doSearch = () => {
|
||||
loading.value = true
|
||||
if (props.searchForm.paging != null) {
|
||||
props.searchForm.paging(formData.$clone() as P)
|
||||
.then(res => {
|
||||
totalCount.value = res.data?.total ?? 0
|
||||
const records = res.data?.records ?? ([] as T[])
|
||||
tableData.$reset(records)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
expose({doSearch})
|
||||
const showHighFormHandle = () => {
|
||||
showHighForm.value = !showHighForm.value
|
||||
formData.$reset()
|
||||
}
|
||||
const doExport = () => {
|
||||
if (props?.searchForm?.export == null) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
saveFile(props?.searchForm?.export(formData.$clone() as P))
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
const rowAction = (data: ColumnScopeType<T>, action: TableActionType<T>) => {
|
||||
if (action.loading != null) {
|
||||
action.loading = true
|
||||
}
|
||||
const result = action.action(data)
|
||||
if (result instanceof Promise) {
|
||||
result
|
||||
.then(reload => {
|
||||
if (reload) {
|
||||
doSearch()
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (action.loading != null) {
|
||||
action.loading = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function doReset() {
|
||||
formData.$reset()
|
||||
doSearch()
|
||||
}
|
||||
|
||||
const highFormCssParam = computed(() => {
|
||||
return {
|
||||
'--col-count': props.searchForm.highForm?.colCount ?? 3,
|
||||
'--vgap': props.searchForm.highForm?.vgap ?? '0',
|
||||
'--hgap': props.searchForm.highForm?.hgap ?? '0',
|
||||
}
|
||||
})
|
||||
|
||||
const pageCssParam = computed(() => {
|
||||
return {
|
||||
'--data-list-height': props.pageLayout.dataListHeight,
|
||||
}
|
||||
})
|
||||
const actionColumnBtnRender = (scope: ColumnScopeType<T>, tableAction: TableActionType<T>) => {
|
||||
const Btn = <ElButton
|
||||
icon={tableAction.icon == null ? undefined : elIcons[tableAction.icon]}
|
||||
loading={tableAction.loading}
|
||||
type={tableAction.type}
|
||||
class={tableAction.textBtn ? 'text-btn' : 'icon-btn'}
|
||||
text>
|
||||
{tableAction.label}
|
||||
</ElButton>
|
||||
const tooltipTxt = tableAction.tooltip == null ? '' : (typeof tableAction.tooltip === 'function' ? tableAction.tooltip(scope) : tableAction.tooltip)
|
||||
if (Strings.isBlank(tooltipTxt)) {
|
||||
return (<ElTooltip content={tooltipTxt} placement="top">
|
||||
{{
|
||||
default: () => Btn,
|
||||
}}
|
||||
</ElTooltip>)
|
||||
}
|
||||
return Btn
|
||||
}
|
||||
const actionColumnRender = () => {
|
||||
const actionColumn = props.table?.actionColumn
|
||||
return Colls.isEmpty(actionColumn?.tableActions) ? <></>
|
||||
: (<ElTableColumn width={actionColumn?.width ?? '180'} fixed="right" label="操作">
|
||||
<div class="action-btn">
|
||||
{{
|
||||
default: (scope: ColumnScopeType<T>) => (actionColumn?.tableActions!
|
||||
.filter(it => (it.show == null ? true : it.show(scope)))
|
||||
.map((tableAction, i) => (tableAction.confirm != null ?
|
||||
(<ElPopconfirm
|
||||
key={'action-btn-' + i}
|
||||
cancel-button-text={tableAction.confirm.cancelButtonText ?? '否'}
|
||||
confirm-button-text={tableAction.confirm.confirmButtonText ?? '是'}
|
||||
title={typeof tableAction.confirm.title === 'function' ? tableAction.confirm.title(scope) : tableAction.confirm.title}
|
||||
width={tableAction.confirm.width ?? '180'}
|
||||
cancel-button-type="primary"
|
||||
confirm-button-type="danger"
|
||||
onConfirm={() => rowAction(scope, tableAction)}>
|
||||
{{
|
||||
reference: () => (actionColumnBtnRender(scope, tableAction)),
|
||||
}}
|
||||
</ElPopconfirm>) : actionColumnBtnRender(scope, tableAction)))
|
||||
),
|
||||
}}
|
||||
</div>
|
||||
</ElTableColumn>)
|
||||
}
|
||||
onMounted(doSearch)
|
||||
return () => (<APage class={[ styles.tablePage, showHighForm.value ? '' : styles.folder ]} style={pageCssParam.value}>
|
||||
{/*@ts-ignore*/}
|
||||
<div class={styles.searchFormWrapper} style={highFormCssParam.value}>
|
||||
<ElScrollbar>
|
||||
{/*@ts-ignore*/}
|
||||
<ElForm class={styles.searchForm} onSubmit={withModifiers(doSearch, [ 'prevent' ])} labelWidth={props.searchForm.highForm?.labelWidth ?? '90px'}>
|
||||
{
|
||||
slots.highFormItem?.(formData)
|
||||
}
|
||||
<button style="display: none" type="submit"/>
|
||||
</ElForm>
|
||||
</ElScrollbar>
|
||||
</div>
|
||||
<div class={styles.dataList}>
|
||||
<div class={styles.toolBar}>
|
||||
<div class={styles.toolBarLeft}>
|
||||
{
|
||||
props.toolBar?.leftTools?.map((tool, i) => (
|
||||
<ElButton key={'tool-bar-left-' + i}
|
||||
icon={Strings.isBlank(tool.icon) ? undefined : elIcons[tool.icon!]}
|
||||
type={tool.type ?? 'primary'}
|
||||
onClick={tool.action}>
|
||||
{tool.label}
|
||||
</ElButton>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div class={styles.toolBarRight}>
|
||||
{/*@ts-ignore*/}
|
||||
<ElForm onSubmit={withModifiers(doSearch, [ 'prevent' ])}>
|
||||
{
|
||||
slots.simpleFormItem?.(formData)
|
||||
}
|
||||
<button style="display: none" type="submit"/>
|
||||
</ElForm>
|
||||
<ElTooltip content="搜索" placement="top">
|
||||
<ElDropdown split-button onClick={doSearch} onCommand={(command: string) => {
|
||||
if (command === 'reset') {
|
||||
doReset()
|
||||
}
|
||||
}}>
|
||||
{{
|
||||
default: () => (<ElButton icon={elIcons.Search} loading={loading.value} type="default"/>),
|
||||
dropdown: () => (<ElDropdownMenu>
|
||||
<ElDropdownItem icon={elIcons.Refresh} command="reset">重置并刷新</ElDropdownItem>
|
||||
</ElDropdownMenu>),
|
||||
}}
|
||||
</ElDropdown>
|
||||
</ElTooltip>
|
||||
{
|
||||
props.toolBar?.rightTools?.map((tool, i) => (
|
||||
<ElButton key={'tool-bar-right-' + i}
|
||||
icon={elIcons[tool.icon]}
|
||||
onClick={tool.action}/>
|
||||
))
|
||||
}
|
||||
<ElTooltip content="导出" placement="top">
|
||||
<ElButton icon={elIcons.Download} loading={loading.value} type="default" onClick={doExport}/>
|
||||
</ElTooltip>
|
||||
<ElTooltip content={showHighForm.value ? '关闭高级搜索' : '打开高级搜索'} placement="top">
|
||||
<ElButton class={showHighForm.value ? styles.filterBtnActive : ''} icon={elIcons.Filter} type="default" onClick={showHighFormHandle}/>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
withDirectives(<ElTable
|
||||
data={tableData}
|
||||
empty-text={props.table?.emptyText ?? '暂无数据'}
|
||||
row-key={props.table?.rowKey ?? 'id'}
|
||||
ref="dataTable"
|
||||
lazy={props.table?.treeLoad == null ? undefined : true}
|
||||
load={props.table?.treeLoad ? ((row, expanded, resolve) => props.table?.treeLoad!(formData as P, row, expanded, resolve)) : undefined}
|
||||
onExpand-change={props.table?.treeLoad ? ((row: any, expandedRows: any) => props.table?.treeLoad!(formData as P, row, expandedRows, undefined)) : undefined}
|
||||
cell-class-name="table-cell"
|
||||
header-row-class-name="table-header"
|
||||
>
|
||||
{
|
||||
slots.columns?.()
|
||||
}
|
||||
{
|
||||
actionColumnRender()
|
||||
}
|
||||
</ElTable>, [ [ ElLoading.directive, loading.value ] ])
|
||||
}
|
||||
<ElPagination
|
||||
current-page={(formData as G.PageParam).current}
|
||||
page-size={(formData as G.PageParam).size}
|
||||
onUpdate:current-page={(val) => (formData as G.PageParam).current = val}
|
||||
onUpdate:page-size={(val) => (formData as G.PageParam).size = val}
|
||||
hide-on-single-page={false}
|
||||
page-sizes={[ 10, 20, 50, 100, 500 ]}
|
||||
teleported={false}
|
||||
total={totalCount.value}
|
||||
background={true}
|
||||
layout="total, prev, pager, next, sizes, jumper"
|
||||
onChange={doSearch}/>
|
||||
{
|
||||
slots?.default?.()
|
||||
}
|
||||
</div>
|
||||
</APage>)
|
||||
},
|
||||
{
|
||||
name: 'ATablePage',
|
||||
props: [ 'pageLayout', 'searchForm', 'toolBar', 'table' ],
|
||||
},
|
||||
)
|
||||
|
||||
export interface ATablePageInstance extends InstanceType<typeof component>, Exposed {
|
||||
}
|
||||
|
||||
export default component
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export {}
|
||||
declare global {
|
||||
interface ATablePageInstance extends InstanceType<typeof ATablePage>, ATablePageExposed {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
.table-page {
|
||||
grid-template-columns 1fr
|
||||
grid-template-rows: minmax(0, 1fr) minmax(0, var(--data-list-height));
|
||||
grid-auto-rows: minmax(0, auto);
|
||||
gap 10px
|
||||
|
||||
&.folder {
|
||||
grid-template-rows: 0 minmax(0, 3fr);
|
||||
gap: 0;
|
||||
|
||||
.search-form {
|
||||
padding 0
|
||||
border-width 0
|
||||
height 0
|
||||
}
|
||||
}
|
||||
|
||||
.search-form-wrapper {
|
||||
border: 1px solid #EAEBF1;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
background-color: white;
|
||||
height 100%
|
||||
width 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
& {
|
||||
|
||||
}
|
||||
|
||||
& > div {
|
||||
max-height 168px
|
||||
width 100%;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display grid
|
||||
grid-template-columns repeat(var(--col-count), 1fr)
|
||||
row-gap var(--vgap);
|
||||
column-gap var(--hgap);
|
||||
|
||||
:global(.el-form-item) {
|
||||
margin 0
|
||||
}
|
||||
|
||||
:global(.el-form-item).form-action-btn {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
.el-form-item__content {
|
||||
justify-content end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.data-list {
|
||||
box-sizing: border-box;
|
||||
display grid
|
||||
grid-template-columns 1fr
|
||||
grid-template-rows 50px minmax(0, 1fr) 50px
|
||||
border: 1px solid #EAEBF1;
|
||||
padding: 15px 20px 20px 15px;
|
||||
border-radius: 8px;
|
||||
background-color: white;
|
||||
height 100%
|
||||
width 100%;
|
||||
gap 20px
|
||||
|
||||
.tool-bar {
|
||||
display flex
|
||||
justify-content space-between
|
||||
box-sizing: border-box;
|
||||
|
||||
.tool-bar-left {
|
||||
flex 1
|
||||
}
|
||||
|
||||
.tool-bar-right {
|
||||
flex 1
|
||||
display flex
|
||||
gap 10px
|
||||
justify-content end
|
||||
|
||||
:global(.el-form) {
|
||||
display flex
|
||||
gap 10px
|
||||
flex-shrink 0
|
||||
|
||||
.el-form-item {
|
||||
margin: 0;
|
||||
flex 1
|
||||
}
|
||||
}
|
||||
|
||||
:global(.el-button--default) {
|
||||
width 32px
|
||||
color #4D5875
|
||||
background-color #F1F4F4
|
||||
border-color #F1F4F4
|
||||
margin 0
|
||||
|
||||
&:hover {
|
||||
color var(--main-color)
|
||||
background-color #E6EAEB;
|
||||
border-color #E6EAEB;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:global(.el-dropdown) {
|
||||
flex-shrink 0
|
||||
}
|
||||
|
||||
:global(.el-button--default).filter-btn-active {
|
||||
color var(--main-color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.el-table) {
|
||||
width 100%
|
||||
height: 100%;
|
||||
|
||||
:global(.table-header) {
|
||||
color #454C59
|
||||
|
||||
th {
|
||||
background-color #EDF1F7
|
||||
font-weight 500
|
||||
position relative
|
||||
|
||||
& > div {
|
||||
display flex
|
||||
gap 5px
|
||||
align-items center
|
||||
}
|
||||
|
||||
&:not(:first-child) > div::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1px;
|
||||
width: 1px;
|
||||
background-color: #D3D7DE;
|
||||
transform: translateY(-50%);
|
||||
content: "";
|
||||
height 50%
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.table-cell) {
|
||||
color #2F3540
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width 100%
|
||||
display flex
|
||||
flex-wrap wrap
|
||||
gap: 10px;
|
||||
|
||||
.text-btn {
|
||||
margin 0
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
margin 0
|
||||
padding: 8px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
//#ebf0ff
|
||||
}
|
||||
|
||||
:global(.el-button--default).icon-btn {
|
||||
color oklch(72% .19 231.6)
|
||||
background-color oklch(0.96 0.03 224.26)
|
||||
border-color oklch(0.96 0.03 224.26)
|
||||
}
|
||||
|
||||
:global(.el-button--danger).icon-btn {
|
||||
color oklch(73% .15 25.3)
|
||||
background-color oklch(0.96 0.02 22.09)
|
||||
border-color oklch(0.96 0.02 22.09)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.el-pagination) {
|
||||
justify-content center
|
||||
|
||||
:global(.btn-next),
|
||||
:global(.btn-prev),
|
||||
:global(.el-pager) li {
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<script generic="F extends object,TT extends DefaultRow" lang="ts" setup>
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
import Page from '@/components/page/Page.vue'
|
||||
import APage from '@/components/a-page/APage.vue'
|
||||
import Utils, { type ResetAble } from '@/common/utils'
|
||||
import Colls from '@/common/utils/colls.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
|
|
@ -153,7 +153,7 @@ onMounted(doSearch)
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Page class="form-page">
|
||||
<APage class="form-page">
|
||||
<div v-show="showSearchForm" class="search-form">
|
||||
<ElScrollbar>
|
||||
<ElForm :class="{'border-form':formStyle.border}" v-bind="searchFormProps" @submit.prevent="doSearch">
|
||||
|
|
@ -334,7 +334,7 @@ onMounted(doSearch)
|
|||
@change="doSearch"/>
|
||||
</div>
|
||||
<slot/>
|
||||
</Page>
|
||||
</APage>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue').EffectScope
|
||||
const ElLoading: typeof import('element-plus/es').ElLoading
|
||||
const ElMessage: typeof import('element-plus/es').ElMessage
|
||||
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
|
||||
const computed: typeof import('vue').computed
|
||||
|
|
|
|||
|
|
@ -1,30 +1,27 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:default-search-form="{createTimes:[undefined,undefined]}"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{ searchForm }">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #highFormItem="formData">
|
||||
<ElFormItem label="产品分类">
|
||||
<GoodsCategoryDropTable v-model="searchForm.goodsCategoryId"/>
|
||||
<GoodsCategoryDropTable v-model="formData.goodsCategoryId"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="产品编码">
|
||||
<ElInput v-model="searchForm.sn" placeholder="产品编码"/>
|
||||
<ElInput v-model="formData.sn" placeholder="产品编码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="产品名称">
|
||||
<ElInput v-model="searchForm.goodsName" placeholder="产品名称"/>
|
||||
<ElInput v-model="formData.goodsName" placeholder="产品名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="创建时间">
|
||||
<ADtPicker v-model="searchForm.createTimes" :change-handler="research"/>
|
||||
<ADtPicker v-model="formData.createTimes" :change-handler="research"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #simpleSearchFormItem="{ searchForm }">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput v-model="searchForm.sn" placeholder="产品编码"/>
|
||||
<ElInput v-model="formData.sn" placeholder="产品编码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElInput v-model="searchForm.goodsName" placeholder="产品名称"/>
|
||||
<ElInput v-model="formData.goodsName" placeholder="产品名称"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
|
|
@ -46,26 +43,55 @@
|
|||
<ElTableColumn label="创建时间" prop="createTime" width="160"/>
|
||||
</template>
|
||||
<GoodsForm ref="goodsForm" :research="research"/>
|
||||
</FormPage>
|
||||
</ATablePage>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import GoodsApi from '@/pages/gds/goods/goods-api.ts'
|
||||
import GoodsForm from '@/pages/gds/goods/GoodsForm.vue'
|
||||
import AppApi from '@/common/app/app-api.ts'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import ADtPicker from '@/components/a-dt-picker/ADtPicker.vue'
|
||||
import GoodsCategoryDropTable from '@/pages/gds/goods-category/GoodsCategoryDropTable.vue'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const goodsFormIns = useTemplateRef<InstanceType<typeof GoodsForm>>('goodsForm')
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<GoodsTypes.SearchGoodsResult>>({
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
|
||||
function research() {
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
const tablePageProps = buildProps({
|
||||
searchForm: {
|
||||
defaultData: {createTimes: [ undefined, undefined ]},
|
||||
highForm: {
|
||||
colCount: 4,
|
||||
},
|
||||
paging(param: GoodsTypes.SearchGoodsParam) {
|
||||
return GoodsApi.paging({
|
||||
...param,
|
||||
createTimeStart: param.createTimes[0],
|
||||
createTimeEnd: param.createTimes[1],
|
||||
})
|
||||
},
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
goodsFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
|
|
@ -91,28 +117,10 @@ const actionColumn = reactive<ActionColumnType<GoodsTypes.SearchGoodsResult>>({
|
|||
},
|
||||
},
|
||||
],
|
||||
} as ActionColumnType<GoodsTypes.SearchGoodsResult>)
|
||||
const leftTools: ToolType[] = [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
goodsFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function paging(param: GoodsTypes.SearchGoodsParam) {
|
||||
return GoodsApi.paging({
|
||||
...param,
|
||||
createTimeStart: param.createTimes[0],
|
||||
createTimeEnd: param.createTimes[1],
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function enableGoodsHandler(enable: boolean, id: string) {
|
||||
GoodsApi.enable({enable, id})
|
||||
|
|
|
|||
|
|
@ -1,53 +1,46 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:form-style="{
|
||||
border: false,
|
||||
colCount: 3,
|
||||
vgap: '20px',
|
||||
hgap: '20px',
|
||||
}"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{searchForm}">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #highFormItem="formData">
|
||||
<ElFormItem label="站点">
|
||||
<ElInput v-model="searchForm.stationId" placeholder="站点"/>
|
||||
<ElInput v-model="formData.stationId" placeholder="站点"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="订单编号">
|
||||
<ElInput v-model="searchForm.sn" placeholder="订单编号"/>
|
||||
<ElInput v-model="formData.sn" placeholder="订单编号"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="项目名称">
|
||||
<ElInput v-model="searchForm.projectName" placeholder="项目名称"/>
|
||||
<ElInput v-model="formData.projectName" placeholder="项目名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="客户姓名">
|
||||
<ElInput v-model="searchForm.contacts" placeholder="客户姓名"/>
|
||||
<ElInput v-model="formData.contacts" placeholder="客户姓名"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="联系方式">
|
||||
<ElInput v-model="searchForm.phone" placeholder="联系方式"/>
|
||||
<ElInput v-model="formData.phone" placeholder="联系方式"/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="订单类型">
|
||||
<ElInput v-model="searchForm.orderCategory" placeholder="订单类型"/>
|
||||
<ElInput v-model="formData.orderCategory" placeholder="订单类型"/>
|
||||
</ElFormItem>
|
||||
<!-- <ElFormItem label="订单状态">
|
||||
<ElInput v-model="searchForm.orderStatus" placeholder="订单状态"/>
|
||||
<ElInput v-model="formData.orderStatus" placeholder="订单状态"/>
|
||||
</ElFormItem> -->
|
||||
<ElFormItem label="运输企业">
|
||||
<ElInput v-model="searchForm.transOrgName" placeholder="运输企业"/>
|
||||
<ElInput v-model="formData.transOrgName" placeholder="运输企业"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="下单时间">
|
||||
<ADtPicker v-model="searchForm.orderTimes" :change-handler="research"/>
|
||||
<ADtPicker v-model="formData.orderTimes" :change-handler="research"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="完结时间">
|
||||
<ADtPicker v-model="searchForm.finishTimes" :change-handler="research"/>
|
||||
<ADtPicker v-model="formData.finishTimes" :change-handler="research"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #simpleSearchFormItem="{searchForm}">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput v-model="searchForm.sn" placeholder="订单编号"/>
|
||||
<ElInput v-model="formData.sn" placeholder="订单编号"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElInput v-model="searchForm.orderCategory" placeholder="订单类型"/>
|
||||
<ElInput v-model="formData.orderCategory" placeholder="订单类型"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
|
|
@ -86,53 +79,49 @@
|
|||
<!-- <ElTableColumn label="客户备注" prop="customerMemo"/> -->
|
||||
</template>
|
||||
<OrderForm ref="orderForm" :research="research"/>
|
||||
</FormPage>
|
||||
</ATablePage>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import OrderApi from '@/pages/order/order-api.ts'
|
||||
import OrderForm from '@/pages/order/book/BookForm.vue'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import ADtPicker from '@/components/a-dt-picker/ADtPicker.vue'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import type { ActionColumnType } from '@/components/page/a-page-type.ts'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<OrderTypes.SearchOrderResult>>({
|
||||
function research() {
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
const tablePageProps = buildProps({
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '详情',
|
||||
icon: 'Postcard',
|
||||
action({row}) {
|
||||
action() {
|
||||
},
|
||||
},
|
||||
/* {
|
||||
icon: 'Delete',
|
||||
loading: false,
|
||||
type: 'danger',
|
||||
tooltip: '删除',
|
||||
confirm: {
|
||||
title: '是否删除当前数据',
|
||||
},
|
||||
action({row}) {
|
||||
OrgApi.del([ row.id! ])
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
return true
|
||||
})
|
||||
},
|
||||
}, */
|
||||
],
|
||||
},
|
||||
},
|
||||
searchForm: {
|
||||
paging(param: OrderTypes.SearchOrderParam) {
|
||||
return OrderApi.paging(param).then(res => {
|
||||
res.data.records = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
res.data.records.push({})
|
||||
}
|
||||
return res
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function paging(param: OrderTypes.SearchOrderParam) {
|
||||
return OrderApi.paging(param)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<Page>
|
||||
<APage>
|
||||
<div class="dict-page">
|
||||
<DictCategory @search-dict="searchDict"/>
|
||||
<ElDivider direction="vertical"/>
|
||||
<DictItem ref="dictItem"/>
|
||||
</div>
|
||||
</Page>
|
||||
</APage>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Page from '@/components/page/Page.vue'
|
||||
import APage from '@/components/a-page/APage.vue'
|
||||
import DictCategory from '@/pages/sys/dict/DictCategory.vue'
|
||||
import DictItem from '@/pages/sys/dict/DictItem.vue'
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue