提交
This commit is contained in:
1 parent
575e63e7e8
commit
771f010a39
165 files changed
+67359
-21698
No files matched your search
@@ -22,9 +22,20 @@
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持模糊查询。</span>
|
||||
<span class="filter-hint">支持模糊查询;默认展示近 30 天内创建的客户。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"><el-icon><RefreshLeft /></el-icon>重置</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch"><el-icon><Search /></el-icon>搜索</el-button>
|
||||
@@ -239,7 +250,22 @@
|
||||
|
||||
defineOptions({ name: 'BizCustomer' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultCreateTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive<{ keyword: string }>({ keyword: '' })
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultCreateTimeRange())
|
||||
const tableData = ref<Api.BizCustomer.CustomerItem[]>([])
|
||||
const selectedRows = ref<Api.BizCustomer.CustomerItem[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -303,7 +329,9 @@
|
||||
const res = await fetchCustomerList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined
|
||||
keyword: searchForm.keyword || undefined,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -319,6 +347,7 @@
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
createTimeRange.value = getDefaultCreateTimeRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -412,7 +441,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -37,8 +37,20 @@
|
||||
<el-option label="已办保险" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="满月日期">
|
||||
<el-date-picker
|
||||
v-model="fullmoonDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持按协议号、姓名模糊检索;待办状态默认未办保险,满月日期默认近 30 天。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -481,10 +493,25 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageFullmoonTodo' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultFullmoonDateRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 搜索 & 主表
|
||||
// ---------------------------------------------------------------------------
|
||||
const searchForm = reactive({ keyword: '', todoStatus: '' })
|
||||
const searchForm = reactive({ keyword: '', todoStatus: '0' })
|
||||
const fullmoonDateRange = ref<[string, string] | null>(getDefaultFullmoonDateRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const tableRef = ref()
|
||||
const selectedRows = ref<any[]>([])
|
||||
@@ -615,7 +642,9 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
todoStatus: searchForm.todoStatus || undefined
|
||||
todoStatus: searchForm.todoStatus || undefined,
|
||||
fullmoonDateStart: fullmoonDateRange.value?.[0] || undefined,
|
||||
fullmoonDateEnd: fullmoonDateRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = (res as any)?.list || []
|
||||
pagination.total = (res as any)?.total ?? 0
|
||||
@@ -631,7 +660,8 @@
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.todoStatus = ''
|
||||
searchForm.todoStatus = '0'
|
||||
fullmoonDateRange.value = getDefaultFullmoonDateRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -1093,7 +1123,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, fullmoonDateRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -30,6 +30,45 @@
|
||||
<h2>缴费确认列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" label-position="top" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="协议号/客户姓名/身份证号/新生儿姓名/新生儿身份证号"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="应缴费时间">
|
||||
<el-date-picker
|
||||
v-model="installmentDueDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint"
|
||||
>支持协议号、客户姓名、身份证号、新生儿姓名、新生儿身份证号模糊检索;默认展示近 30 天内应缴费的明细。</span
|
||||
>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap payment-confirm-table-wrap">
|
||||
<el-table class="list-table" :data="tableData" v-loading="loading" stripe row-key="id" @row-dblclick="handleRowDblClick">
|
||||
<el-table-column
|
||||
@@ -230,7 +269,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Close, Check } from '@element-plus/icons-vue'
|
||||
import { Close, Check, RefreshLeft, Search } from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchReceiptConfirmList,
|
||||
fetchReceiptConfirmedList,
|
||||
@@ -256,6 +295,23 @@
|
||||
|
||||
defineOptions({ name: 'CellStoragePaymentConfirm' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultInstallmentDueDateRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '' })
|
||||
const installmentDueDateRange = ref<[string, string] | null>(getDefaultInstallmentDueDateRange())
|
||||
|
||||
const tabs = [
|
||||
{ key: 'pending', label: '待确认' },
|
||||
{ key: 'confirmed', label: '已确认' }
|
||||
@@ -311,10 +367,20 @@
|
||||
downloadAttachmentFile(file, { fullFileUrl })
|
||||
}
|
||||
|
||||
function buildListParams() {
|
||||
return {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
installmentDueDateStart: installmentDueDateRange.value?.[0] || undefined,
|
||||
installmentDueDateEnd: installmentDueDateRange.value?.[1] || undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = { page: pagination.page, pageSize: pagination.pageSize }
|
||||
const params = buildListParams()
|
||||
const res =
|
||||
activeTab.value === 'pending'
|
||||
? await fetchReceiptConfirmList(params)
|
||||
@@ -333,6 +399,18 @@
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
installmentDueDateRange.value = getDefaultInstallmentDueDateRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function openConfirm(row: Record<string, unknown>) {
|
||||
currentDetailId.value = String(row.id)
|
||||
confirmRow.value = row
|
||||
@@ -370,6 +448,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
watchDebounced(
|
||||
[searchForm, installmentDueDateRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
},
|
||||
{ debounce: 300, deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
@@ -404,6 +491,19 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-form :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.filter-form :deep(.el-form-item__label) {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
padding: 0 0 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.payment-confirm-table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -48,9 +48,20 @@
|
||||
<el-option label="现金" value="xj" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="应缴费时间">
|
||||
<el-date-picker
|
||||
v-model="installmentDueDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持按协议号模糊检索。</span>
|
||||
<span class="filter-hint">支持按协议号模糊检索;默认展示近 30 天内应缴费的明细。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -447,6 +458,20 @@
|
||||
|
||||
defineOptions({ name: 'CellStoragePaymentInfo' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultInstallmentDueDateRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const tabs = [
|
||||
{ key: 'dfj', label: '待缴费' },
|
||||
{ key: 'jfqrz', label: '缴费确认中' },
|
||||
@@ -457,6 +482,7 @@
|
||||
|
||||
const activeTab = ref('dfj')
|
||||
const searchForm = reactive({ keyword: '', transferType: '' })
|
||||
const installmentDueDateRange = ref<[string, string] | null>(getDefaultInstallmentDueDateRange())
|
||||
const tableData = ref<Record<string, unknown>[]>([])
|
||||
const selectedRows = ref<Record<string, unknown>[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -533,7 +559,9 @@
|
||||
pageSize: pagination.pageSize,
|
||||
payStatus: activeTab.value,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
transferType: searchForm.transferType || undefined
|
||||
transferType: searchForm.transferType || undefined,
|
||||
installmentDueDateStart: installmentDueDateRange.value?.[0] || undefined,
|
||||
installmentDueDateEnd: installmentDueDateRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -713,12 +741,13 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.transferType = ''
|
||||
installmentDueDateRange.value = getDefaultInstallmentDueDateRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, installmentDueDateRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -32,9 +32,32 @@
|
||||
<el-option label="转科研" value="zky" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="样本采集时间">
|
||||
<el-date-picker
|
||||
v-model="sampleCollectTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗。</span>
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗;默认展示近 30 天内创建的协议单。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"
|
||||
><el-icon><RefreshLeft /></el-icon>重置</el-button
|
||||
@@ -326,11 +349,27 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageProtocolAudit' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultCreateTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
/* ====== 列表 ====== */
|
||||
const searchForm = reactive<{ keyword: string; protocolStatus: string }>({
|
||||
keyword: '',
|
||||
protocolStatus: ''
|
||||
})
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultCreateTimeRange())
|
||||
const sampleCollectTimeRange = ref<[string, string] | null>(null)
|
||||
const tableData = ref<CollectionProtocolRow[]>([])
|
||||
const selectedRows = ref<CollectionProtocolRow[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -347,7 +386,11 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
protocolStatus: searchForm.protocolStatus || undefined
|
||||
protocolStatus: searchForm.protocolStatus || undefined,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined,
|
||||
sampleCollectTimeStart: sampleCollectTimeRange.value?.[0] || undefined,
|
||||
sampleCollectTimeEnd: sampleCollectTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -364,6 +407,8 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.protocolStatus = ''
|
||||
createTimeRange.value = getDefaultCreateTimeRange()
|
||||
sampleCollectTimeRange.value = null
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -485,7 +530,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange, sampleCollectTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -32,9 +32,32 @@
|
||||
<el-option label="转科研" value="zky" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="样本采集时间">
|
||||
<el-date-picker
|
||||
v-model="sampleCollectTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗。</span>
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗;默认展示近 30 天内创建的协议单。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"
|
||||
><el-icon><RefreshLeft /></el-icon>重置</el-button
|
||||
@@ -284,11 +307,27 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageProtocol' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultCreateTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
/* ====== 列表 ====== */
|
||||
const searchForm = reactive<{ keyword: string; protocolStatus: string }>({
|
||||
keyword: '',
|
||||
protocolStatus: ''
|
||||
})
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultCreateTimeRange())
|
||||
const sampleCollectTimeRange = ref<[string, string] | null>(null)
|
||||
const tableData = ref<CollectionProtocolRow[]>([])
|
||||
const selectedRows = ref<CollectionProtocolRow[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -305,7 +344,11 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
protocolStatus: searchForm.protocolStatus || undefined
|
||||
protocolStatus: searchForm.protocolStatus || undefined,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined,
|
||||
sampleCollectTimeStart: sampleCollectTimeRange.value?.[0] || undefined,
|
||||
sampleCollectTimeEnd: sampleCollectTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -322,6 +365,8 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.protocolStatus = ''
|
||||
createTimeRange.value = getDefaultCreateTimeRange()
|
||||
sampleCollectTimeRange.value = null
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -391,7 +436,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange, sampleCollectTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -30,6 +30,45 @@
|
||||
<h2>退费确认列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" label-position="top" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="协议号/客户姓名/身份证号/新生儿姓名/新生儿身份证号"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="应缴费时间">
|
||||
<el-date-picker
|
||||
v-model="installmentDueDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint"
|
||||
>支持协议号、客户姓名、身份证号、新生儿姓名、新生儿身份证号模糊检索;默认展示近 30 天内应缴费的明细。</span
|
||||
>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap refund-confirm-table-wrap">
|
||||
<el-table class="list-table" :data="tableData" v-loading="loading" stripe row-key="id" @row-dblclick="handleRowDblClick">
|
||||
<el-table-column
|
||||
@@ -247,7 +286,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Close, Check } from '@element-plus/icons-vue'
|
||||
import { Close, Check, RefreshLeft, Search } from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchRefundConfirmList,
|
||||
fetchRefundConfirmedList,
|
||||
@@ -273,6 +312,23 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageRefundConfirm' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultInstallmentDueDateRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '' })
|
||||
const installmentDueDateRange = ref<[string, string] | null>(getDefaultInstallmentDueDateRange())
|
||||
|
||||
const tabs = [
|
||||
{ key: 'pending', label: '待确认' },
|
||||
{ key: 'confirmed', label: '已确认' }
|
||||
@@ -328,10 +384,20 @@
|
||||
downloadAttachmentFile(file, { fullFileUrl })
|
||||
}
|
||||
|
||||
function buildListParams() {
|
||||
return {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
installmentDueDateStart: installmentDueDateRange.value?.[0] || undefined,
|
||||
installmentDueDateEnd: installmentDueDateRange.value?.[1] || undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = { page: pagination.page, pageSize: pagination.pageSize }
|
||||
const params = buildListParams()
|
||||
const res =
|
||||
activeTab.value === 'pending'
|
||||
? await fetchRefundConfirmList(params)
|
||||
@@ -350,6 +416,18 @@
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
installmentDueDateRange.value = getDefaultInstallmentDueDateRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function openConfirm(row: Record<string, unknown>) {
|
||||
currentDetailId.value = String(row.id)
|
||||
confirmRow.value = row
|
||||
@@ -387,6 +465,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
watchDebounced(
|
||||
[searchForm, installmentDueDateRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
},
|
||||
{ debounce: 300, deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
@@ -421,6 +508,19 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-form :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.filter-form :deep(.el-form-item__label) {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
padding: 0 0 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.refund-confirm-table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,20 @@
|
||||
<el-option label="未通知" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="接收时间">
|
||||
<el-date-picker
|
||||
v-model="receptionTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持按协议号、姓名、样本编码模糊检索;默认展示近 30 天内接收的样本。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -155,7 +167,22 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageSampleReceptionInfo' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultReceptionTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', acceptConclusion: '', smsNotified: '' })
|
||||
const receptionTimeRange = ref<[string, string] | null>(getDefaultReceptionTimeRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
@@ -174,7 +201,9 @@
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
acceptConclusion: searchForm.acceptConclusion || undefined,
|
||||
smsNotified: searchForm.smsNotified || undefined
|
||||
smsNotified: searchForm.smsNotified || undefined,
|
||||
receptionTimeStart: receptionTimeRange.value?.[0] || undefined,
|
||||
receptionTimeEnd: receptionTimeRange.value?.[1] || undefined
|
||||
})
|
||||
const res = (result as any) || {}
|
||||
tableData.value = res.list || []
|
||||
@@ -191,6 +220,7 @@
|
||||
|
||||
function handleReset() {
|
||||
Object.assign(searchForm, { keyword: '', acceptConclusion: '', smsNotified: '' })
|
||||
receptionTimeRange.value = getDefaultReceptionTimeRange()
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
@@ -240,7 +270,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, receptionTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -24,8 +24,20 @@
|
||||
<el-option label="已制作" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="入库日期">
|
||||
<el-date-picker
|
||||
v-model="storageInDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持按协议号、姓名模糊检索;制作状态默认未制作,入库日期默认近 30 天。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -317,10 +329,25 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageStorageCert' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultStorageInDateRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 搜索 & 主表
|
||||
// ---------------------------------------------------------------------------
|
||||
const searchForm = reactive({ keyword: '', makeStatus: '' })
|
||||
const searchForm = reactive({ keyword: '', makeStatus: '0' })
|
||||
const storageInDateRange = ref<[string, string] | null>(getDefaultStorageInDateRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
@@ -393,7 +420,9 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
makeStatus: searchForm.makeStatus || undefined
|
||||
makeStatus: searchForm.makeStatus || undefined,
|
||||
storageInDateStart: storageInDateRange.value?.[0] || undefined,
|
||||
storageInDateEnd: storageInDateRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = (res as any)?.list || []
|
||||
pagination.total = (res as any)?.total ?? 0
|
||||
@@ -409,7 +438,8 @@
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.makeStatus = ''
|
||||
searchForm.makeStatus = '0'
|
||||
storageInDateRange.value = getDefaultStorageInDateRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -593,7 +623,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, storageInDateRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -30,8 +30,20 @@
|
||||
<el-option label="未通知" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="入库时间">
|
||||
<el-date-picker
|
||||
v-model="storageTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持按协议号、姓名、样本编码模糊检索;默认展示近 30 天内入库的样本。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -161,7 +173,22 @@
|
||||
|
||||
defineOptions({ name: 'CellStorageStorageEntryInfo' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultStorageTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', storageStatus: '', smsNotified: '' })
|
||||
const storageTimeRange = ref<[string, string] | null>(getDefaultStorageTimeRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
@@ -180,7 +207,9 @@
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
storageStatus: searchForm.storageStatus || undefined,
|
||||
smsNotified: searchForm.smsNotified || undefined
|
||||
smsNotified: searchForm.smsNotified || undefined,
|
||||
storageTimeStart: storageTimeRange.value?.[0] || undefined,
|
||||
storageTimeEnd: storageTimeRange.value?.[1] || undefined
|
||||
})
|
||||
const res = (result as any) || {}
|
||||
tableData.value = res.list || []
|
||||
@@ -197,6 +226,7 @@
|
||||
|
||||
function handleReset() {
|
||||
Object.assign(searchForm, { keyword: '', storageStatus: '', smsNotified: '' })
|
||||
storageTimeRange.value = getDefaultStorageTimeRange()
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
@@ -246,7 +276,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, storageTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -18,9 +18,20 @@
|
||||
<el-form-item label="关键词">
|
||||
<el-input v-model="searchForm.keyword" placeholder="预约编号/来访单位/联系人" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="到访日期">
|
||||
<el-date-picker
|
||||
v-model="visitDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">按预约编号、来访单位、联系人模糊查询。</span>
|
||||
<span class="filter-hint">按预约编号、来访单位、联系人模糊查询;默认展示未来 30 天内的到访预约。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"><el-icon><RefreshLeft /></el-icon>重置</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch"><el-icon><Search /></el-icon>搜索</el-button>
|
||||
@@ -190,7 +201,22 @@
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultVisitDateRange(): [string, string] {
|
||||
const start = new Date()
|
||||
const end = new Date()
|
||||
end.setDate(end.getDate() + 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive<{ keyword: string }>({ keyword: '' })
|
||||
const visitDateRange = ref<[string, string] | null>(getDefaultVisitDateRange())
|
||||
const tableData = ref<AppointmentRow[]>([])
|
||||
const selectedRows = ref<AppointmentRow[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -245,7 +271,9 @@
|
||||
const res = await fetchExhibitionAppointmentList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined
|
||||
keyword: searchForm.keyword || undefined,
|
||||
visitDateStart: visitDateRange.value?.[0] || undefined,
|
||||
visitDateEnd: visitDateRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -261,6 +289,7 @@
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
visitDateRange.value = getDefaultVisitDateRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -350,7 +379,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, visitDateRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -37,9 +37,20 @@
|
||||
<el-option label="退订产品" value="unsubscribe" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint"></span>
|
||||
<span class="filter-hint">默认展示近 30 天内创建的流水。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -391,7 +402,22 @@
|
||||
done: ['yqr']
|
||||
}
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultLast30DaysRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const activeTab = ref('pending')
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const searchForm = reactive({
|
||||
txnType: '' as string,
|
||||
txnStatus: ['dqr'] as string[],
|
||||
@@ -418,6 +444,8 @@
|
||||
params.txnStatus = searchForm.txnStatus.join(',')
|
||||
}
|
||||
if (searchForm.keyword.trim()) params.keyword = searchForm.keyword.trim()
|
||||
if (createTimeRange.value?.[0]) params.createTimeStart = createTimeRange.value[0]
|
||||
if (createTimeRange.value?.[1]) params.createTimeEnd = createTimeRange.value[1]
|
||||
|
||||
const res: any = await fetchServiceOrderTxnList(params)
|
||||
tableData.value = res?.data?.list || res?.list || []
|
||||
@@ -438,6 +466,7 @@
|
||||
searchForm.txnType = ''
|
||||
searchForm.txnStatus = [...TAB_STATUS_MAP[activeTab.value]]
|
||||
searchForm.keyword = ''
|
||||
createTimeRange.value = getDefaultLast30DaysRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -453,7 +482,7 @@
|
||||
|
||||
// 检索条件变更时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -45,9 +45,20 @@
|
||||
<el-option label="已作废" value="yzf" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">渠道名称输入后自动检索;订单类型、状态变更后亦会自动刷新列表。</span>
|
||||
<span class="filter-hint">默认展示近 30 天内创建的订单;渠道名称输入后自动检索。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -728,6 +739,22 @@ const formatProjectOptionLabel = (p: any) => {
|
||||
}
|
||||
|
||||
// ── 搜索 ──────────────────────────────────────────────────────────────
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultLast30DaysRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
|
||||
const searchForm = reactive<{
|
||||
orderType: string
|
||||
orderStatus: string[]
|
||||
@@ -758,6 +785,8 @@ const loadData = async () => {
|
||||
if (searchForm.orderType) params.orderType = searchForm.orderType
|
||||
if (searchForm.orderStatus.length) params.orderStatus = searchForm.orderStatus.join(',')
|
||||
if (searchForm.keyword) params.keyword = searchForm.keyword
|
||||
if (createTimeRange.value?.[0]) params.createTimeStart = createTimeRange.value[0]
|
||||
if (createTimeRange.value?.[1]) params.createTimeEnd = createTimeRange.value[1]
|
||||
|
||||
const res: any = await fetchChannelServiceOrderList(params)
|
||||
const data = res?.data ?? res
|
||||
@@ -779,13 +808,14 @@ const handleReset = () => {
|
||||
searchForm.orderType = ''
|
||||
searchForm.orderStatus = []
|
||||
searchForm.keyword = ''
|
||||
createTimeRange.value = getDefaultLast30DaysRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
// 检索条件变更时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,651 @@
|
||||
<!-- 中试服务申请单列表页 -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>中试服务申请单</h1>
|
||||
<p class="page-desc">管理中试服务申请单的创建、审批、状态流转,关联渠道服务订单与患者信息。</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">中试服务申请单</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="申请单号">
|
||||
<el-input
|
||||
v-model="searchForm.applicationNo"
|
||||
placeholder="请输入申请单号"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="渠道">
|
||||
<el-select
|
||||
v-model="searchForm.channelId"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
filterable
|
||||
:loading="channelLoading"
|
||||
@focus="onChannelSelectFocus"
|
||||
@change="handleSearchChannelChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="ch in channelOptions"
|
||||
:key="ch.id"
|
||||
:label="ch.channelName || ch.name"
|
||||
:value="ch.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务订单">
|
||||
<el-select
|
||||
v-model="searchForm.channelServiceOrderId"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
filterable
|
||||
:disabled="!searchForm.channelId"
|
||||
:loading="serviceOrderLoading"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<el-option
|
||||
v-for="so in serviceOrderOptions"
|
||||
:key="so.id"
|
||||
:label="formatServiceOrderLabel(so)"
|
||||
:value="so.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<div class="status-filter-group">
|
||||
<el-button
|
||||
v-for="item in statusFilters"
|
||||
:key="item.value"
|
||||
:type="activeStatus === item.value ? 'primary' : 'default'"
|
||||
size="default"
|
||||
@click="handleStatusFilter(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-toolbar">
|
||||
<div class="list-toolbar-row">
|
||||
<el-button class="btn-main" type="primary" @click="handleCreate">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
@row-dblclick="handleView"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="index => (pagination.page - 1) * pagination.pageSize + index + 1"
|
||||
/>
|
||||
<el-table-column prop="applicationNo" label="申请单号" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="handleView(row)">
|
||||
{{ row.applicationNo || '-' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="channelName" label="渠道名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="关联服务订单" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.serviceOrderNo">{{ row.serviceOrderNo }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="patientName" label="患者姓名" min-width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.patientName || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="infusionPlanCount" label="输注方案数" min-width="100" align="center">
|
||||
<template #default="{ row }">{{ row.infusionPlanCount ?? 0 }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="applicationStatus" label="状态" min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="applicationStatusTagType(row.applicationStatus)" size="small">
|
||||
{{ applicationStatusLabel(row.applicationStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="160" align="center" />
|
||||
<el-table-column label="操作" min-width="280" fixed="right" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item primary" @click="handleView(row)">查看</el-button>
|
||||
<el-button
|
||||
v-if="row.applicationStatus === 'dks'"
|
||||
class="btn-op-item"
|
||||
@click="handleEdit(row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-popconfirm
|
||||
v-if="row.applicationStatus === 'dks'"
|
||||
title="确定删除该申请单吗?"
|
||||
confirm-button-text="确定"
|
||||
cancel-button-text="取消"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button class="btn-op-item op-warn">删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-button
|
||||
v-if="row.applicationStatus === 'dks'"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="handleStart(row)"
|
||||
>
|
||||
开始
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.applicationStatus === 'dks'"
|
||||
class="btn-op-item op-warn"
|
||||
type="danger"
|
||||
@click="handleVoid(row)"
|
||||
>
|
||||
作废
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.applicationStatus === 'jxz'"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="handleComplete(row)"
|
||||
>
|
||||
完成
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.applicationStatus === 'jxz'"
|
||||
class="btn-op-item op-warn"
|
||||
type="danger"
|
||||
@click="handleVoid(row)"
|
||||
>
|
||||
作废
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@update:current-page="val => (pagination.page = val)"
|
||||
@update:page-size="val => (pagination.pageSize = val)"
|
||||
@size-change="loadData"
|
||||
@current-change="loadData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 新增申请单弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="新增中试服务申请单"
|
||||
width="600px"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<div class="dialog-form-layout">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-position="top"
|
||||
class="dialog-form"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="渠道" prop="channelId">
|
||||
<el-select
|
||||
v-model="formData.channelId"
|
||||
placeholder="请选择渠道"
|
||||
filterable
|
||||
clearable
|
||||
:loading="dialogChannelLoading"
|
||||
@focus="onDialogChannelFocus"
|
||||
@change="handleDialogChannelChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="ch in dialogChannelOptions"
|
||||
:key="ch.id"
|
||||
:label="ch.channelName || ch.name"
|
||||
:value="ch.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务订单" prop="channelServiceOrderId">
|
||||
<el-select
|
||||
v-model="formData.channelServiceOrderId"
|
||||
placeholder="请先选择渠道,再选择服务订单"
|
||||
filterable
|
||||
clearable
|
||||
:disabled="!formData.channelId"
|
||||
:loading="dialogServiceOrderLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="so in dialogServiceOrderOptions"
|
||||
:key="so.id"
|
||||
:label="formatServiceOrderLabel(so)"
|
||||
:value="so.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
<el-input
|
||||
v-model="formData.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入备注"
|
||||
:rows="3"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="dialogVisible = false">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||||
import {
|
||||
Plus,
|
||||
Search,
|
||||
RefreshLeft,
|
||||
Close,
|
||||
Check,
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchPilotApplicationList,
|
||||
createPilotApplication,
|
||||
deletePilotApplication,
|
||||
startPilotApplication,
|
||||
completePilotApplication,
|
||||
voidPilotApplication,
|
||||
fetchChannelList,
|
||||
fetchChannelServiceOrderList,
|
||||
} from '@/api/admin'
|
||||
import {
|
||||
applicationStatusLabel,
|
||||
applicationStatusTagType,
|
||||
channelServiceOrderTypeLabel,
|
||||
} from '@/utils/status-tag-registry'
|
||||
|
||||
defineOptions({ name: 'PilotApplicationManagement' })
|
||||
|
||||
// ── 工具函数 ──────────────────────────────────────────────────────────
|
||||
const displayValue = (v: any): string => {
|
||||
if (v == null || v === '' || v === undefined) return '-'
|
||||
return String(v)
|
||||
}
|
||||
|
||||
const formatServiceOrderLabel = (so: any) => {
|
||||
const no = so.orderNo || so.id || ''
|
||||
const typeLabel = channelServiceOrderTypeLabel(so.orderType)
|
||||
return `${no}(${typeLabel})`
|
||||
}
|
||||
|
||||
const unwrapApiList = (res: any): any[] => {
|
||||
const d = res?.data ?? res
|
||||
if (Array.isArray(d)) return d
|
||||
return d?.list ?? d?.records ?? []
|
||||
}
|
||||
|
||||
// ── 状态筛选 ──────────────────────────────────────────────────────────
|
||||
const statusFilters = [
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '待开始', value: 'dks' },
|
||||
{ label: '进行中', value: 'jxz' },
|
||||
{ label: '已完成', value: 'ywc' },
|
||||
{ label: '已作废', value: 'yzf' },
|
||||
]
|
||||
const activeStatus = ref('')
|
||||
|
||||
const handleStatusFilter = (val: string) => {
|
||||
activeStatus.value = val
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
// ── 搜索 ──────────────────────────────────────────────────────────────
|
||||
const searchForm = reactive({
|
||||
applicationNo: '',
|
||||
channelId: '',
|
||||
channelServiceOrderId: '',
|
||||
})
|
||||
|
||||
// ── 搜索区域渠道下拉 ──────────────────────────────────────────────────
|
||||
const channelOptions = ref<any[]>([])
|
||||
const channelLoading = ref(false)
|
||||
const channelLoaded = ref(false)
|
||||
|
||||
const onChannelSelectFocus = () => {
|
||||
if (!channelLoaded.value) {
|
||||
loadChannelOptions()
|
||||
}
|
||||
}
|
||||
|
||||
const loadChannelOptions = async () => {
|
||||
channelLoading.value = true
|
||||
try {
|
||||
const res: any = await fetchChannelList({ page: 1, pageSize: 200 })
|
||||
channelOptions.value = unwrapApiList(res)
|
||||
channelLoaded.value = true
|
||||
} catch {
|
||||
channelOptions.value = []
|
||||
} finally {
|
||||
channelLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ── 搜索区域服务订单下拉(联动渠道) ──────────────────────────────────
|
||||
const serviceOrderOptions = ref<any[]>([])
|
||||
const serviceOrderLoading = ref(false)
|
||||
|
||||
const handleSearchChannelChange = () => {
|
||||
searchForm.channelServiceOrderId = ''
|
||||
serviceOrderOptions.value = []
|
||||
if (searchForm.channelId) {
|
||||
loadSearchServiceOrders(searchForm.channelId)
|
||||
}
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
const loadSearchServiceOrders = async (channelId: string) => {
|
||||
serviceOrderLoading.value = true
|
||||
try {
|
||||
const res: any = await fetchChannelServiceOrderList({
|
||||
channelId,
|
||||
page: 1,
|
||||
pageSize: 200,
|
||||
})
|
||||
serviceOrderOptions.value = unwrapApiList(res)
|
||||
} catch {
|
||||
serviceOrderOptions.value = []
|
||||
} finally {
|
||||
serviceOrderLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ── 表格 ──────────────────────────────────────────────────────────────
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: Record<string, any> = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
if (searchForm.applicationNo) params.applicationNo = searchForm.applicationNo
|
||||
if (searchForm.channelId) params.channelId = searchForm.channelId
|
||||
if (searchForm.channelServiceOrderId) params.channelServiceOrderId = searchForm.channelServiceOrderId
|
||||
if (activeStatus.value) params.applicationStatus = activeStatus.value
|
||||
|
||||
const res: any = await fetchPilotApplicationList(params)
|
||||
const data = res?.data ?? res
|
||||
tableData.value = data?.list ?? data?.records ?? []
|
||||
pagination.total = data?.total ?? 0
|
||||
} catch (e) {
|
||||
console.error('加载申请单列表失败:', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
searchForm.applicationNo = ''
|
||||
searchForm.channelId = ''
|
||||
searchForm.channelServiceOrderId = ''
|
||||
activeStatus.value = ''
|
||||
serviceOrderOptions.value = []
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
// ── 查看详情 ──────────────────────────────────────────────────────────
|
||||
const router = useRouter()
|
||||
|
||||
const handleView = (row: any) => {
|
||||
router.push({ name: 'PilotApplicationDetail', query: { id: row.id } })
|
||||
}
|
||||
|
||||
// ── 新增弹窗 ──────────────────────────────────────────────────────────
|
||||
const dialogVisible = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const initFormData = () => ({
|
||||
channelId: '',
|
||||
channelServiceOrderId: '',
|
||||
remark: '',
|
||||
})
|
||||
|
||||
const formData = reactive(initFormData())
|
||||
|
||||
const formRules: FormRules = {
|
||||
channelId: [{ required: true, message: '请选择渠道', trigger: 'change' }],
|
||||
channelServiceOrderId: [{ required: true, message: '请选择服务订单', trigger: 'change' }],
|
||||
}
|
||||
|
||||
// ── 弹窗渠道下拉 ──────────────────────────────────────────────────────
|
||||
const dialogChannelOptions = ref<any[]>([])
|
||||
const dialogChannelLoading = ref(false)
|
||||
const dialogChannelLoaded = ref(false)
|
||||
|
||||
const onDialogChannelFocus = () => {
|
||||
if (!dialogChannelLoaded.value) {
|
||||
loadDialogChannelOptions()
|
||||
}
|
||||
}
|
||||
|
||||
const loadDialogChannelOptions = async () => {
|
||||
dialogChannelLoading.value = true
|
||||
try {
|
||||
const res: any = await fetchChannelList({ page: 1, pageSize: 200 })
|
||||
dialogChannelOptions.value = unwrapApiList(res)
|
||||
dialogChannelLoaded.value = true
|
||||
} catch {
|
||||
dialogChannelOptions.value = []
|
||||
} finally {
|
||||
dialogChannelLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ── 弹窗服务订单下拉(联动渠道) ──────────────────────────────────────
|
||||
const dialogServiceOrderOptions = ref<any[]>([])
|
||||
const dialogServiceOrderLoading = ref(false)
|
||||
|
||||
const handleDialogChannelChange = async (channelId: string) => {
|
||||
formData.channelServiceOrderId = ''
|
||||
dialogServiceOrderOptions.value = []
|
||||
if (!channelId) return
|
||||
dialogServiceOrderLoading.value = true
|
||||
try {
|
||||
const res: any = await fetchChannelServiceOrderList({
|
||||
channelId,
|
||||
page: 1,
|
||||
pageSize: 200,
|
||||
})
|
||||
dialogServiceOrderOptions.value = unwrapApiList(res)
|
||||
} catch {
|
||||
dialogServiceOrderOptions.value = []
|
||||
} finally {
|
||||
dialogServiceOrderLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreate = () => {
|
||||
Object.assign(formData, initFormData())
|
||||
dialogChannelLoaded.value = false
|
||||
dialogChannelOptions.value = []
|
||||
dialogServiceOrderOptions.value = []
|
||||
dialogVisible.value = true
|
||||
void loadDialogChannelOptions()
|
||||
}
|
||||
|
||||
const handleDialogClose = () => {
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const res: any = await createPilotApplication({
|
||||
channelServiceOrderId: formData.channelServiceOrderId,
|
||||
remark: formData.remark,
|
||||
})
|
||||
dialogVisible.value = false
|
||||
ElMessage.success('创建成功')
|
||||
// 跳转详情页
|
||||
const data = res?.data ?? res
|
||||
const newId = data?.id || data?.pilotApplicationId || data
|
||||
if (newId) {
|
||||
router.push({ name: 'PilotApplicationDetail', query: { id: newId } })
|
||||
} else {
|
||||
loadData()
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || '创建失败')
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ── 编辑 ──────────────────────────────────────────────────────────────
|
||||
const handleEdit = (row: any) => {
|
||||
// Phase 1 编辑仅修改备注,直接跳详情页
|
||||
router.push({ name: 'PilotApplicationDetail', query: { id: row.id } })
|
||||
}
|
||||
|
||||
// ── 删除 ──────────────────────────────────────────────────────────────
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await deletePilotApplication({ id: row.id })
|
||||
ElMessage.success('删除成功')
|
||||
loadData()
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || '删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
// ── 状态操作 ──────────────────────────────────────────────────────────
|
||||
const handleStart = async (row: any) => {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定开始该申请单吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info',
|
||||
})
|
||||
await startPilotApplication({ id: row.id })
|
||||
ElMessage.success('操作成功')
|
||||
loadData()
|
||||
} catch (e: any) {
|
||||
if (e !== 'cancel') {
|
||||
ElMessage.error(e?.message || '操作失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleComplete = async (row: any) => {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定完成该申请单吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info',
|
||||
})
|
||||
await completePilotApplication({ id: row.id })
|
||||
ElMessage.success('操作成功')
|
||||
loadData()
|
||||
} catch (e: any) {
|
||||
if (e !== 'cancel') {
|
||||
ElMessage.error(e?.message || '操作失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleVoid = async (row: any) => {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定作废该申请单吗?作废后不可恢复。', '提示', {
|
||||
confirmButtonText: '确定作废',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
await voidPilotApplication({ id: row.id })
|
||||
ElMessage.success('操作成功')
|
||||
loadData()
|
||||
} catch (e: any) {
|
||||
if (e !== 'cancel') {
|
||||
ElMessage.error(e?.message || '操作失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 初始化 ────────────────────────────────────────────────────────────
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.status-filter-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -24,8 +24,20 @@
|
||||
<el-option label="已完成" value="ywc" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始时间">
|
||||
<el-date-picker
|
||||
v-model="startedTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">默认展示近 30 天内已开始的任务;清空日期可查看尚未开始的待配置任务。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"><el-icon><RefreshLeft /></el-icon>重置</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch"><el-icon><Search /></el-icon>搜索</el-button>
|
||||
@@ -325,7 +337,22 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// 列表视图
|
||||
// ---------------------------------------------------------------------------
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultLast30DaysRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', taskStatus: '' })
|
||||
const startedTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const tableData = ref<Record<string, any>[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
@@ -344,7 +371,9 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
taskStatus: searchForm.taskStatus || undefined
|
||||
taskStatus: searchForm.taskStatus || undefined,
|
||||
startedTimeStart: startedTimeRange.value?.[0] || undefined,
|
||||
startedTimeEnd: startedTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -361,6 +390,7 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.taskStatus = ''
|
||||
startedTimeRange.value = getDefaultLast30DaysRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -400,7 +430,7 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, startedTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -40,8 +40,20 @@
|
||||
<el-option label="已完成" value="ywc" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">默认展示近 30 天内创建的工单。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"
|
||||
><el-icon><RefreshLeft /></el-icon>重置</el-button
|
||||
@@ -519,7 +531,22 @@
|
||||
return map[source] || { label: source, type: 'info' }
|
||||
}
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultLast30DaysRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', workOrderStatus: '' })
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const workOrderListTableRef = ref<TableInstance>()
|
||||
const loading = ref(false)
|
||||
@@ -544,7 +571,9 @@
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
workOrderStatus: searchForm.workOrderStatus || undefined,
|
||||
workOrderType: activeTypeTab.value === 'all' ? undefined : activeTypeTab.value
|
||||
workOrderType: activeTypeTab.value === 'all' ? undefined : activeTypeTab.value,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -560,6 +589,7 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.workOrderStatus = ''
|
||||
createTimeRange.value = getDefaultLast30DaysRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -782,7 +812,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -35,8 +35,20 @@
|
||||
<el-option label="已完成" value="ywc" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">默认展示近 30 天内创建的工单。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"><el-icon><RefreshLeft /></el-icon>重置</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch"><el-icon><Search /></el-icon>搜索</el-button>
|
||||
@@ -575,7 +587,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultLast30DaysRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', workOrderStatus: '' })
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const tableData = ref<QcWorkOrder[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
@@ -929,7 +956,9 @@
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
workOrderStatus: searchForm.workOrderStatus || undefined,
|
||||
workOrderType: activeTypeTab.value === 'all' ? undefined : activeTypeTab.value
|
||||
workOrderType: activeTypeTab.value === 'all' ? undefined : activeTypeTab.value,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -945,6 +974,7 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.workOrderStatus = ''
|
||||
createTimeRange.value = getDefaultLast30DaysRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -1015,7 +1045,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -46,13 +46,35 @@
|
||||
<el-option label="科研捐赠" value="research_donation" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeTab === 'pending'" label="预计到达时间">
|
||||
<el-date-picker
|
||||
v-model="etaDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-else label="接收时间">
|
||||
<el-date-picker
|
||||
v-model="receptionTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">
|
||||
{{
|
||||
activeTab === 'pending'
|
||||
? '勾选多个样本后可批量接收(同快递可一次登记,每项单独填写)。'
|
||||
: '双击行可查看接收详情;也可点击「编辑」修改接收登记。'
|
||||
? '勾选多个样本后可批量接收;预计到达时间默认近 30 天。'
|
||||
: '双击行可查看接收详情;接收时间默认近 30 天。'
|
||||
}}
|
||||
</span>
|
||||
<div class="filter-actions-end">
|
||||
@@ -607,6 +629,23 @@
|
||||
|
||||
const activeTab = ref('pending')
|
||||
const searchForm = reactive({ keyword: '', sourceType: '' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultLast30DaysRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const etaDateRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const receptionTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const tableData = ref<Record<string, unknown>[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
@@ -1027,16 +1066,24 @@
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
const baseParams = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
sourceType: searchForm.sourceType || undefined,
|
||||
sourceType: searchForm.sourceType || undefined
|
||||
}
|
||||
const res =
|
||||
activeTab.value === 'pending'
|
||||
? await fetchSampleReceptionPendingList(params)
|
||||
: await fetchSampleReceptionReceivedList(params)
|
||||
? await fetchSampleReceptionPendingList({
|
||||
...baseParams,
|
||||
etaTimeStart: etaDateRange.value?.[0] || undefined,
|
||||
etaTimeEnd: etaDateRange.value?.[1] || undefined
|
||||
})
|
||||
: await fetchSampleReceptionReceivedList({
|
||||
...baseParams,
|
||||
receptionTimeStart: receptionTimeRange.value?.[0] || undefined,
|
||||
receptionTimeEnd: receptionTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
} finally {
|
||||
@@ -1060,6 +1107,11 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.sourceType = ''
|
||||
if (activeTab.value === 'pending') {
|
||||
etaDateRange.value = getDefaultLast30DaysRange()
|
||||
} else {
|
||||
receptionTimeRange.value = getDefaultLast30DaysRange()
|
||||
}
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -1196,7 +1248,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, etaDateRange, receptionTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<!-- 捐赠协议审核 -->
|
||||
<!-- 捐赠协议管理 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>捐赠协议审核</h1>
|
||||
<p class="page-desc">审核与管理科研捐赠协议数据。</p>
|
||||
<h1>捐赠协议管理</h1>
|
||||
<p class="page-desc">管理科研捐赠协议数据,含审核与状态变更。</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
@@ -32,9 +32,32 @@
|
||||
<el-option label="转细胞存储" value="zckc" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="样本采集时间">
|
||||
<el-date-picker
|
||||
v-model="sampleCollectTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗。</span>
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗;默认展示近 30 天内创建的协议单。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"
|
||||
><el-icon><RefreshLeft /></el-icon>重置</el-button
|
||||
@@ -343,11 +366,27 @@
|
||||
|
||||
defineOptions({ name: 'ResearchDonationAudit' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultCreateTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
/* ====== 列表 ====== */
|
||||
const searchForm = reactive<{ keyword: string; donationStatus: string }>({
|
||||
keyword: '',
|
||||
donationStatus: ''
|
||||
})
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultCreateTimeRange())
|
||||
const sampleCollectTimeRange = ref<[string, string] | null>(null)
|
||||
const tableData = ref<ResearchDonationRow[]>([])
|
||||
const selectedRows = ref<ResearchDonationRow[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -364,7 +403,11 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
donationStatus: searchForm.donationStatus || undefined
|
||||
donationStatus: searchForm.donationStatus || undefined,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined,
|
||||
sampleCollectTimeStart: sampleCollectTimeRange.value?.[0] || undefined,
|
||||
sampleCollectTimeEnd: sampleCollectTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -381,6 +424,8 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.donationStatus = ''
|
||||
createTimeRange.value = getDefaultCreateTimeRange()
|
||||
sampleCollectTimeRange.value = null
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -496,7 +541,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange, sampleCollectTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
@@ -32,9 +32,32 @@
|
||||
<el-option label="转细胞存储" value="zckc" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="createTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="样本采集时间">
|
||||
<el-date-picker
|
||||
v-model="sampleCollectTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗。</span>
|
||||
<span class="filter-hint">列表为概要信息,详情见弹窗;默认展示近 30 天内创建的协议单。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset"
|
||||
><el-icon><RefreshLeft /></el-icon>重置</el-button
|
||||
@@ -280,11 +303,27 @@
|
||||
|
||||
defineOptions({ name: 'ResearchDonationList' })
|
||||
|
||||
function formatLocalDate(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}`
|
||||
}
|
||||
|
||||
function getDefaultCreateTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
/* ====== 列表 ====== */
|
||||
const searchForm = reactive<{ keyword: string; donationStatus: string }>({
|
||||
keyword: '',
|
||||
donationStatus: ''
|
||||
})
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultCreateTimeRange())
|
||||
const sampleCollectTimeRange = ref<[string, string] | null>(null)
|
||||
const tableData = ref<ResearchDonationRow[]>([])
|
||||
const selectedRows = ref<ResearchDonationRow[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -301,7 +340,11 @@
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
donationStatus: searchForm.donationStatus || undefined
|
||||
donationStatus: searchForm.donationStatus || undefined,
|
||||
createTimeStart: createTimeRange.value?.[0] || undefined,
|
||||
createTimeEnd: createTimeRange.value?.[1] || undefined,
|
||||
sampleCollectTimeStart: sampleCollectTimeRange.value?.[0] || undefined,
|
||||
sampleCollectTimeEnd: sampleCollectTimeRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -318,6 +361,8 @@
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.donationStatus = ''
|
||||
createTimeRange.value = getDefaultCreateTimeRange()
|
||||
sampleCollectTimeRange.value = null
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -387,7 +432,7 @@
|
||||
}
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
searchForm,
|
||||
[searchForm, createTimeRange, sampleCollectTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
|
||||
Reference in new issue
Block a user