时间范围筛选优化

This commit is contained in:
2026-06-04 10:51:35 +08:00
parent 32f8e19bf1
commit ff61e815d8
6 changed files with 560 additions and 172 deletions
@@ -0,0 +1,91 @@
<template>
<template v-if="variant === 'split'">
<el-form-item :label="label" :class="{ 'is-compact': compact }">
<el-radio-group v-model="timeType" :size="compact ? 'small' : 'default'" @change="emit('time-type-change')">
<el-radio-button label="today">今天</el-radio-button>
<el-radio-button label="yesterday">昨天</el-radio-button>
<el-radio-button label="week">最近7天</el-radio-button>
<el-radio-button label="month">本月</el-radio-button>
<el-radio-button label="custom">自定义</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="timeType === 'custom'">
<el-date-picker
v-model="dateRangeModel"
type="daterange"
value-format="YYYY-MM-DD"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:size="compact ? 'small' : 'default'"
:style="{ width: pickerWidth }"
@change="emit('custom-change')"
/>
</el-form-item>
</template>
<el-form-item v-else :label="label" :class="{ 'is-compact': compact }">
<div class="list-time-filter-inline">
<el-radio-group v-model="timeType" :size="compact ? 'small' : 'default'" @change="emit('time-type-change')">
<el-radio-button label="today">今天</el-radio-button>
<el-radio-button label="yesterday">昨天</el-radio-button>
<el-radio-button label="week">最近7天</el-radio-button>
<el-radio-button label="month">本月</el-radio-button>
<el-radio-button label="custom">自定义</el-radio-button>
</el-radio-group>
<el-date-picker
v-if="timeType === 'custom'"
v-model="dateRangeModel"
type="daterange"
value-format="YYYY-MM-DD"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:size="compact ? 'small' : 'default'"
:style="{ width: pickerWidth }"
@change="emit('custom-change')"
/>
</div>
</el-form-item>
</template>
<script lang="ts" setup>
import type { ListTimeType } from '@/hooks/useListTimeFilter'
withDefaults(
defineProps<{
label?: string
/** split:与自录统计一致,两个 form-item;inline:处方订单筛选用单行 */
variant?: 'split' | 'inline'
pickerWidth?: string
/** 紧凑模式:small 尺寸 radio / 日期 */
compact?: boolean
}>(),
{
label: '时间范围',
variant: 'split',
pickerWidth: '260px',
compact: false,
}
)
const timeType = defineModel<ListTimeType>('timeType', { required: true })
const dateRangeModel = defineModel<string[]>('dateRange', { default: () => [] })
const emit = defineEmits<{
'time-type-change': []
'custom-change': []
}>()
</script>
<style scoped lang="scss">
.list-time-filter-inline {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px 8px;
}
:deep(.is-compact.el-form-item) {
margin-bottom: 0;
}
</style>
+86
View File
@@ -0,0 +1,86 @@
export type ListTimeType = 'today' | 'yesterday' | 'week' | 'month' | 'custom'
export function formatYmd(d: Date): string {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
/** 列表时间筛选:month 为本自然月 1 日~月末 */
export function resolveListTimeRange(timeType: ListTimeType, dateRange: string[]): [string, string] {
const today = formatYmd(new Date())
switch (timeType) {
case 'yesterday': {
const d = new Date()
d.setDate(d.getDate() - 1)
const y = formatYmd(d)
return [y, y]
}
case 'week': {
const end = new Date()
const start = new Date()
start.setDate(start.getDate() - 6)
return [formatYmd(start), formatYmd(end)]
}
case 'month': {
const now = new Date()
const start = new Date(now.getFullYear(), now.getMonth(), 1)
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0)
return [formatYmd(start), formatYmd(end)]
}
case 'custom': {
let start = dateRange[0] || today
let end = dateRange[1] || today
if (start > end) {
;[start, end] = [end, start]
}
return [start, end]
}
case 'today':
default:
return [today, today]
}
}
export function useListTimeFilter(defaultType: ListTimeType = 'today') {
const time_type = ref<ListTimeType>(defaultType)
const dateRange = ref<string[]>([])
const resolve = () => resolveListTimeRange(time_type.value, dateRange.value)
const handleTimeTypeChange = (onQuery: () => void) => {
if (time_type.value !== 'custom') {
dateRange.value = []
onQuery()
}
}
const handleCustomDateChange = (onQuery: () => void) => {
if (dateRange.value.length === 2) {
onQuery()
}
}
const resetTimeFilter = () => {
time_type.value = defaultType
dateRange.value = []
}
const applyCustomRange = (start: string, end: string) => {
if (!start || !end) return
time_type.value = 'custom'
dateRange.value = [start, end]
}
return {
time_type,
dateRange,
resolve,
handleTimeTypeChange,
handleCustomDateChange,
resetTimeFilter,
applyCustomRange,
}
}
@@ -8,86 +8,76 @@
</div>
</header> -->
<el-card class="!border-none shadow-sm mb-4" shadow="never">
<div class="flex flex-col gap-3">
<div v-if="showPrescriptionAuditFilter" class="flex items-center gap-2 flex-wrap">
<span class="text-gray-500 text-sm font-medium w-20 shrink-0">处方审核</span>
<div
v-for="tab in rxAuditTabs"
:key="tab.value"
:class="[
'px-4 py-1.5 rounded-lg cursor-pointer transition-all duration-200 select-none text-sm',
queryParams.prescription_audit_status === tab.value
? 'bg-primary text-white shadow-md'
: 'bg-gray-50 text-gray-600 hover:bg-gray-100'
]"
@click="handleRxAuditTabClick(tab.value)"
>
<span class="font-medium">{{ tab.label }}</span>
<el-card class="!border-none shadow-sm mb-4 po-status-card" shadow="never">
<div class="po-status-grid">
<div v-if="showPrescriptionAuditFilter" class="po-seg-group">
<span class="po-seg-label">处方审核</span>
<div class="po-seg">
<button
v-for="tab in rxAuditTabs"
:key="tab.value"
type="button"
:class="['po-seg-item', { 'is-active': queryParams.prescription_audit_status === tab.value }]"
@click="handleRxAuditTabClick(tab.value)"
>
{{ tab.label }}
</button>
</div>
</div>
<div class="flex items-center gap-2 flex-wrap">
<span class="text-gray-500 text-sm font-medium w-20 shrink-0">支付单审核</span>
<div
v-for="tab in payAuditTabs"
:key="tab.value"
:class="[
'px-4 py-1.5 rounded-lg cursor-pointer transition-all duration-200 select-none text-sm',
queryParams.payment_slip_audit_status === tab.value
? 'bg-primary text-white shadow-md'
: 'bg-gray-50 text-gray-600 hover:bg-gray-100'
]"
@click="handlePayAuditTabClick(tab.value)"
>
<span class="font-medium">{{ tab.label }}</span>
<div class="po-seg-group">
<span class="po-seg-label">支付单审核</span>
<div class="po-seg">
<button
v-for="tab in payAuditTabs"
:key="tab.value"
type="button"
:class="['po-seg-item', { 'is-active': queryParams.payment_slip_audit_status === tab.value }]"
@click="handlePayAuditTabClick(tab.value)"
>
{{ tab.label }}
</button>
</div>
</div>
<div class="flex items-center gap-2 flex-wrap">
<span class="text-gray-500 text-sm font-medium w-20 shrink-0">发货状态</span>
<div
v-for="tab in fulfillmentStatusTabs"
:key="'fs-' + String(tab.value)"
:class="[
'px-4 py-1.5 rounded-lg cursor-pointer transition-all duration-200 select-none text-sm',
queryParams.fulfillment_status === tab.value
? 'bg-primary text-white shadow-md'
: 'bg-gray-50 text-gray-600 hover:bg-gray-100'
]"
@click="handleFulfillmentStatusTabClick(tab.value)"
>
<span class="font-medium">{{ tab.label }}</span>
<div class="po-seg-group">
<span class="po-seg-label">发货状态</span>
<div class="po-seg">
<button
v-for="tab in fulfillmentStatusTabs"
:key="'fs-' + String(tab.value)"
type="button"
:class="['po-seg-item', { 'is-active': queryParams.fulfillment_status === tab.value }]"
@click="handleFulfillmentStatusTabClick(tab.value)"
>
{{ tab.label }}
</button>
</div>
</div>
<div class="flex items-center gap-2 flex-wrap">
<span class="text-gray-500 text-sm font-medium w-20 shrink-0">供货方式</span>
<div
v-for="tab in supplyModeTabs"
:key="'sm-' + String(tab.value)"
:class="[
'px-4 py-1.5 rounded-lg cursor-pointer transition-all duration-200 select-none text-sm',
queryParams.supply_mode === tab.value
? 'bg-primary text-white shadow-md'
: 'bg-gray-50 text-gray-600 hover:bg-gray-100'
]"
@click="handleSupplyModeTabClick(tab.value)"
>
<span class="font-medium">{{ tab.label }}</span>
<div class="po-seg-group">
<span class="po-seg-label">供货方式</span>
<div class="po-seg">
<button
v-for="tab in supplyModeTabs"
:key="'sm-' + String(tab.value)"
type="button"
:class="['po-seg-item', { 'is-active': queryParams.supply_mode === tab.value }]"
@click="handleSupplyModeTabClick(tab.value)"
>
{{ tab.label }}
</button>
</div>
</div>
<div class="flex items-center gap-2 flex-wrap">
<span class="text-gray-500 text-sm font-medium w-20 shrink-0">快递方式</span>
<div
v-for="tab in expressCompanyTabs"
:key="'ec-' + String(tab.value)"
:class="[
'px-4 py-1.5 rounded-lg cursor-pointer transition-all duration-200 select-none text-sm',
queryParams.express_company === tab.value
? 'bg-primary text-white shadow-md'
: 'bg-gray-50 text-gray-600 hover:bg-gray-100'
]"
@click="handleExpressCompanyTabClick(tab.value)"
>
<span class="font-medium">{{ tab.label }}</span>
<div class="po-seg-group">
<span class="po-seg-label">快递方式</span>
<div class="po-seg">
<button
v-for="tab in expressCompanyTabs"
:key="'ec-' + String(tab.value)"
type="button"
:class="['po-seg-item', { 'is-active': queryParams.express_company === tab.value }]"
@click="handleExpressCompanyTabClick(tab.value)"
>
{{ tab.label }}
</button>
</div>
</div>
</div>
@@ -172,19 +162,18 @@
</p> -->
</div>
</div>
<el-form class="ls-form" :model="queryParams" inline>
<el-form-item class="w-[360px] min-w-[240px] max-w-full" label="创建时间">
<DaterangePicker
v-model:startTime="queryParams.start_time"
v-model:endTime="queryParams.end_time"
picker-type="daterange"
value-format="YYYY-MM-DD"
start-placeholder="开始日期"
end-placeholder="结束日期"
class="!w-full"
/>
</el-form-item>
<el-form-item class="w-[260px]" label="订单号">
<el-form class="po-filter-form" :model="queryParams" size="small" inline>
<list-time-filter
v-model:time-type="time_type"
v-model:date-range="dateRange"
label="创建时间"
variant="inline"
compact
picker-width="230px"
@time-type-change="onTimeTypeChange"
@custom-change="onCustomDateChange"
/>
<el-form-item class="po-fi w-[210px]" label="订单号">
<el-input
v-model="queryParams.order_no"
placeholder="业务订单号"
@@ -192,7 +181,7 @@
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item class="w-[140px]" label="处方ID">
<el-form-item class="po-fi w-[150px]" label="处方ID">
<el-input
v-model="queryParams.prescription_id"
placeholder="处方ID"
@@ -200,7 +189,7 @@
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item class="w-[220px]" label="患者">
<el-form-item class="po-fi w-[200px]" label="患者">
<el-input
v-model="queryParams.patient_keyword"
placeholder="姓名 / 手机号"
@@ -208,7 +197,7 @@
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item class="w-[220px]" label="快递">
<el-form-item class="po-fi w-[200px]" label="快递">
<el-input
v-model="queryParams.express_keyword"
placeholder="快递单号 / 公司"
@@ -216,13 +205,13 @@
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item v-if="showAuditAdminFilter" class="w-[200px]" label="下单人">
<el-form-item v-if="showAuditAdminFilter" class="po-fi w-[190px]" label="下单人">
<el-select
v-model="queryParams.audit_admin_id"
clearable
filterable
placeholder="全部下单人"
class="!w-full"
class="po-filter-control"
>
<el-option
v-for="a in auditAdminOptions"
@@ -232,13 +221,13 @@
/>
</el-select>
</el-form-item>
<el-form-item class="w-[200px]" label="医生">
<el-form-item class="po-fi w-[180px]" label="医生">
<el-select
v-model="queryParams.doctor_id"
clearable
filterable
placeholder="开方医生"
class="!w-full"
class="po-filter-control"
>
<el-option
v-for="d in doctorOptions"
@@ -248,28 +237,28 @@
/>
</el-select>
</el-form-item>
<el-form-item class="w-[220px] min-w-[200px]" label="医助部门">
<el-form-item class="po-fi w-[220px]" label="医助部门">
<el-tree-select
v-model="queryParams.assistant_dept_id"
:data="departmentTreeRaw"
class="!w-full"
class="po-filter-control"
clearable
filterable
check-strictly
:default-expand-all="true"
node-key="id"
:props="assistantDeptTreeProps"
placeholder="医助部门(选父级含子级)"
placeholder="医助部门(含子级)"
@change="onAssistantDeptChange"
/>
</el-form-item>
<el-form-item class="w-[200px]" label="医助">
<el-form-item class="po-fi w-[180px]" label="医助">
<el-select
v-model="queryParams.assistant_id"
clearable
filterable
placeholder="订单创建人"
class="!w-full"
class="po-filter-control"
>
<el-option
v-for="a in filteredAssistantOptions"
@@ -279,17 +268,21 @@
/>
</el-select>
</el-form-item>
<el-form-item class="w-[160px]" label="服务渠道">
<el-select v-model="queryParams.service_channel" clearable placeholder="全部" class="!w-full">
<el-form-item class="po-fi w-[150px]" label="服务渠道">
<el-select
v-model="queryParams.service_channel"
clearable
placeholder="全部"
class="po-filter-control"
>
<el-option label="未指派" value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-form-item class="po-fi-actions">
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="handleReset">重置</el-button>
<export-data
v-perms="['tcm.prescriptionOrder/export']"
class="ml-2.5"
:fetch-fun="prescriptionOrderExport"
:params="prescriptionOrderExportParams"
:page-size="pager.size"
@@ -2856,7 +2849,8 @@
import { computed, onMounted, reactive, ref, nextTick, watch, defineAsyncComponent } from 'vue'
import { useRoute } from 'vue-router'
import { Refresh, Loading, ArrowDown, InfoFilled, QuestionFilled, Search, Calendar, Document, Link as LinkIcon, Wallet } from '@element-plus/icons-vue'
import DaterangePicker from '@/components/daterange-picker/index.vue'
import ListTimeFilter from '@/components/list-time-filter/index.vue'
import { useListTimeFilter } from '@/hooks/useListTimeFilter'
import {
prescriptionOrderAuditPayment,
prescriptionOrderAuditPrescription,
@@ -3162,9 +3156,6 @@ function handleExpressCompanyTabClick(value: '' | 'sf' | 'jd') {
}
const queryParams = reactive({
/** 创建时间区间(与列表筛选一致;不影响「今日」统计) */
start_time: '' as string,
end_time: '' as string,
order_no: '',
prescription_id: '' as string | number,
/** 诊单患者姓名/手机号(后台关联 diagnosis */
@@ -3252,6 +3243,24 @@ function handleFocusBoardSearch(key: 'pendingRx' | 'pendingPay' | 'pendingShip'
resetPage()
}
const {
time_type,
dateRange,
resolve: resolveCreateTimeRange,
handleTimeTypeChange,
handleCustomDateChange,
resetTimeFilter,
applyCustomRange,
} = useListTimeFilter('today')
const handleQuery = () => {
pager.page = 1
getLists()
}
const onTimeTypeChange = () => handleTimeTypeChange(handleQuery)
const onCustomDateChange = () => handleCustomDateChange(handleQuery)
function normalizePrescriptionOrderListQuery(params: Record<string, unknown>): Record<string, unknown> {
const p: Record<string, unknown> = { ...params }
if (p.prescription_id === '' || p.prescription_id === undefined) {
@@ -3331,11 +3340,15 @@ function normalizePrescriptionOrderListQuery(params: Record<string, unknown>): R
}
async function fetchLists(params: Record<string, unknown>) {
const p = normalizePrescriptionOrderListQuery({ ...params })
const [start_time, end_time] = resolveCreateTimeRange()
const p = normalizePrescriptionOrderListQuery({ ...params, start_time, end_time })
return prescriptionOrderLists(p)
}
const prescriptionOrderExportParams = computed(() => normalizePrescriptionOrderListQuery({ ...queryParams }))
const prescriptionOrderExportParams = computed(() => {
const [start_time, end_time] = resolveCreateTimeRange()
return normalizePrescriptionOrderListQuery({ ...queryParams, start_time, end_time })
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: fetchLists,
@@ -3370,8 +3383,9 @@ function applyRouteQueryToPrescriptionOrderList() {
}
const st = normDate(q.start_time)
const et = normDate(q.end_time)
if (st) queryParams.start_time = st
if (et) queryParams.end_time = et
if (st && et) {
applyCustomRange(st, et)
}
const ad = q.assistant_dept_id
if (ad !== undefined && ad !== null && String(ad) !== '') {
const n = Number(ad)
@@ -3462,8 +3476,7 @@ const listStats = computed(() => {
scopeHint =
'统计口径:本人创建的订单 + 关联处方开方人为本人的订单(含医助代建);与下方筛选项(不含「创建时间」)一致'
}
const hasCustomTime =
String(queryParams.start_time || '').trim() !== '' && String(queryParams.end_time || '').trim() !== ''
const hasCustomTime = time_type.value !== 'today'
const headPrefix = hasCustomTime ? '区间' : '今日'
return {
order: n(o),
@@ -3536,8 +3549,7 @@ watch(
function handleReset() {
activeFocusKey.value = ''
queryParams.start_time = ''
queryParams.end_time = ''
resetTimeFilter()
queryParams.order_no = ''
queryParams.prescription_id = ''
queryParams.patient_keyword = ''
@@ -6492,6 +6504,121 @@ async function downloadPrescriptionSlipPdf() {
</script>
<style scoped lang="scss">
.stats-filter-form {
:deep(.el-form-item) {
margin-bottom: 0;
}
}
/* ── 状态分段筛选(iOS 风格 segmented control)── */
.po-status-card :deep(.el-card__body) {
padding: 14px 18px;
}
.po-status-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 32px;
@media (max-width: 1180px) {
grid-template-columns: 1fr;
}
}
.po-seg-group {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.po-seg-label {
flex-shrink: 0;
width: 72px;
font-size: 13px;
font-weight: 500;
color: var(--el-text-color-secondary);
text-align: right;
}
.po-seg {
display: inline-flex;
flex-wrap: wrap;
gap: 2px;
padding: 3px;
background: var(--el-fill-color-light);
border-radius: 9px;
}
.po-seg-item {
appearance: none;
border: none;
margin: 0;
background: transparent;
padding: 5px 16px;
border-radius: 6px;
font-size: 13px;
line-height: 1.4;
color: var(--el-text-color-regular);
cursor: pointer;
transition: color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}
.po-seg-item:hover {
color: var(--el-color-primary);
}
.po-seg-item.is-active {
background: #fff;
color: var(--el-color-primary);
font-weight: 600;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 2px 6px rgba(0, 0, 0, 0.04);
}
/* ── 查询条件表单(流式 inline,自动换行)── */
.po-filter-form {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px 18px;
:deep(.el-form-item) {
margin: 0;
}
:deep(.el-form-item__label) {
padding-right: 8px;
color: var(--el-text-color-secondary);
font-size: 13px;
}
:deep(.el-form-item__content) {
flex: 1;
min-width: 0;
}
:deep(.el-input),
:deep(.el-select),
:deep(.el-tree-select) {
width: 100%;
}
}
.po-filter-control {
width: 100%;
}
/* 查询/重置/导出:流到末尾并靠右 */
.po-fi-actions {
margin-left: auto;
:deep(.el-form-item__content) {
display: flex;
align-items: center;
gap: 8px;
}
}
.prescription-order-page {
margin: 0 auto;
@@ -6517,7 +6644,7 @@ async function downloadPrescriptionSlipPdf() {
}
.po-filter-card :deep(.el-card__body) {
padding-bottom: 12px;
padding: 12px 16px 14px;
}
.po-list-stats {
@@ -190,18 +190,16 @@
<ArrowDown />
</el-icon>
</div>
<el-form v-show="!h5FilterCollapsed" class="ls-form" :model="queryParams" inline>
<el-form-item class="w-[360px] min-w-[240px] max-w-full" label="创建时间">
<DaterangePicker
v-model:startTime="queryParams.start_time"
v-model:endTime="queryParams.end_time"
picker-type="daterange"
value-format="YYYY-MM-DD"
start-placeholder="开始日期"
end-placeholder="结束日期"
class="!w-full"
/>
</el-form-item>
<el-form v-show="!h5FilterCollapsed" class="ls-form stats-filter-form" :model="queryParams" inline>
<list-time-filter
v-model:time-type="time_type"
v-model:date-range="dateRange"
label="创建时间"
variant="inline"
picker-width="260px"
@time-type-change="onTimeTypeChange"
@custom-change="onCustomDateChange"
/>
<el-form-item class="w-[260px]" label="订单号">
<el-input
v-model="queryParams.order_no"
@@ -2507,7 +2505,8 @@ import {
Wallet,
User
} from '@element-plus/icons-vue'
import DaterangePicker from '@/components/daterange-picker/index.vue'
import ListTimeFilter from '@/components/list-time-filter/index.vue'
import { useListTimeFilter } from '@/hooks/useListTimeFilter'
import {
prescriptionOrderAuditPayment,
prescriptionOrderAuditPrescription,
@@ -2805,9 +2804,6 @@ function handleExpressCompanyTabClick(value: '' | 'sf' | 'jd') {
}
const queryParams = reactive({
/** 创建时间区间(与列表筛选一致;不影响「今日」统计) */
start_time: '' as string,
end_time: '' as string,
order_no: '',
prescription_id: '' as string | number,
/** 诊单患者姓名/手机号(后台关联 diagnosis */
@@ -2886,8 +2882,26 @@ function handleFocusBoardSearch(key: 'pendingRx' | 'pendingPay' | 'pendingShip'
resetPage()
}
const {
time_type,
dateRange,
resolve: resolveCreateTimeRange,
handleTimeTypeChange,
handleCustomDateChange,
resetTimeFilter,
} = useListTimeFilter('today')
const handleQuery = () => {
pager.page = 1
getLists()
}
const onTimeTypeChange = () => handleTimeTypeChange(handleQuery)
const onCustomDateChange = () => handleCustomDateChange(handleQuery)
async function fetchLists(params: Record<string, unknown>) {
const p: Record<string, unknown> = { ...params }
const [start_time, end_time] = resolveCreateTimeRange()
const p: Record<string, unknown> = { ...params, start_time, end_time }
if (p.prescription_id === '' || p.prescription_id === undefined) {
delete p.prescription_id
} else {
@@ -3041,8 +3055,7 @@ const listStats = computed(() => {
scopeHint =
'统计口径:本人创建的订单 + 关联处方开方人为本人的订单(含医助代建);与下方筛选项(不含「创建时间」)一致'
}
const hasCustomTime =
String(queryParams.start_time || '').trim() !== '' && String(queryParams.end_time || '').trim() !== ''
const hasCustomTime = time_type.value !== 'today'
const headPrefix = hasCustomTime ? '区间' : '今日'
return {
order: n(o),
@@ -3114,8 +3127,7 @@ watch(
function handleReset() {
activeFocusKey.value = ''
queryParams.start_time = ''
queryParams.end_time = ''
resetTimeFilter()
queryParams.order_no = ''
queryParams.prescription_id = ''
queryParams.patient_keyword = ''
@@ -3381,11 +3393,11 @@ const h5FilterCollapsed = ref(true)
const h5ActiveFilterCount = computed(() => {
const q = queryParams as any
const keys = [
'start_time', 'end_time', 'order_no', 'prescription_id',
'order_no', 'prescription_id',
'patient_keyword', 'express_keyword', 'doctor_id',
'assistant_dept_id', 'assistant_id'
]
let n = 0
let n = time_type.value !== 'today' ? 1 : 0
for (const k of keys) {
const v = q[k]
if (v === null || v === undefined) continue
@@ -5520,6 +5532,12 @@ async function downloadPrescriptionSlipPdf() {
</script>
<style scoped lang="scss">
.stats-filter-form {
:deep(.el-form-item) {
margin-bottom: 0;
}
}
.prescription-order-page {
margin: 0 auto;
+50 -17
View File
@@ -14,13 +14,13 @@
</el-card>
<el-card class="!border-none" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="日期范围">
<daterange-picker
v-model:startTime="queryParams.start_date"
v-model:endTime="queryParams.end_date"
/>
</el-form-item>
<el-form :inline="true" :model="queryParams" class="stats-filter-form">
<list-time-filter
v-model:time-type="time_type"
v-model:date-range="dateRange"
@time-type-change="onTimeTypeChange"
@custom-change="onCustomDateChange"
/>
<el-form-item label="自媒体渠道">
<el-select
v-model="queryParams.media_channel_code"
@@ -67,11 +67,11 @@
v-model="queryParams.remark"
placeholder="备注 / 创建人 / 修改人"
clearable
@keyup.enter="resetPage"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button type="primary" :loading="pager.loading" @click="handleQuery">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
@@ -148,7 +148,9 @@
<script lang="ts" setup name="accountCostList">
import { accountCostDelete, accountCostLists } from '@/api/finance'
import { usePaging } from '@/hooks/usePaging'
import { useListTimeFilter } from '@/hooks/useListTimeFilter'
import feedback from '@/utils/feedback'
import ListTimeFilter from '@/components/list-time-filter/index.vue'
import EditPopup from './edit.vue'
@@ -172,18 +174,40 @@ const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const queryParams = reactive({
start_date: '',
end_date: '',
media_channel_code: '',
dept_id: '',
remark: '',
})
const { pager, getLists, resetPage } = usePaging({
fetchFun: accountCostLists,
const {
time_type,
dateRange,
resolve,
handleTimeTypeChange,
handleCustomDateChange,
resetTimeFilter,
} = useListTimeFilter('today')
const { pager, getLists } = usePaging({
fetchFun: async (params: Record<string, any>) => {
const [start_date, end_date] = resolve()
return accountCostLists({
...params,
start_date,
end_date,
})
},
params: queryParams,
})
const handleQuery = () => {
pager.page = 1
getLists()
}
const onTimeTypeChange = () => handleTimeTypeChange(handleQuery)
const onCustomDateChange = () => handleCustomDateChange(handleQuery)
const mediaChannelOptionsFlat = computed<MediaChannelOption[]>(() => {
const options = pager.extend.media_channel_options
if (!Array.isArray(options)) return []
@@ -258,18 +282,27 @@ const handleDelete = async (id: number) => {
}
const handleReset = () => {
queryParams.start_date = ''
queryParams.end_date = ''
resetTimeFilter()
queryParams.media_channel_code = ''
queryParams.dept_id = ''
queryParams.remark = ''
resetPage()
pager.page = 1
pager.size = 15
getLists()
}
getLists()
onMounted(() => {
getLists()
})
</script>
<style scoped lang="scss">
.stats-filter-form {
:deep(.el-form-item) {
margin-bottom: 0;
}
}
.account-cost-channel-select {
:deep(.channel-opt-row) {
display: flex;
@@ -14,13 +14,14 @@
</el-card>
<el-card class="!border-none" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="日期范围">
<daterange-picker
v-model:startTime="queryParams.start_date"
v-model:endTime="queryParams.end_date"
/>
</el-form-item>
<el-form :inline="true" :model="queryParams" class="stats-filter-form">
<list-time-filter
v-model:time-type="time_type"
v-model:date-range="dateRange"
@time-type-change="onTimeTypeChange"
@custom-change="onCustomDateChange"
/>
<el-form-item label="部门">
<el-tree-select
v-model="queryParams.dept_id"
@@ -33,7 +34,7 @@
clearable
filterable
class="w-[220px]"
@change="resetPage"
@change="handleQuery"
/>
</el-form-item>
<el-form-item label="自媒体来源">
@@ -44,7 +45,7 @@
placeholder="全部来源"
:allow-create="false"
select-class="w-[220px]"
@change="resetPage"
@change="handleQuery"
@visible-change="onMediaSourceDropdownVisible"
/>
</el-form-item>
@@ -53,11 +54,11 @@
v-model="queryParams.remark"
placeholder="备注 / 创建人"
clearable
@keyup.enter="resetPage"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button type="primary" :loading="pager.loading" @click="handleQuery">查询</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button v-if="selfInputPath" class="ml-2" @click="goSelfInput">返回统计</el-button>
</el-form-item>
@@ -146,6 +147,8 @@ import feedback from '@/utils/feedback'
import CostEditPopup from './cost-edit.vue'
import MediaSourceSelect from './MediaSourceSelect.vue'
import { useMediaSourceOptions } from './useMediaSourceOptions'
import ListTimeFilter from '@/components/list-time-filter/index.vue'
import { useListTimeFilter } from '@/hooks/useListTimeFilter'
const router = useRouter()
const editRef = shallowRef<InstanceType<typeof CostEditPopup>>()
@@ -173,25 +176,48 @@ const goSelfInput = () => {
}
const queryParams = reactive({
start_date: '',
end_date: '',
media_source: '',
dept_id: undefined as number | undefined,
remark: '',
})
const {
time_type,
dateRange,
resolve,
handleTimeTypeChange,
handleCustomDateChange,
resetTimeFilter,
} = useListTimeFilter('today')
const { pager, getLists, resetPage } = usePaging({
fetchFun: personalAccountCostLists,
fetchFun: async (params: Record<string, any>) => {
const [start_date, end_date] = resolve()
return personalAccountCostLists({
...params,
start_date,
end_date,
})
},
params: queryParams,
})
const handleQuery = () => {
pager.page = 1
getLists()
}
const onTimeTypeChange = () => handleTimeTypeChange(handleQuery)
const onCustomDateChange = () => handleCustomDateChange(handleQuery)
const handleReset = () => {
queryParams.start_date = ''
queryParams.end_date = ''
resetTimeFilter()
queryParams.media_source = ''
queryParams.dept_id = undefined
queryParams.remark = ''
resetPage()
pager.page = 1
pager.size = 15
getLists()
}
const onMediaSourceDropdownVisible = (visible: boolean) => {
@@ -236,9 +262,10 @@ const loadDeptOptions = async () => {
}
}
onMounted(() => {
onMounted(async () => {
loadDeptOptions()
loadMediaSourceOptions()
await getLists()
})
</script>
@@ -247,6 +274,12 @@ onMounted(() => {
padding: 20px;
}
.stats-filter-form {
:deep(.el-form-item) {
margin-bottom: 0;
}
}
.dept-cell {
cursor: help;
border-bottom: 1px dashed #c0c4cc;