订单管理

master
lzq 2026-01-28 18:23:13 +08:00
parent 771c2dff8f
commit 1005fcc79b
25 changed files with 1768 additions and 1399 deletions

1573
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
.el-dialog {
border var(--border-base) !important
border 2px solid var(--el-border-color-light) !important
}
.el-dialog__body {
@ -19,12 +19,15 @@
justify-content: center !important
align-items: center !important
box-sizing border-box !important
width 100% !important;
}
.el-dialog {
//height 90% !important
max-height 90% !important
max-width 90% !important;
margin 0 !important
box-sizing border-box !important
overflow: hidden;
}
.draggable-dialog > .el-dialog__header > .el-dialog__title {
@ -36,5 +39,10 @@
.el-dialog__body {
height calc(100% - 88px) !important
box-sizing border-box !important
& > .el-scrollbar > .el-scrollbar__wrap {
max-height calc(100vh - 400px)
height unset
}
}
}

View File

@ -4,6 +4,7 @@
@import "dropdown-menu.styl"
@import "select-dropdown.styl"
@import "dialog.styl"
@import "table.styl"
// Element Plus
// -------------------------------- el-size=default start --------------------------------

View File

@ -0,0 +1,78 @@
.data-table.el-table {
width 100% !important
height 100% !important;
.table-header {
color #454C59 !important
th {
background-color #EDF1F7 !important
font-weight 500 !important
position relative
& > div {
display flex !important
gap 5px !important
align-items center !important
}
&:not(:first-child) > div::before {
position: absolute !important
top 50% !important
left 1px !important
width 1px !important
background-color #D3D7DE !important
transform translateY(-50%) !important
content "" !important
height 50% !important
}
}
}
.table-cell {
color #2F3540 !important
}
.action-btn {
width 100% !important
display grid !important
grid-template-columns repeat(auto-fit, 32px) !important
grid-auto-rows: 32px !important
gap: 10px !important
.text-btn {
margin 0 !important
}
.icon-btn {
margin 0 !important
padding: 8px !important
justify-content center !important
align-items center !important
}
.el-button--default.icon-btn {
color #7987A1 !important
background-color #F2F4F5 !important
border-color #F2F4F5 !important
}
.el-button--info.icon-btn {
color #5D87FF !important
background-color #EBF0FF !important
border-color #EBF0FF !important
}
.el-button--primary.icon-btn {
color oklch(72% .19 231.6) !important
background-color oklch(0.96 0.03 224.26) !important
border-color oklch(0.96 0.03 224.26) !important
}
.el-button--danger.icon-btn {
color oklch(73% .15 25.3) !important
background-color oklch(0.96 0.02 22.09) !important
border-color oklch(0.96 0.02 22.09) !important
}
}
}

View File

@ -0,0 +1,86 @@
import {
defineComponent,
withDirectives,
} from 'vue'
import type { SetupContext } from '@vue/runtime-core'
import type { R } from '@/common/utils/http-util.ts'
import Utils from '@/common/utils'
import ADialog from '@/components/a-dialog/ADialog.vue'
import {
ElButton,
ElLoading,
} from 'element-plus'
import styles from '@/components/a-detail-panel/a-detail-panel.module.styl'
interface ADetailPanelType<D extends object> {
title: string
width: string
detailsLoader: (id: string) => Promise<R<D> | undefined | null | void>
}
const component = defineComponent(
<T extends object & { id?: string }, D extends object>(props: ADetailPanelType<D>, {slots, expose}: SetupContext) => {
const showDialog = ref(false)
const loading = ref(false)
const detailData = Utils.resetAble(reactive<D>({} as D))
const dialogCloseHandler = () => {
detailData.$reset()
}
const open = (data: T) => {
showDialog.value = true
loading.value = true
props.detailsLoader(data.id!)
.then(res => {
detailData.$reset((res?.data ?? {}) as any)
})
.finally(() => {
loading.value = false
})
}
expose({open})
return () => (
<ADialog
width={props.width}
show={showDialog.value}
onUpdate:show={show => showDialog.value = show}
closed={dialogCloseHandler}
title={props.title}>
{{
default: () => (withDirectives(
<div class={[ styles.detailPanel, 'detail-panel-wrapper' ]}>
{slots.default!(detailData as D)}
</div>,
[ [ ElLoading.directive, loading.value ] ],
)),
footer: () => (<div>
{
slots.footer?.(detailData as D)
}
<ElButton onClick={() => showDialog.value = false}></ElButton>
</div>),
}}
</ADialog>
)
},
{
name: 'ADetailPanel',
props: [ 'title', 'width', 'detailsLoader' ],
},
)
export interface ADetailPanelInstance<T extends object & { id?: string }> extends InstanceType<typeof component> {
open: (data: T) => void
}
export function buildDetailPanelProps<D extends object>({title, width, detailsLoader}: DeepPartial<ADetailPanelType<D>>) {
return reactive({
title: title ?? '详情',
width: width ?? 'fit-content',
detailsLoader: detailsLoader ?? (() => Promise.resolve()),
} as ADetailPanelType<D>)
}
export default component

View File

@ -0,0 +1,6 @@
.detail-panel {
box-sizing border-box
display grid
gap 20px
grid-template-columns 1fr
}

View File

@ -5,12 +5,8 @@ import useMove from '@/common/utils/use-move.ts'
const props = withDefaults(defineProps<{
show: boolean
title: string
closeOnSuccess?: boolean
width?: string
closeBtnText?: string
submitBtnText?: string
closed?: () => void
submitHandler: () => Promise<any>
}>(), {
width: 'fit-content',
closeOnSuccess: true,
@ -22,19 +18,6 @@ const props = withDefaults(defineProps<{
const emits = defineEmits([ 'update:show' ])
function submit() {
submiting.value = true
props.submitHandler()
.then(() => {
if (props.closeOnSuccess) {
showDialog.value = false
}
})
.finally(() => {
submiting.value = false
})
}
const id = nanoid()
const modalClass = 'draggable-dialog-modal-' + id
@ -44,7 +27,6 @@ const showDialog = computed({
emits('update:show', val)
},
})
const submiting = ref(false)
const enableRender = ref(false)
let moveHandle = useMove(id)
@ -99,8 +81,7 @@ onUnmounted(() => {
<slot/>
</ElScrollbar>
<template #footer>
<ElButton @click="showDialog = false">{{ closeBtnText }}</ElButton>
<ElButton :loading="submiting" type="primary" @click="submit">{{ submitBtnText }}</ElButton>
<slot name="footer"/>
</template>
</ElDialog>
</template>

View File

@ -32,14 +32,20 @@ function dialogCloseHandler() {
formData.$reset()
}
const submiting = ref(false)
function submitHandler() {
return FormUtil.submit(formIns, () => props.doSubmit(formData.$clone() as T))
submiting.value = true
FormUtil.submit(formIns, () => props.doSubmit(formData.$clone() as T))
.then(res => {
ElMessage.success('提交成功')
if ((res ?? true)) {
showDialog.value = false
}
})
.finally(() => {
submiting.value = false
})
}
defineExpose({
@ -72,6 +78,10 @@ defineExpose({
class="form-panel">
<slot :formData="formData as T"/>
</ElForm>
<template #footer>
<ElButton @click="showDialog = false">关闭</ElButton>
<ElButton :loading="submiting" type="primary" @click="submitHandler"></ElButton>
</template>
</ADialog>
</template>

View File

@ -18,7 +18,3 @@ const icon = computed(() => {
<template>
<i :class="icon" v-bind="$attrs"/>
</template>
<style lang="stylus" scoped>
</style>

View File

@ -760,11 +760,12 @@ export const icons = {
'font_class': 'shenheguanli',
'unicode': 'e639',
'unicode_decimal': 58937,
}
]
},
],
} as const
export type IconName = (typeof icons.glyphs)[number]['font_class']
export const iconNames = icons.glyphs.map(it => it.font_class)
export interface IconGlyphs {
icon_id: string

View File

@ -8,6 +8,7 @@ import {
ElDropdownMenu,
ElForm,
ElLoading,
ElMessageBox,
ElPagination,
ElPopconfirm,
ElScrollbar,
@ -27,7 +28,6 @@ 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'
@ -35,14 +35,13 @@ import { saveFile } from '@/common/app'
import Colls from '@/common/utils/colls.ts'
import type { SetupContext } from '@vue/runtime-core'
import Types from '@/common/utils/types.ts'
import {
type IconName,
iconNames,
} from '@/components/a-icon/iconfont.ts'
import AIcon from '@/components/a-icon/AIcon.vue'
import type { DefaultRow } from 'element-plus/es/components/table/src/table/defaults'
type DeepPartial<T> = T extends Function
? T
: T extends Array<infer U>
? Array<DeepPartial<U>>
: T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
interface ColumnScopeType<T> {
row: T,
@ -51,10 +50,9 @@ interface ColumnScopeType<T> {
}
interface TableActionType<T> {
icon?: ElIconType
icon?: ElIconType | IconName
type?: 'text' | 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
label?: string | ((data: ColumnScopeType<T>) => string)
tooltip?: string | ((data: ColumnScopeType<T>) => string)
tooltip: string | ((data: ColumnScopeType<T>) => string)
loading?: boolean
show?: (data: ColumnScopeType<T>) => boolean
action: (data: ColumnScopeType<T>) => Promise<boolean> | void
@ -70,7 +68,7 @@ interface ActionColumnType<T> {
/**
* 80px
*/
width: string
width: number
/**
*
*/
@ -97,7 +95,7 @@ interface TablePropsType<T extends DefaultRow, F extends object> extends Omit<Ta
actionColumn: ActionColumnType<T>
}
interface FormPropsType<P, T> {
interface FormPropsType<P, T extends DefaultRow> {
/**
*
* @param param
@ -143,8 +141,6 @@ interface FormPropsType<P, T> {
*
*/
interface PageLayoutType {
/* columns: string[]
rows: string[] */
/**
* fr9fr
*/
@ -170,7 +166,7 @@ interface ATablePageType<P extends object, T extends DefaultRow> {
table: TablePropsType<T, P>
}
function buildSearchForm<P, T>(searchForm: DeepPartial<FormPropsType<P, T>> = {}) {
function buildSearchForm<P, T extends DefaultRow>(searchForm: DeepPartial<FormPropsType<P, T>> = {}) {
if (searchForm.defaultData == null) {
searchForm.defaultData = {} as DeepPartial<P>
}
@ -190,13 +186,6 @@ function buildSearchForm<P, T>(searchForm: DeepPartial<FormPropsType<P, T>> = {}
}
function buildPageLayout(pageLayout: DeepPartial<PageLayoutType> = {}) {
/* if (pageLayout.columns == null) {
pageLayout.columns = [ '1fr' ]
}
if (pageLayout.rows == null) {
pageLayout.rows = [ '1fr', '9fr' ]
} */
if (pageLayout.dataListHeight == null) {
pageLayout.dataListHeight = 9
}
@ -204,10 +193,10 @@ function buildPageLayout(pageLayout: DeepPartial<PageLayoutType> = {}) {
return pageLayout
}
function buildTable<P extends object, T extends DefaultRow>(table: DeepPartial<TablePropsType<T, P>> = {}) {
function buildTable<P extends object, T extends object>(table: DeepPartial<TablePropsType<T, P>> = {}) {
if (table.actionColumn == null) {
table.actionColumn = {
width: '80px',
width: 80,
tableActions: [],
}
}
@ -222,13 +211,13 @@ function buildTable<P extends object, T extends DefaultRow>(table: DeepPartial<T
}
}
if (table.actionColumn.width == null) {
table.actionColumn.width = '80px'
table.actionColumn.width = Math.min(table.actionColumn.tableActions.length, 3) * 50
}
if (table.emptyText == null) {
table.emptyText = '暂无数据'
}
if (table.rowKey == null) {
table.emptyText = 'id'
table.rowKey = 'id'
}
return table
@ -246,7 +235,7 @@ function buildToolBar(toolBar: DeepPartial<ToolBarType> = {}) {
return toolBar
}
export function buildProps<P extends G.PageParam, T extends DefaultRow>({pageLayout, searchForm, toolBar, table}: DeepPartial<ATablePageType<P, T>>) {
export function buildTablePageProps<P extends G.PageParam, T extends DefaultRow>({pageLayout, searchForm, toolBar, table}: DeepPartial<ATablePageType<P, T>>) {
return reactive({
pageLayout: buildPageLayout(pageLayout),
searchForm: buildSearchForm(searchForm),
@ -266,7 +255,7 @@ const component = defineComponent(
const totalCount = ref(0)
const loading = ref<boolean>(false)
const showHighForm = ref<boolean>(true)
const showHighForm = ref<boolean>(false)
const doSearch = () => {
loading.value = true
@ -340,31 +329,42 @@ const component = defineComponent(
}
})
const actionColumnBtnRender = (scope: ColumnScopeType<T>, tableAction: TableActionType<T>) => {
const Btn = <ElButton
icon={tableAction.icon == null ? undefined : elIcons[tableAction.icon]}
let elIcon: any | undefined = undefined
if (iconNames.includes(tableAction.icon as IconName)) {
elIcon = <AIcon name={tableAction.icon as IconName}/>
} else if (Object.keys(elIcons).includes(tableAction.icon as unknown as string)) {
elIcon = elIcons[tableAction.icon as ElIconType]
}
const tooltipTxt = tableAction.tooltip == null ? '' : (typeof tableAction.tooltip === 'function' ? tableAction.tooltip(scope) : tableAction.tooltip)
if (!Strings.isBlank(tooltipTxt)) {
return (<ElTooltip content={tooltipTxt} placement="top">
<ElButton
icon={elIcon}
loading={tableAction.loading}
type={tableAction.type}
class={styles.iconBtn}
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,
}}
class="icon-btn"
onClick={tableAction.confirm == null ? () => rowAction(scope, tableAction) : undefined}
text/>
</ElTooltip>)
}
return Btn
return (<ElButton
icon={elIcon}
loading={tableAction.loading}
type={tableAction.type}
class="icon-btn"
onClick={tableAction.confirm == null ? () => rowAction(scope, tableAction) : undefined}
text/>)
}
const actionColumnRender = () => {
const actionColumn = props.table.actionColumn
return Colls.isEmpty(actionColumn.tableActions) ? <></>
: (<ElTableColumn width={actionColumn.width} fixed="right" label="操作">
<div class="action-btn">
const len = actionColumn.tableActions.length
if (Colls.isEmpty(actionColumn.tableActions)) return (<></>)
return (<ElTableColumn width={actionColumn.width + 'px'} fixed="right" label="操作" prop="tableAction">
{{
default: (scope: ColumnScopeType<T>) => (actionColumn.tableActions
default: (scope: ColumnScopeType<T>) => {
let btns: any[]
if (len <= 3) {
btns = (actionColumn.tableActions
.filter(it => (it.show == null ? true : it.show(scope)))
.map((tableAction, i) => (tableAction.confirm != null ?
(<ElPopconfirm
@ -377,12 +377,86 @@ const component = defineComponent(
confirm-button-type="danger"
onConfirm={() => rowAction(scope, tableAction)}>
{{
reference: () => (actionColumnBtnRender(scope, tableAction)),
reference: () => (<div>
{actionColumnBtnRender(scope, tableAction)}
</div>),
}}
</ElPopconfirm>) : actionColumnBtnRender(scope, tableAction)))
),
)
} else {
btns = (actionColumn.tableActions
.filter(it => (it.show == null ? true : it.show(scope)))
.filter((_, i) => i < 2)
.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}
cancel-button-type="primary"
confirm-button-type="danger"
onConfirm={() => rowAction(scope, tableAction)}>
{{
reference: () => (<div>
{actionColumnBtnRender(scope, tableAction)}
</div>),
}}
</ElPopconfirm>) : actionColumnBtnRender(scope, tableAction)))
)
btns.push(<ElDropdown onCommand={(cmd) => {
const tableAction = actionColumn.tableActions[cmd]
if (tableAction.confirm != null) {
ElMessageBox.confirm(
typeof tableAction.confirm.title === 'function' ? tableAction.confirm.title(scope) : tableAction.confirm.title,
'操作提示',
{
confirmButtonText: tableAction.confirm.confirmButtonText,
cancelButtonText: tableAction.confirm.cancelButtonText,
confirmButtonType: 'primary',
cancelButtonType: 'danger',
type: 'warning',
},
)
.then(() => {
rowAction(scope, tableAction)
})
.catch(() => {
})
return
}
rowAction(scope, tableAction)
}}>
{{
default: () => (<ElButton icon={elIcons.More} class={[ styles.iconBtn, styles.moreIcon ]} text/>),
dropdown: () => (<ElDropdownMenu>
{
actionColumn.tableActions
.filter(it => (it.show == null ? true : it.show(scope)))
.filter((_, i) => i >= 2)
.map((it, i) => {
let elIcon: any | undefined = undefined
if (iconNames.includes(it.icon as IconName)) {
elIcon = <AIcon name={it.icon as IconName}/>
} else if (Object.keys(elIcons).includes(it.icon as unknown as string)) {
elIcon = elIcons[it.icon as ElIconType]
}
return (
<ElDropdownItem key={'action-btn-' + i} command={i + 2} icon={elIcon}>
{typeof it.tooltip === 'function' ? it.tooltip(scope) : it.tooltip}
</ElDropdownItem>
)
})
}
</ElDropdownMenu>),
}}
</ElDropdown>)
}
return (<div class="action-btn">
{btns}
</div>)
},
}}
</div>
</ElTableColumn>)
}
onMounted(doSearch)
@ -466,6 +540,7 @@ const component = defineComponent(
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"
class="data-table"
>
{
slots.columns?.()

View File

@ -24,10 +24,6 @@
width 100%;
box-sizing: border-box;
& {
}
& > div {
max-height 168px
width 100%;
@ -123,7 +119,8 @@
}
}
:global(.el-table) {
/*:global(.el-table) {
width 100%
height: 100%;
@ -160,8 +157,9 @@
.action-btn {
width 100%
display flex
flex-wrap wrap
display grid
grid-template-columns repeat(auto-fit, 32px)
grid-auto-rows: 32px;
gap: 10px;
.text-btn {
@ -173,10 +171,21 @@
padding: 8px;
justify-content: center;
align-items: center;
//#ebf0ff
}
:global(.el-button--default).icon-btn {
color #7987A1
background-color #F2F4F5
border-color #F2F4F5
}
:global(.el-button--info).icon-btn {
color #5D87FF
background-color #EBF0FF
border-color #EBF0FF
}
:global(.el-button--primary).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)
@ -189,7 +198,7 @@
}
}
}
*/
:global(.el-pagination) {
justify-content center

View File

@ -1,92 +0,0 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
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
const createApp: typeof import('vue').createApp
const createPinia: typeof import('pinia').createPinia
const customRef: typeof import('vue').customRef
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
const defineComponent: typeof import('vue').defineComponent
const defineStore: typeof import('pinia').defineStore
const effectScope: typeof import('vue').effectScope
const getActivePinia: typeof import('pinia').getActivePinia
const getCurrentInstance: typeof import('vue').getCurrentInstance
const getCurrentScope: typeof import('vue').getCurrentScope
const getCurrentWatcher: typeof import('vue').getCurrentWatcher
const h: typeof import('vue').h
const inject: typeof import('vue').inject
const isProxy: typeof import('vue').isProxy
const isReactive: typeof import('vue').isReactive
const isReadonly: typeof import('vue').isReadonly
const isRef: typeof import('vue').isRef
const isShallow: typeof import('vue').isShallow
const mapActions: typeof import('pinia').mapActions
const mapGetters: typeof import('pinia').mapGetters
const mapState: typeof import('pinia').mapState
const mapStores: typeof import('pinia').mapStores
const mapWritableState: typeof import('pinia').mapWritableState
const markRaw: typeof import('vue').markRaw
const nextTick: typeof import('vue').nextTick
const onActivated: typeof import('vue').onActivated
const onBeforeMount: typeof import('vue').onBeforeMount
const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave
const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate
const onBeforeUnmount: typeof import('vue').onBeforeUnmount
const onBeforeUpdate: typeof import('vue').onBeforeUpdate
const onDeactivated: typeof import('vue').onDeactivated
const onErrorCaptured: typeof import('vue').onErrorCaptured
const onMounted: typeof import('vue').onMounted
const onRenderTracked: typeof import('vue').onRenderTracked
const onRenderTriggered: typeof import('vue').onRenderTriggered
const onScopeDispose: typeof import('vue').onScopeDispose
const onServerPrefetch: typeof import('vue').onServerPrefetch
const onUnmounted: typeof import('vue').onUnmounted
const onUpdated: typeof import('vue').onUpdated
const onWatcherCleanup: typeof import('vue').onWatcherCleanup
const provide: typeof import('vue').provide
const reactive: typeof import('vue').reactive
const readonly: typeof import('vue').readonly
const ref: typeof import('vue').ref
const resolveComponent: typeof import('vue').resolveComponent
const setActivePinia: typeof import('pinia').setActivePinia
const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix
const shallowReactive: typeof import('vue').shallowReactive
const shallowReadonly: typeof import('vue').shallowReadonly
const shallowRef: typeof import('vue').shallowRef
const storeToRefs: typeof import('pinia').storeToRefs
const toRaw: typeof import('vue').toRaw
const toRef: typeof import('vue').toRef
const toRefs: typeof import('vue').toRefs
const toValue: typeof import('vue').toValue
const triggerRef: typeof import('vue').triggerRef
const unref: typeof import('vue').unref
const useAttrs: typeof import('vue').useAttrs
const useCssModule: typeof import('vue').useCssModule
const useCssVars: typeof import('vue').useCssVars
const useId: typeof import('vue').useId
const useLink: typeof import('vue-router').useLink
const useModel: typeof import('vue').useModel
const useRoute: typeof import('vue-router').useRoute
const useRouter: typeof import('vue-router').useRouter
const useSlots: typeof import('vue').useSlots
const useTemplateRef: typeof import('vue').useTemplateRef
const watch: typeof import('vue').watch
const watchEffect: typeof import('vue').watchEffect
const watchPostEffect: typeof import('vue').watchPostEffect
const watchSyncEffect: typeof import('vue').watchSyncEffect
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

View File

@ -1,124 +0,0 @@
/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
ElIconPhone: typeof import('@element-plus/icons-vue')['Phone']
ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
ElIconPlus: typeof import('@element-plus/icons-vue')['Plus']
ElImage: typeof import('element-plus/es')['ElImage']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMain: typeof import('element-plus/es')['ElMain']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTransfer: typeof import('element-plus/es')['ElTransfer']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
export interface GlobalDirectives {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}
// For TSX support
declare global {
const ElAside: typeof import('element-plus/es')['ElAside']
const ElAvatar: typeof import('element-plus/es')['ElAvatar']
const ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
const ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
const ElButton: typeof import('element-plus/es')['ElButton']
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
const ElContainer: typeof import('element-plus/es')['ElContainer']
const ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
const ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
const ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
const ElDialog: typeof import('element-plus/es')['ElDialog']
const ElDivider: typeof import('element-plus/es')['ElDivider']
const ElDropdown: typeof import('element-plus/es')['ElDropdown']
const ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
const ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
const ElEmpty: typeof import('element-plus/es')['ElEmpty']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElFormItem: typeof import('element-plus/es')['ElFormItem']
const ElHeader: typeof import('element-plus/es')['ElHeader']
const ElIcon: typeof import('element-plus/es')['ElIcon']
const ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
const ElIconPhone: typeof import('@element-plus/icons-vue')['Phone']
const ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
const ElIconPlus: typeof import('@element-plus/icons-vue')['Plus']
const ElImage: typeof import('element-plus/es')['ElImage']
const ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
const ElInput: typeof import('element-plus/es')['ElInput']
const ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
const ElMain: typeof import('element-plus/es')['ElMain']
const ElOption: typeof import('element-plus/es')['ElOption']
const ElPagination: typeof import('element-plus/es')['ElPagination']
const ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
const ElRadio: typeof import('element-plus/es')['ElRadio']
const ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
const ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
const ElSelect: typeof import('element-plus/es')['ElSelect']
const ElSwitch: typeof import('element-plus/es')['ElSwitch']
const ElTable: typeof import('element-plus/es')['ElTable']
const ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
const ElTabPane: typeof import('element-plus/es')['ElTabPane']
const ElTabs: typeof import('element-plus/es')['ElTabs']
const ElTag: typeof import('element-plus/es')['ElTag']
const ElText: typeof import('element-plus/es')['ElText']
const ElTooltip: typeof import('element-plus/es')['ElTooltip']
const ElTransfer: typeof import('element-plus/es')['ElTransfer']
const ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
const ElUpload: typeof import('element-plus/es')['ElUpload']
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
}

7
src/dts/g.d.ts vendored
View File

@ -1,6 +1,13 @@
export {}
declare global {
type DeepPartial<T> = T extends Function
? T
: T extends Array<infer U>
? Array<DeepPartial<U>>
: T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
namespace G {
interface TreeNode {
id: string

View File

@ -8,7 +8,7 @@ export default {
return get<G.PageResult<CustomerTypes.SearchCustomerResult>>('/customer/paging', data)
},
detail(id: string) {
return get<CustomerTypes.SearchCustomerResult>('/customer/detail', {id})
return get<CustomerTypes.TableData>('/customer/detail', {id})
},
add(data: CustomerTypes.AddCustomerParam) {
return post('/customer/add', data)

View File

@ -54,7 +54,7 @@ import ADtPicker from '@/components/a-dt-picker/ADtPicker.vue'
import GoodsCategoryDropTable from '@/pages/gds/goods-category/GoodsCategoryDropTable.vue'
import ATablePage, {
type ATablePageInstance,
buildProps,
buildTablePageProps,
} from '@/components/a-page/a-table-page/ATablePage.tsx'
const goodsFormIns = useTemplateRef<InstanceType<typeof GoodsForm>>('goodsForm')
@ -65,7 +65,7 @@ function research() {
tablePageIns.value?.doSearch()
}
const tablePageProps = buildProps({
const tablePageProps = buildTablePageProps({
searchForm: {
defaultData: {createTimes: [ undefined, undefined ]},
highForm: {

View File

@ -72,7 +72,7 @@
<ElTableColumn label="出场时间" prop="outTime" width="140"/>
<!-- <ElTableColumn label="完结时间" prop="finishTime"/> -->
<ElTableColumn fixed="right" label="支付状态" prop="paymentStatusTxt"/>
y
<ElTableColumn fixed="right" label="订单状态" prop="transStatusTxt"/>
<ElTableColumn fixed="right" label="勘料状态" prop="checkStatusTxt"/>
@ -80,27 +80,31 @@
<!-- <ElTableColumn label="客户备注" prop="customerMemo"/> -->
</template>
<OrderForm ref="orderForm" :research="research"/>
<BookDetail ref="bookDetail"/>
</ATablePage>
</template>
<script lang="ts" setup>
import OrderApi from '@/pages/order/order-api.ts'
import OrderForm from '@/pages/order/book/BookForm.vue'
import ADtPicker from '@/components/a-dt-picker/ADtPicker.vue'
import ATablePage, {
type ATablePageInstance,
buildProps,
buildTablePageProps,
} from '@/components/a-page/a-table-page/ATablePage.tsx'
import { transStatus } from '@/pages/order/constants.ts'
import BookDetail from '@/pages/order/book/BookDetail.vue'
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
const bookDetailIns = useTemplateRef<InstanceType<typeof BookDetail>>('bookDetail')
function research() {
tablePageIns.value?.doSearch()
}
const tablePageProps = buildProps({
const tablePageProps = buildTablePageProps<OrderTypes.SearchOrderParam, OrderTypes.TableData>({
pageLayout: {
dataListHeight: 4,
dataListHeight: 3,
},
table: {
actionColumn: {
@ -108,7 +112,20 @@ const tablePageProps = buildProps({
{
tooltip: '详情',
icon: 'Postcard',
action() {
type: 'primary',
action({row}) {
bookDetailIns.value?.open(row)
},
},
{
tooltip: '派单',
type: 'info',
show({row}) {
return row.transStatus === transStatus.DaiPaiDan
},
icon: 'Position',
action({row}) {
bookDetailIns.value?.open(row)
},
},
],
@ -118,13 +135,58 @@ const tablePageProps = buildProps({
highForm: {
contentWidth: 342,
},
paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param).then(res => {
res.data.records = []
for (let i = 0; i < 20; i++) {
res.data.records.push({})
/* paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
.then(res => {
const records = res.data.records
const dataList: OrderTypes.TableData[] = []
res.data.records = dataList
for (const record of records) {
const transRecodes = record.transRecodes ?? []
record.transRecodes = undefined
for (let i = 0; i < transRecodes.length; i++) {
const it = transRecodes[i]
dataList.push({
...record,
...it,
rowCount: i === 0 ? transRecodes.length : 0,
} as OrderTypes.TableData)
}
return res
}
return res as R<G.PageResult<OrderTypes.TableData>>
})
}, */
paging(param: OrderTypes.SearchOrderParam) {
return Promise.resolve({
code: 200,
data: {
current: param.current,
size: param.size,
total: 100,
records: [
{
rowCount: 1,
id: '123',
sn: '202308240001',
orderTime: '2023-08-24 10:00:00',
contacts: '张三',
phone: '13800000000',
projectName: '项目A',
stationName: '站点B',
goodsName: '商品X',
unit: '吨',
customerMemo: '客户备注',
estimatedQuantity: 100,
estimatedTrainNum: 2,
transDistance: 500,
orderCategoryTxt: '订单类型A',
transStatusTxt: '运输中',
transStatus: 'DaiPaiDan',
checkStatusTxt: '未勘料',
paymentStatusTxt: '未支付',
},
],
},
})
},
},

View File

@ -1,123 +1,154 @@
<template>
<ElDialog v-model="showDialog"
destroy-on-close
width="fit-content"
@close="dialogCloseHandler">
<ElDescriptions title="收/销订单" border>
<ElDescriptionsItem label="Id" prop="id">
{{ detailData.id }}
</ElDescriptionsItem>
<ElDescriptionsItem label="订单编号" prop="sn">
<ADetailPanel
ref="detailPanel"
v-bind="detailPanelProps"
>
<template #default="detailData">
<ElDescriptions border class="description" title="订单信息">
<ElDescriptionsItem label="订单编号">
{{ detailData.sn }}
</ElDescriptionsItem>
<ElDescriptionsItem label="项目 Id" prop="projectId">
{{ detailData.projectId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="下单人 Idsys_user.id" prop="userId">
{{ detailData.userId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="下单人客户 Idcst_customer.id" prop="customerId">
{{ detailData.customerId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="下单人姓名" prop="contacts">
{{ detailData.contacts }}
</ElDescriptionsItem>
<ElDescriptionsItem label="下单人联系方式" prop="phone">
{{ detailData.phone }}
</ElDescriptionsItem>
<ElDescriptionsItem label="下单时间" prop="orderTime">
<ElDescriptionsItem label="下单时间">
{{ detailData.orderTime }}
</ElDescriptionsItem>
<ElDescriptionsItem label="订单类型字典代码order_categoryHuiShouYuYue-->回收预约单、XiaoShouYuYue-->销售预约单、DuanBoRu-->短驳入、DuanBoChu-->短驳出" prop="orderCategory">
{{ detailData.orderCategory }}
<ElDescriptionsItem label="客户姓名">
{{ detailData.contacts }}
</ElDescriptionsItem>
<ElDescriptionsItem label="订单状态字典代码order_statusYiYuYue-->已预约、JinXingZhong-->进行中、YiWanCheng-->已完成、YiQuXiao-->已取消" prop="orderStatus">
{{ detailData.orderStatus }}
<ElDescriptionsItem label="客户电话">
{{ detailData.phone }}
</ElDescriptionsItem>
<ElDescriptionsItem label="完结时间" prop="finishTime">
{{ detailData.finishTime }}
<ElDescriptionsItem label="项目名称">
{{ detailData.projectInfo?.projectName || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="运输企业 Idcst_org.id" prop="transOrgId">
{{ detailData.transOrgId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="运输方客户 Id" prop="transCustomerId">
{{ detailData.transCustomerId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="指派清运公司时间" prop="assignmentTransTime">
{{ detailData.assignmentTransTime }}
</ElDescriptionsItem>
<ElDescriptionsItem label="站点 Idcst_station.id" prop="stationId">
{{ detailData.stationId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="站点名称cst_station.station.name" prop="stationName">
<ElDescriptionsItem label="站点名称">
{{ detailData.stationName }}
</ElDescriptionsItem>
<ElDescriptionsItem label="运距;单位:米" prop="transDistance">
{{ detailData.transDistance }}
</ElDescriptionsItem>
<ElDescriptionsItem label="预估量" prop="estimatedQuantity">
{{ detailData.estimatedQuantity }}
</ElDescriptionsItem>
<ElDescriptionsItem label="预估车数" prop="estimatedTrainNum">
{{ detailData.estimatedTrainNum }}
</ElDescriptionsItem>
<ElDescriptionsItem label="产品 Id" prop="goodsId">
{{ detailData.goodsId }}
</ElDescriptionsItem>
<ElDescriptionsItem label="产品名称" prop="goodsName">
<ElDescriptionsItem label="产品名称">
{{ detailData.goodsName }}
</ElDescriptionsItem>
<ElDescriptionsItem label="计量单位字典代码unit" prop="unit">
<ElDescriptionsItem label="计量单位">
{{ detailData.unit }}
</ElDescriptionsItem>
<ElDescriptionsItem label="客户备注" prop="customerMemo">
<ElDescriptionsItem label="客户备注">
{{ detailData.customerMemo }}
</ElDescriptionsItem>
<ElDescriptionsItem label="创建人 Id sys_user.id" prop="creatorId">
{{ detailData.creatorId }}
<ElDescriptionsItem label="预估量">
{{ detailData.estimatedQuantity }}
</ElDescriptionsItem>
<ElDescriptionsItem label="修改人 Id sys_user.id" prop="modifierId">
{{ detailData.modifierId }}
<ElDescriptionsItem label="预估车数">
{{ detailData.estimatedTrainNum }}
</ElDescriptionsItem>
<ElDescriptionsItem label="创建时间" prop="createTime">
{{ detailData.createTime }}
<ElDescriptionsItem label="运距(米)">
{{ detailData.transDistance }}
</ElDescriptionsItem>
<ElDescriptionsItem label="修改时间" prop="modifyTime">
{{ detailData.modifyTime }}
<ElDescriptionsItem label="订单类型">
{{ detailData.orderCategoryTxt }}
</ElDescriptionsItem>
<ElDescriptionsItem label="是否删除; 0-->未删除、1-->已删除" prop="deleted">
{{ detailData.deleted }}
</ElDescriptions>
<ElDescriptions class="description" direction="vertical" title="运输信息">
<ElDescriptionsItem>
<ElTable
:data="detailData.transRecodes"
cell-class-name="table-cell"
class="data-table"
header-row-class-name="table-header">
<ElTableColumn label="车次" prop="trainNum"/>
<ElTableColumn label="运输状态" prop="transStatusTxt"/>
<ElTableColumn label="司机姓名" prop="driverName"/>
<ElTableColumn label="司机电话" prop="driverPhone"/>
<ElTableColumn label="车牌号" prop="truckLicensePlate"/>
</ElTable>
</ElDescriptionsItem>
</ElDescriptions>
<template #footer>
<ElButton @click="showDialog = false" type="primary">关闭</ElButton>
</template>
</ElDialog>
<template #footer>
<ElButton type="primary" @click="dispatch"></ElButton>
</template>
</ADetailPanel>
</template>
<script lang="ts" setup>
import OrderApi from '@/pages/order/order-api.ts'
import Utils from '@/common/utils'
import ADetailPanel, {
type ADetailPanelInstance,
buildDetailPanelProps,
} from '@/components/a-detail-panel/ADetailPanel.tsx'
import { ElMessageBox } from 'element-plus'
const showDialog = ref(false)
const detailPanelIns = useTemplateRef<ADetailPanelInstance<OrderTypes.TableData>>('detailPanel')
const detailData = Utils.resetAble(reactive<OrderTypes.SearchOrderResult>({}))
function dialogCloseHandler() {
detailData.$reset()
function dispatch() {
console.log('派单')
ElMessageBox({
title: '请选择司机',
message: h('p', null, [
h('input', {
type: 'text',
placeholder: '请输入司机姓名',
}),
]),
})
}
defineExpose({
open(data: OrderTypes.SearchOrderResult) {
showDialog.value = true
OrderApi.detail(data.id!)
.then(res => {
detailData.$reset(res.data)
const detailPanelProps = buildDetailPanelProps<OrderTypes.SearchOrderResult>({
title: '订单详情',
width: '80vw',
detailsLoader: () => {
return Promise.resolve({
code: 200,
data: {
id: '123',
sn: '202308240001',
orderTime: '2023-08-24 10:00:00',
contacts: '张三',
phone: '13800000000',
projectInfo: {
projectName: '项目A',
},
stationName: '站点B',
goodsName: '商品X',
unit: '吨',
customerMemo: '客户备注',
estimatedQuantity: 100,
estimatedTrainNum: 2,
transDistance: 500,
orderCategoryTxt: '订单类型A',
transRecodes: [
{
trainNum: '车次1',
transStatusTxt: '运输中',
driverName: '司机A',
driverPhone: '13900000000',
truckLicensePlate: '粤B12345',
}, {
trainNum: '车次1',
transStatusTxt: '运输中',
driverName: '司机A',
driverPhone: '13900000000',
truckLicensePlate: '粤B12345',
}, {
trainNum: '车次1',
transStatusTxt: '运输中',
driverName: '司机A',
driverPhone: '13900000000',
truckLicensePlate: '粤B12345',
},
],
},
})
}
},
// detailsLoader: OrderApi.detail,
})
defineExpose({
open(data: OrderTypes.TableData) {
detailPanelIns.value?.open(data)
},
})
</script>
<style lang="stylus" scoped>
.description {
}
</style>

View File

@ -1,3 +1,5 @@
import type { DefaultRow } from 'element-plus/es/components/table/src/table/defaults'
export {}
declare global {
@ -233,6 +235,53 @@ declare global {
transRecodes?: TransRecode[]
}
interface TableData extends DefaultRow {
rowCount: number
// Id
id?: string
// 订单编号
sn?: string
// 下单时间
orderTime?: string
// 下单人姓名
contacts?: string
// 下单人联系方式
phone?: string
projectName?: string
// 站点名称cst_station.station.name
stationName?: string
transOrgName?: string
// 运距;单位:米
transDistance?: number
// 产品名称
goodsName?: string
// 计量单位字典代码unit
unit?: string
// 客户备注
customerMemo?: string
trainNum?: string
truckLicensePlate?: string
driverName?: string
driverPhone?: string
settleWeight?: string
roughWeight?: string
tareWeight?: string
inTime?: string
outTime?: string
transTime?: string
// 完结时间
finishTime?: string
paymentStatus?: string
paymentStatusTxt?: string
transStatus?: string
transStatusTxt?: string
checkStatus?: string
checkStatusTxt?: string
}
interface AddOrderParam {
// Id
id?: string

View File

@ -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>
@ -79,6 +72,7 @@
<ElTableColumn label="出场时间" prop="outTime" width="140"/>
<!-- <ElTableColumn label="完结时间" prop="finishTime"/> -->
<ElTableColumn fixed="right" label="支付状态" prop="paymentStatusTxt"/>
<ElTableColumn fixed="right" label="订单状态" prop="transStatusTxt"/>
<ElTableColumn fixed="right" label="勘料状态" prop="checkStatusTxt"/>
@ -86,53 +80,113 @@
<!-- <ElTableColumn label="客户备注" prop="customerMemo"/> -->
</template>
<OrderForm ref="orderForm" :research="research"/>
</FormPage>
<BookDetail ref="bookDetail"/>
</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,
buildTablePageProps,
} from '@/components/a-page/a-table-page/ATablePage.tsx'
import BookDetail from '@/pages/order/book/BookDetail.vue'
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
const bookDetailIns = useTemplateRef<InstanceType<typeof BookDetail>>('bookDetail')
const actionColumn = reactive<ActionColumnType<OrderTypes.SearchOrderResult>>({
function research() {
tablePageIns.value?.doSearch()
}
const tablePageProps = buildTablePageProps<OrderTypes.SearchOrderParam, OrderTypes.TableData>({
pageLayout: {
dataListHeight: 3,
},
table: {
actionColumn: {
tableActions: [
{
tooltip: '详情',
icon: 'Postcard',
type: 'primary',
action({row}) {
bookDetailIns.value?.open(row)
},
},
/* {
icon: 'Delete',
loading: false,
type: 'danger',
{
tooltip: '删除',
type: 'danger',
icon: 'Delete',
confirm: {
title: '是否删除当前数据',
title: '确认删除吗?',
},
action({row}) {
OrgApi.del([ row.id! ])
.then(() => {
ElMessage.success('删除成功')
return true
},
},
],
},
},
searchForm: {
highForm: {
contentWidth: 342,
},
/* paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
.then(res => {
const records = res.data.records
const dataList: OrderTypes.TableData[] = []
res.data.records = dataList
for (const record of records) {
const transRecodes = record.transRecodes ?? []
record.transRecodes = undefined
for (let i = 0; i < transRecodes.length; i++) {
const it = transRecodes[i]
dataList.push({
...record,
...it,
rowCount: i === 0 ? transRecodes.length : 0,
} as OrderTypes.TableData)
}
}
return res as R<G.PageResult<OrderTypes.TableData>>
})
}, */
paging(param: OrderTypes.SearchOrderParam) {
return Promise.resolve({
code: 200,
data: {
current: param.current,
size: param.size,
total: 100,
records: [
{
rowCount: 1,
id: '123',
sn: '202308240001',
orderTime: '2023-08-24 10:00:00',
contacts: '张三',
phone: '13800000000',
projectName: '项目A',
stationName: '站点B',
goodsName: '商品X',
unit: '吨',
customerMemo: '客户备注',
estimatedQuantity: 100,
estimatedTrainNum: 2,
transDistance: 500,
orderCategoryTxt: '订单类型A',
transStatusTxt: '运输中',
transStatus: 'DaiPaiDan',
checkStatusTxt: '未勘料',
paymentStatusTxt: '未支付',
},
],
},
})
},
}, */
],
},
})
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
function research() {
formPageIns.value?.doSearch()
}
function paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
}
</script>

View File

@ -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>
@ -79,6 +72,7 @@
<ElTableColumn label="出场时间" prop="outTime" width="140"/>
<!-- <ElTableColumn label="完结时间" prop="finishTime"/> -->
<ElTableColumn fixed="right" label="支付状态" prop="paymentStatusTxt"/>
<ElTableColumn fixed="right" label="订单状态" prop="transStatusTxt"/>
<ElTableColumn fixed="right" label="勘料状态" prop="checkStatusTxt"/>
@ -86,53 +80,111 @@
<!-- <ElTableColumn label="客户备注" prop="customerMemo"/> -->
</template>
<OrderForm ref="orderForm" :research="research"/>
</FormPage>
<BookDetail ref="bookDetail"/>
</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,
buildTablePageProps,
} from '@/components/a-page/a-table-page/ATablePage.tsx'
import BookDetail from '@/pages/order/book/BookDetail.vue'
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
const bookDetailIns = useTemplateRef<InstanceType<typeof BookDetail>>('bookDetail')
const actionColumn = reactive<ActionColumnType<OrderTypes.SearchOrderResult>>({
function research() {
tablePageIns.value?.doSearch()
}
const tablePageProps = buildTablePageProps<OrderTypes.SearchOrderParam, OrderTypes.TableData>({
pageLayout: {
dataListHeight: 3,
},
table: {
actionColumn: {
tableActions: [
{
tooltip: '详情',
icon: 'Postcard',
type: 'primary',
action({row}) {
bookDetailIns.value?.open(row)
},
},
/* {
icon: 'Delete',
loading: false,
type: 'danger',
tooltip: '删除',
confirm: {
title: '是否删除当前数据',
},
{
tooltip: '三联单',
type: 'info',
icon: 'Position',
action({row}) {
OrgApi.del([ row.id! ])
.then(() => {
ElMessage.success('删除成功')
return true
bookDetailIns.value?.open(row)
},
},
],
},
},
searchForm: {
highForm: {
contentWidth: 342,
},
/* paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
.then(res => {
const records = res.data.records
const dataList: OrderTypes.TableData[] = []
res.data.records = dataList
for (const record of records) {
const transRecodes = record.transRecodes ?? []
record.transRecodes = undefined
for (let i = 0; i < transRecodes.length; i++) {
const it = transRecodes[i]
dataList.push({
...record,
...it,
rowCount: i === 0 ? transRecodes.length : 0,
} as OrderTypes.TableData)
}
}
return res as R<G.PageResult<OrderTypes.TableData>>
})
}, */
paging(param: OrderTypes.SearchOrderParam) {
return Promise.resolve({
code: 200,
data: {
current: param.current,
size: param.size,
total: 100,
records: [
{
rowCount: 1,
id: '123',
sn: '202308240001',
orderTime: '2023-08-24 10:00:00',
contacts: '张三',
phone: '13800000000',
projectName: '项目A',
stationName: '站点B',
goodsName: '商品X',
unit: '吨',
customerMemo: '客户备注',
estimatedQuantity: 100,
estimatedTrainNum: 2,
transDistance: 500,
orderCategoryTxt: '订单类型A',
transStatusTxt: '运输中',
transStatus: 'DaiPaiDan',
checkStatusTxt: '未勘料',
paymentStatusTxt: '未支付',
},
],
},
})
},
}, */
],
},
})
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
function research() {
formPageIns.value?.doSearch()
}
function paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
}
</script>

View File

@ -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>
@ -79,6 +72,7 @@
<ElTableColumn label="出场时间" prop="outTime" width="140"/>
<!-- <ElTableColumn label="完结时间" prop="finishTime"/> -->
<ElTableColumn fixed="right" label="支付状态" prop="paymentStatusTxt"/>
<ElTableColumn fixed="right" label="订单状态" prop="transStatusTxt"/>
<ElTableColumn fixed="right" label="勘料状态" prop="checkStatusTxt"/>
@ -86,53 +80,127 @@
<!-- <ElTableColumn label="客户备注" prop="customerMemo"/> -->
</template>
<OrderForm ref="orderForm" :research="research"/>
</FormPage>
<BookDetail ref="bookDetail"/>
</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,
buildTablePageProps,
} from '@/components/a-page/a-table-page/ATablePage.tsx'
import BookDetail from '@/pages/order/book/BookDetail.vue'
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
const bookDetailIns = useTemplateRef<InstanceType<typeof BookDetail>>('bookDetail')
const actionColumn = reactive<ActionColumnType<OrderTypes.SearchOrderResult>>({
function research() {
tablePageIns.value?.doSearch()
}
const tablePageProps = buildTablePageProps<OrderTypes.SearchOrderParam, OrderTypes.TableData>({
pageLayout: {
dataListHeight: 3,
},
table: {
actionColumn: {
tableActions: [
{
tooltip: '详情',
icon: 'Postcard',
type: 'primary',
action({row}) {
bookDetailIns.value?.open(row)
},
},
/* {
icon: 'Delete',
loading: false,
type: 'danger',
tooltip: '删除',
confirm: {
title: '是否删除当前数据',
},
{
tooltip: '进场',
type: 'info',
icon: 'Position',
action({row}) {
OrgApi.del([ row.id! ])
.then(() => {
ElMessage.success('删除成功')
return true
bookDetailIns.value?.open(row)
},
},
{
tooltip: '出场',
type: 'info',
icon: 'Position',
action({row}) {
bookDetailIns.value?.open(row)
},
},
{
tooltip: '勘料',
type: 'info',
icon: 'Position',
action({row}) {
bookDetailIns.value?.open(row)
},
},
],
},
},
searchForm: {
highForm: {
contentWidth: 342,
},
/* paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
.then(res => {
const records = res.data.records
const dataList: OrderTypes.TableData[] = []
res.data.records = dataList
for (const record of records) {
const transRecodes = record.transRecodes ?? []
record.transRecodes = undefined
for (let i = 0; i < transRecodes.length; i++) {
const it = transRecodes[i]
dataList.push({
...record,
...it,
rowCount: i === 0 ? transRecodes.length : 0,
} as OrderTypes.TableData)
}
}
return res as R<G.PageResult<OrderTypes.TableData>>
})
}, */
paging(param: OrderTypes.SearchOrderParam) {
return Promise.resolve({
code: 200,
data: {
current: param.current,
size: param.size,
total: 100,
records: [
{
rowCount: 1,
id: '123',
sn: '202308240001',
orderTime: '2023-08-24 10:00:00',
contacts: '张三',
phone: '13800000000',
projectName: '项目A',
stationName: '站点B',
goodsName: '商品X',
unit: '吨',
customerMemo: '客户备注',
estimatedQuantity: 100,
estimatedTrainNum: 2,
transDistance: 500,
orderCategoryTxt: '订单类型A',
transStatusTxt: '运输中',
transStatus: 'DaiPaiDan',
checkStatusTxt: '未勘料',
paymentStatusTxt: '未支付',
},
],
},
})
},
}, */
],
},
})
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
function research() {
formPageIns.value?.doSearch()
}
function paging(param: OrderTypes.SearchOrderParam) {
return OrderApi.paging(param)
}
</script>

View File

@ -19,6 +19,9 @@
"src/*"
]
},
"types": [
"element-plus/global"
],
"plugins": [
{
"name": "typescript-plugin-css-modules"

View File

@ -35,10 +35,7 @@ export default defineConfig((configEnv) => {
vue(),
vueJsx(),
VueDevTools(),
ElementPlus({
defaultLocale: 'zh-cn',
// useSource: true,
}),
ElementPlus({}),
AutoImport({
imports: [ 'vue', 'vue-router', 'pinia' ],
dts: './src/dts/auto-imports.d.ts',