fix withdraw page search bug
This commit is contained in:
@@ -180,17 +180,33 @@ export default {
|
||||
try {
|
||||
const page = parseInt(query.page) || 1
|
||||
const rows = parseInt(query.rows) || 10
|
||||
|
||||
// Map filter query to status
|
||||
let status = undefined
|
||||
if (query.filter === 'dep') status = 2
|
||||
else if (query.filter === 'accept') status = 1
|
||||
else if (query.filter === 'pend') status = 0
|
||||
|
||||
const params = {
|
||||
page,
|
||||
rows
|
||||
}
|
||||
if (status !== undefined) {
|
||||
params.status = status
|
||||
}
|
||||
if (query.search) {
|
||||
params.search = query.search
|
||||
}
|
||||
|
||||
const { data } = await $axios.get('/api/admin/gps/withdraw', {
|
||||
params: {
|
||||
page,
|
||||
rows
|
||||
}
|
||||
params
|
||||
})
|
||||
|
||||
return {
|
||||
requestsData: data.data,
|
||||
totalDocuments: data.totalDocuments || 0,
|
||||
totalPages: data.totalPages || 1
|
||||
totalPages: data.totalPages || 1,
|
||||
filterText: query.search || ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
@@ -213,31 +229,16 @@ export default {
|
||||
config() {
|
||||
return this.$config
|
||||
},
|
||||
statusValue() {
|
||||
// Map filterType to status integer
|
||||
if (this.filterType === 'dep') return 2
|
||||
if (this.filterType === 'accept') return 1
|
||||
if (this.filterType === 'pend') return 0
|
||||
return undefined // 'all' returns undefined to show all
|
||||
},
|
||||
filteredItems() {
|
||||
console.log('res data', this.requestsData)
|
||||
|
||||
const filterUsersByType = this.requestsData.filter(item => {
|
||||
if (this.filterType === 'all') return item
|
||||
// eslint-disable-next-line eqeqeq
|
||||
else if (this.filterType === 'dep') return item.status == 2
|
||||
// eslint-disable-next-line eqeqeq
|
||||
else if (this.filterType === 'accept') return item.status == 1
|
||||
// eslint-disable-next-line eqeqeq
|
||||
else if (this.filterType === 'pend') return item.status == 0
|
||||
else return null
|
||||
})
|
||||
const filterText = this.filterText
|
||||
if (!this.filterText.length) return filterUsersByType
|
||||
else {
|
||||
return filterUsersByType.filter(item => {
|
||||
return (
|
||||
item.userId.mobile_number.includes(filterText) ||
|
||||
item.userId.national_code.includes(filterText) ||
|
||||
item.userId.last_name.includes(filterText) ||
|
||||
item.userId.first_name.includes(filterText)
|
||||
)
|
||||
})
|
||||
}
|
||||
// No client-side filtering needed - all filtering is done on backend
|
||||
return this.requestsData
|
||||
},
|
||||
totalFilteredItems() {
|
||||
return this.filteredItems.length
|
||||
@@ -253,33 +254,112 @@ export default {
|
||||
},
|
||||
filterType: {
|
||||
get() {
|
||||
return this.$route.query?.filter
|
||||
return this.$route.query?.filter || 'all'
|
||||
},
|
||||
set(val) {
|
||||
this.$router.push({ name: 'admin-gps-withdraw', query: { filter: val } })
|
||||
this.$router.push({
|
||||
name: 'admin-gps-withdraw',
|
||||
query: {
|
||||
filter: val,
|
||||
page: 1 // Reset to first page when filter changes
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Initialize filterText from route query
|
||||
if (this.$route.query.search) {
|
||||
this.filterText = this.$route.query.search
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
// Clear search timeout on component destroy
|
||||
if (this.searchTimeout) {
|
||||
clearTimeout(this.searchTimeout)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText() {
|
||||
this.fetchData(1)
|
||||
filterText(newVal, oldVal) {
|
||||
// Only update route if value actually changed (avoid circular updates)
|
||||
if (newVal === oldVal) return
|
||||
|
||||
// Clear existing timeout
|
||||
if (this.searchTimeout) {
|
||||
clearTimeout(this.searchTimeout)
|
||||
}
|
||||
|
||||
// If search is cleared (empty), update immediately without debounce
|
||||
const isCleared = !newVal || !newVal.trim()
|
||||
const wasNotEmpty = oldVal && oldVal.trim()
|
||||
|
||||
if (isCleared && wasNotEmpty) {
|
||||
// Immediately update when clearing
|
||||
this.updateSearchQuery(newVal)
|
||||
} else {
|
||||
// Debounce search to avoid too many requests
|
||||
this.searchTimeout = setTimeout(() => {
|
||||
this.updateSearchQuery(newVal)
|
||||
}, 500) // 500ms debounce
|
||||
}
|
||||
},
|
||||
filterType() {
|
||||
this.fetchData(1)
|
||||
},
|
||||
'$route.query.page'() {
|
||||
this.fetchData()
|
||||
},
|
||||
'$route.query.search'(newVal, oldVal) {
|
||||
// Sync filterText with route query (only if different to avoid loop)
|
||||
const searchValue = newVal || ''
|
||||
if (searchValue !== this.filterText) {
|
||||
this.filterText = searchValue
|
||||
}
|
||||
// Always fetch data when search query changes
|
||||
if (newVal !== oldVal) {
|
||||
this.fetchData(1)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateSearchQuery(searchValue) {
|
||||
// Prevent circular update - check if route query already matches
|
||||
const currentSearch = this.$route.query.search || ''
|
||||
const newSearch = searchValue && searchValue.trim() ? searchValue.trim() : undefined
|
||||
|
||||
if (currentSearch === (newSearch || '')) return
|
||||
|
||||
// Update route query - this will trigger $route.query.search watcher
|
||||
this.$router.push({
|
||||
name: 'admin-gps-withdraw',
|
||||
query: {
|
||||
...this.$route.query,
|
||||
search: newSearch,
|
||||
page: 1 // Reset to first page when search changes
|
||||
}
|
||||
})
|
||||
},
|
||||
async fetchData(page = null) {
|
||||
const currentPage = page || this.currentPage
|
||||
try {
|
||||
const params = {
|
||||
page: currentPage,
|
||||
rows: this.pageSize
|
||||
}
|
||||
|
||||
// Add status parameter if filterType is set
|
||||
if (this.statusValue !== undefined) {
|
||||
params.status = this.statusValue
|
||||
}
|
||||
|
||||
// Add search parameter from route query (source of truth)
|
||||
const searchQuery = this.$route.query.search
|
||||
if (searchQuery && searchQuery.trim()) {
|
||||
params.search = searchQuery.trim()
|
||||
}
|
||||
|
||||
const { data } = await this.$axios.get('/api/admin/gps/withdraw', {
|
||||
params: {
|
||||
page: currentPage,
|
||||
rows: this.pageSize
|
||||
}
|
||||
params
|
||||
})
|
||||
this.requestsData = data.data
|
||||
this.totalDocuments = data.totalDocuments || 0
|
||||
|
||||
@@ -131,48 +131,118 @@ module.exports.getAllForAdmin = async (req, res) => {
|
||||
const page = parseInt(req.query.page) || 1
|
||||
const rows = parseInt(req.query.rows) || 10
|
||||
const search = req.query.search || ''
|
||||
const status = req.query.status !== undefined ? parseInt(req.query.status) : undefined
|
||||
const sortField = req.query.sortField || 'status'
|
||||
const sortOrder = req.query.sortOrder === 'desc' ? -1 : 1
|
||||
const skip = (page - 1) * rows
|
||||
|
||||
const matchStage = search
|
||||
? {
|
||||
$or: [{ IMEI: new RegExp(search, 'i') }, { trackingNumber: new RegExp(search, 'i') }]
|
||||
}
|
||||
: {}
|
||||
// If search is provided, use aggregation to search in user fields
|
||||
if (search) {
|
||||
const matchStage = {}
|
||||
|
||||
// const aggregationPipeline = [
|
||||
// { $match: matchStage },
|
||||
// {
|
||||
// $lookup: {
|
||||
// from: 'usergps',
|
||||
// localField: 'userId',
|
||||
// foreignField: '_id',
|
||||
// as: 'userId'
|
||||
// }
|
||||
// },
|
||||
// { $unwind: '$userId' },
|
||||
// { $sort: { [sortField]: sortOrder } },
|
||||
// { $skip: skip },
|
||||
// { $limit: rows }
|
||||
// ]
|
||||
// const data = await Withdraw.aggregate(aggregationPipeline)
|
||||
const data = await Withdraw.find(matchStage)
|
||||
.sort({ [sortField]: sortOrder })
|
||||
.skip(skip)
|
||||
.limit(rows)
|
||||
.populate('userId')
|
||||
if (status !== undefined) {
|
||||
matchStage.status = status
|
||||
}
|
||||
|
||||
const totalDocuments = await Withdraw.countDocuments(matchStage)
|
||||
// Build search conditions
|
||||
const searchConditions = [
|
||||
{ 'userId.mobile_number': new RegExp(search, 'i') },
|
||||
{ 'userId.national_code': new RegExp(search, 'i') },
|
||||
{ 'userId.first_name': new RegExp(search, 'i') },
|
||||
{ 'userId.last_name': new RegExp(search, 'i') },
|
||||
{ 'userId.shopName': new RegExp(search, 'i') },
|
||||
{ trackingNumber: new RegExp(search, 'i') }
|
||||
]
|
||||
|
||||
// const [data, totalDocuments] = await Promise.all([
|
||||
// Withdraw.aggregate(aggregationPipeline),
|
||||
// Withdraw.countDocuments(matchStage)
|
||||
// ])
|
||||
// Add amount search if search is a number
|
||||
if (!isNaN(search) && search.trim() !== '') {
|
||||
searchConditions.push({ amount: parseInt(search) })
|
||||
}
|
||||
|
||||
const totalPages = Math.ceil(totalDocuments / rows)
|
||||
const aggregationPipeline = [
|
||||
{ $match: matchStage },
|
||||
{
|
||||
$lookup: {
|
||||
from: 'usergps',
|
||||
let: { userIdStr: '$userId' },
|
||||
pipeline: [
|
||||
{
|
||||
$match: {
|
||||
$expr: {
|
||||
$eq: ['$_id', { $toObjectId: '$$userIdStr' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
as: 'userId'
|
||||
}
|
||||
},
|
||||
{ $unwind: { path: '$userId', preserveNullAndEmptyArrays: false } },
|
||||
{
|
||||
$match: {
|
||||
$or: searchConditions
|
||||
}
|
||||
},
|
||||
{ $sort: { [sortField]: sortOrder } },
|
||||
{ $skip: skip },
|
||||
{ $limit: rows }
|
||||
]
|
||||
|
||||
res.status(200).json({ data, totalDocuments, totalPages })
|
||||
const countPipeline = [
|
||||
{ $match: matchStage },
|
||||
{
|
||||
$lookup: {
|
||||
from: 'usergps',
|
||||
let: { userIdStr: '$userId' },
|
||||
pipeline: [
|
||||
{
|
||||
$match: {
|
||||
$expr: {
|
||||
$eq: ['$_id', { $toObjectId: '$$userIdStr' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
as: 'userId'
|
||||
}
|
||||
},
|
||||
{ $unwind: { path: '$userId', preserveNullAndEmptyArrays: false } },
|
||||
{
|
||||
$match: {
|
||||
$or: searchConditions
|
||||
}
|
||||
},
|
||||
{ $count: 'total' }
|
||||
]
|
||||
|
||||
const [data, countResult] = await Promise.all([
|
||||
Withdraw.aggregate(aggregationPipeline),
|
||||
Withdraw.aggregate(countPipeline)
|
||||
])
|
||||
|
||||
const totalDocuments = countResult[0]?.total || 0
|
||||
const totalPages = Math.ceil(totalDocuments / rows)
|
||||
|
||||
res.status(200).json({ data, totalDocuments, totalPages })
|
||||
} else {
|
||||
// No search - use simple find with populate
|
||||
const matchStage = {}
|
||||
|
||||
if (status !== undefined) {
|
||||
matchStage.status = status
|
||||
}
|
||||
|
||||
const data = await Withdraw.find(matchStage)
|
||||
.sort({ [sortField]: sortOrder })
|
||||
.skip(skip)
|
||||
.limit(rows)
|
||||
.populate('userId')
|
||||
|
||||
const totalDocuments = await Withdraw.countDocuments(matchStage)
|
||||
const totalPages = Math.ceil(totalDocuments / rows)
|
||||
|
||||
res.status(200).json({ data, totalDocuments, totalPages })
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'An error occurred, please try again.', error: error.message })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user