导出招商催办的用户

This commit is contained in:
zhonghua.li
2026-05-21 09:08:33 +08:00
parent f7909e64fa
commit d7180a5334
5 changed files with 622 additions and 46 deletions

View File

@@ -70,30 +70,50 @@
</el-card>
<el-card class="table-container" shadow="never">
<el-table v-loading="loading" :data="list" style="width: 100%">
<el-table-column label="申请人" prop="applyUser" min-width="120" />
<el-table-column label="申请电话" prop="applyPhone" min-width="130" />
<el-table-column label="同事姓名" prop="colleagueName" min-width="120" />
<el-table-column label="同事电话" prop="colleaguePhone" min-width="130" show-overflow-tooltip />
<el-table-column label="组长姓名" prop="teamLeader" min-width="120" />
<el-table-column label="申请日期" prop="applyDate" min-width="120" />
<el-table-column label="创建时间" prop="createTime" min-width="170">
<template slot-scope="scope">
{{ formatDateTime(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="更新时间" prop="updateTime" min-width="170">
<template slot-scope="scope">
{{ formatDateTime(scope.row.updateTime) }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="140">
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" style="color:#F56C6C;" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div v-loading="loading" class="purchase-apply-sheet-wrap">
<table v-if="groupedList.length" class="purchase-apply-sheet">
<thead>
<tr>
<th>日期和人数</th>
<th>序号</th>
<th>昵称</th>
<th>手机号</th>
<th>特权开通日期</th>
<th>推荐人</th>
<th>手机号</th>
<th>领导人</th>
<th>开通日期</th>
<th class="col-actions">操作</th>
</tr>
</thead>
<tbody>
<template v-for="group in groupedList">
<tr v-for="(row, rowIndex) in group.rows" :key="row.id || `${group.key}-${rowIndex}`">
<td
v-if="rowIndex === 0"
:rowspan="group.rows.length"
class="date-cell"
>
{{ group.label }}
</td>
<td>{{ rowIndex + 1 }}</td>
<td>{{ row.applyUser || '-' }}</td>
<td>{{ row.applyPhone || '-' }}</td>
<td>{{ formatTryDate(row.tryDate) }}</td>
<td>{{ row.colleagueName || '-' }}</td>
<td>{{ row.colleaguePhone || '-' }}</td>
<td>{{ row.teamLeader || '-' }}</td>
<td>{{ formatOpenDate(row.applyDate) }}</td>
<td class="col-actions">
<el-button type="text" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" style="color:#F56C6C;" @click="handleDelete(row)">删除</el-button>
</td>
</tr>
</template>
</tbody>
</table>
<div v-else class="purchase-apply-sheet-empty">暂无数据</div>
</div>
<el-pagination
:current-page="queryParams.current"
@@ -361,16 +381,52 @@
</div>
</el-dialog>
<el-dialog title="特权推荐人列表" :visible.sync="privilegeDialogVisible" width="760px" @close="resetPrivilegeDialog">
<el-table v-loading="privilegeLoading" :data="privilegeList" style="width: 100%">
<el-table-column type="index" label="#" width="60" />
<el-table-column label="申请人" prop="applyUser" min-width="120" show-overflow-tooltip />
<el-table-column label="申请电话" prop="applyPhone" min-width="140" show-overflow-tooltip />
<el-table-column label="同事姓名" prop="colleagueName" min-width="120" show-overflow-tooltip />
<el-table-column label="同事电话" prop="colleaguePhone" min-width="140" show-overflow-tooltip />
<el-table-column label="组长姓名" prop="teamLeader" min-width="120" show-overflow-tooltip />
<el-table-column label="申请日期" prop="applyDate" min-width="120" />
</el-table>
<el-dialog
title="特权推荐人列表"
:visible.sync="privilegeDialogVisible"
width="960px"
custom-class="purchase-privilege-dialog"
@close="resetPrivilegeDialog"
>
<div v-loading="privilegeLoading" class="purchase-apply-sheet-wrap">
<table v-if="privilegeGroupedList.length" class="purchase-apply-sheet">
<thead>
<tr>
<th>日期和人数</th>
<th>序号</th>
<th>昵称</th>
<th>手机号</th>
<th>特权开通日期</th>
<th>推荐人</th>
<th>手机号</th>
<th>领导人</th>
<th>开通日期</th>
</tr>
</thead>
<tbody>
<template v-for="group in privilegeGroupedList">
<tr v-for="(row, rowIndex) in group.rows" :key="row.id || `priv-${group.key}-${rowIndex}`">
<td
v-if="rowIndex === 0"
:rowspan="group.rows.length"
class="date-cell"
>
{{ group.label }}
</td>
<td>{{ rowIndex + 1 }}</td>
<td>{{ row.applyUser || '-' }}</td>
<td>{{ row.applyPhone || '-' }}</td>
<td>{{ formatTryDate(row.tryDate) }}</td>
<td>{{ row.colleagueName || '-' }}</td>
<td>{{ row.colleaguePhone || '-' }}</td>
<td>{{ row.teamLeader || '-' }}</td>
<td>{{ formatOpenDate(row.applyDate) }}</td>
</tr>
</template>
</tbody>
</table>
<div v-else class="purchase-apply-sheet-empty">暂无数据</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="privilegeDialogVisible = false">关闭</el-button>
</div>
@@ -464,6 +520,14 @@ export default {
}
}
},
computed: {
groupedList() {
return this.buildGroupedList(this.list)
},
privilegeGroupedList() {
return this.buildGroupedList(this.privilegeList)
}
},
created() {
this.fetchList()
},
@@ -475,6 +539,75 @@ export default {
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
buildGroupedList(records) {
if (!Array.isArray(records) || !records.length) return []
const sorted = [...records].sort((a, b) => {
const da = this.normalizeApplyDateValue(a.applyDate)
const db = this.normalizeApplyDateValue(b.applyDate)
if (da !== db) return db.localeCompare(da)
const idA = a.id != null ? String(a.id) : ''
const idB = b.id != null ? String(b.id) : ''
return idA.localeCompare(idB)
})
const map = new Map()
sorted.forEach((row) => {
const dateKey = this.normalizeApplyDateValue(row.applyDate) || '__no_date__'
if (!map.has(dateKey)) {
map.set(dateKey, [])
}
map.get(dateKey).push(row)
})
return Array.from(map.entries()).map(([dateKey, rows]) => ({
key: dateKey,
label: this.formatDateGroupLabel(dateKey, rows.length),
rows
}))
},
formatDateGroupLabel(applyDate, count) {
const displayDate = this.subtractOneDay(applyDate)
const md = this.formatShortMd(displayDate, false)
const n = typeof count === 'number' && count > 0 ? count : 0
return md ? `${md}招商${n}` : `招商${n}`
},
subtractOneDay(dateValue) {
const normalized = this.normalizeApplyDateValue(dateValue)
if (!normalized) return ''
const date = new Date(`${normalized}T12:00:00`)
if (Number.isNaN(date.getTime())) return normalized
date.setDate(date.getDate() - 1)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
formatShortMd(dateValue, padMonthDay = true) {
const normalized = this.normalizeApplyDateValue(dateValue)
if (!normalized) return ''
const parts = normalized.split('-')
if (parts.length < 3) return normalized
const month = Number(parts[1])
const day = Number(parts[2])
if (Number.isNaN(month) || Number.isNaN(day)) return normalized
if (padMonthDay) {
return `${String(month).padStart(2, '0')}.${String(day).padStart(2, '0')}`
}
return `${month}.${day}`
},
formatTryDate(tryDate) {
const text = tryDate != null ? String(tryDate).trim() : ''
return text || '-'
},
formatOpenDate(dateValue) {
const normalized = this.normalizeApplyDateValue(dateValue)
if (!normalized) return '-'
const parts = normalized.split('-')
if (parts.length < 3) return normalized
const year = parts[0]
const month = Number(parts[1])
const day = Number(parts[2])
if (Number.isNaN(month) || Number.isNaN(day)) return normalized
return `${year}/${month}/${day}`
},
fetchList() {
this.loading = true
getLbPurchaseApplyList(this.buildListParams())
@@ -1038,6 +1171,10 @@ export default {
<style lang="scss" scoped>
.app-container {
$table-border: #000;
$header-bg: #ffd966;
$date-cell-bg: #fff2cc;
.filter-container {
margin-bottom: 20px;
}
@@ -1047,11 +1184,110 @@ export default {
}
.table-container {
.purchase-apply-sheet-wrap {
overflow-x: auto;
}
.purchase-apply-sheet {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
color: #000;
font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
font-size: 14px;
text-align: center;
th,
td {
border: 1px solid $table-border;
padding: 8px 6px;
vertical-align: middle;
word-break: break-all;
}
thead th {
background-color: $header-bg;
font-weight: 700;
white-space: nowrap;
}
tbody td {
background-color: #fff;
}
tbody td.date-cell {
background-color: $date-cell-bg;
font-weight: 600;
white-space: nowrap;
}
.col-actions {
width: 120px;
}
}
.purchase-apply-sheet-empty {
padding: 40px 0;
text-align: center;
color: #909399;
border: 1px solid $table-border;
background-color: #fff;
}
.el-pagination {
margin-top: 20px;
text-align: right;
}
}
}
</style>
<style lang="scss">
.purchase-privilege-dialog {
.purchase-apply-sheet-wrap {
overflow-x: auto;
}
.purchase-apply-sheet {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
color: #000;
font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
font-size: 14px;
text-align: center;
th,
td {
border: 1px solid #000;
padding: 8px 6px;
vertical-align: middle;
word-break: break-all;
}
thead th {
background-color: #ffd966;
font-weight: 700;
white-space: nowrap;
}
tbody td {
background-color: #fff;
}
tbody td.date-cell {
background-color: #fff2cc;
font-weight: 600;
white-space: nowrap;
}
}
.purchase-apply-sheet-empty {
padding: 40px 0;
text-align: center;
color: #909399;
border: 1px solid #000;
background-color: #fff;
}
}
</style>