fix withdraw page search bug
This commit is contained in:
@@ -180,17 +180,33 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const page = parseInt(query.page) || 1
|
const page = parseInt(query.page) || 1
|
||||||
const rows = parseInt(query.rows) || 10
|
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', {
|
const { data } = await $axios.get('/api/admin/gps/withdraw', {
|
||||||
params: {
|
params
|
||||||
page,
|
|
||||||
rows
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
requestsData: data.data,
|
requestsData: data.data,
|
||||||
totalDocuments: data.totalDocuments || 0,
|
totalDocuments: data.totalDocuments || 0,
|
||||||
totalPages: data.totalPages || 1
|
totalPages: data.totalPages || 1,
|
||||||
|
filterText: query.search || ''
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@@ -213,31 +229,16 @@ export default {
|
|||||||
config() {
|
config() {
|
||||||
return this.$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() {
|
filteredItems() {
|
||||||
console.log('res data', this.requestsData)
|
// No client-side filtering needed - all filtering is done on backend
|
||||||
|
return 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)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
totalFilteredItems() {
|
totalFilteredItems() {
|
||||||
return this.filteredItems.length
|
return this.filteredItems.length
|
||||||
@@ -253,33 +254,112 @@ export default {
|
|||||||
},
|
},
|
||||||
filterType: {
|
filterType: {
|
||||||
get() {
|
get() {
|
||||||
return this.$route.query?.filter
|
return this.$route.query?.filter || 'all'
|
||||||
},
|
},
|
||||||
set(val) {
|
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: {
|
watch: {
|
||||||
filterText() {
|
filterText(newVal, oldVal) {
|
||||||
this.fetchData(1)
|
// 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() {
|
filterType() {
|
||||||
this.fetchData(1)
|
this.fetchData(1)
|
||||||
},
|
},
|
||||||
'$route.query.page'() {
|
'$route.query.page'() {
|
||||||
this.fetchData()
|
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: {
|
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) {
|
async fetchData(page = null) {
|
||||||
const currentPage = page || this.currentPage
|
const currentPage = page || this.currentPage
|
||||||
try {
|
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', {
|
const { data } = await this.$axios.get('/api/admin/gps/withdraw', {
|
||||||
params: {
|
params
|
||||||
page: currentPage,
|
|
||||||
rows: this.pageSize
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
this.requestsData = data.data
|
this.requestsData = data.data
|
||||||
this.totalDocuments = data.totalDocuments || 0
|
this.totalDocuments = data.totalDocuments || 0
|
||||||
|
|||||||
@@ -131,48 +131,118 @@ module.exports.getAllForAdmin = async (req, res) => {
|
|||||||
const page = parseInt(req.query.page) || 1
|
const page = parseInt(req.query.page) || 1
|
||||||
const rows = parseInt(req.query.rows) || 10
|
const rows = parseInt(req.query.rows) || 10
|
||||||
const search = req.query.search || ''
|
const search = req.query.search || ''
|
||||||
|
const status = req.query.status !== undefined ? parseInt(req.query.status) : undefined
|
||||||
const sortField = req.query.sortField || 'status'
|
const sortField = req.query.sortField || 'status'
|
||||||
const sortOrder = req.query.sortOrder === 'desc' ? -1 : 1
|
const sortOrder = req.query.sortOrder === 'desc' ? -1 : 1
|
||||||
const skip = (page - 1) * rows
|
const skip = (page - 1) * rows
|
||||||
|
|
||||||
const matchStage = search
|
// If search is provided, use aggregation to search in user fields
|
||||||
? {
|
if (search) {
|
||||||
$or: [{ IMEI: new RegExp(search, 'i') }, { trackingNumber: new RegExp(search, 'i') }]
|
const matchStage = {}
|
||||||
}
|
|
||||||
: {}
|
if (status !== undefined) {
|
||||||
|
matchStage.status = status
|
||||||
|
}
|
||||||
|
|
||||||
// const aggregationPipeline = [
|
// Build search conditions
|
||||||
// { $match: matchStage },
|
const searchConditions = [
|
||||||
// {
|
{ 'userId.mobile_number': new RegExp(search, 'i') },
|
||||||
// $lookup: {
|
{ 'userId.national_code': new RegExp(search, 'i') },
|
||||||
// from: 'usergps',
|
{ 'userId.first_name': new RegExp(search, 'i') },
|
||||||
// localField: 'userId',
|
{ 'userId.last_name': new RegExp(search, 'i') },
|
||||||
// foreignField: '_id',
|
{ 'userId.shopName': new RegExp(search, 'i') },
|
||||||
// as: 'userId'
|
{ trackingNumber: new RegExp(search, 'i') }
|
||||||
// }
|
]
|
||||||
// },
|
|
||||||
// { $unwind: '$userId' },
|
// Add amount search if search is a number
|
||||||
// { $sort: { [sortField]: sortOrder } },
|
if (!isNaN(search) && search.trim() !== '') {
|
||||||
// { $skip: skip },
|
searchConditions.push({ amount: parseInt(search) })
|
||||||
// { $limit: rows }
|
}
|
||||||
// ]
|
|
||||||
// const data = await Withdraw.aggregate(aggregationPipeline)
|
|
||||||
const data = await Withdraw.find(matchStage)
|
|
||||||
.sort({ [sortField]: sortOrder })
|
|
||||||
.skip(skip)
|
|
||||||
.limit(rows)
|
|
||||||
.populate('userId')
|
|
||||||
|
|
||||||
const totalDocuments = await Withdraw.countDocuments(matchStage)
|
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 }
|
||||||
|
]
|
||||||
|
|
||||||
// const [data, totalDocuments] = await Promise.all([
|
const countPipeline = [
|
||||||
// Withdraw.aggregate(aggregationPipeline),
|
{ $match: matchStage },
|
||||||
// Withdraw.countDocuments(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 totalPages = Math.ceil(totalDocuments / rows)
|
const [data, countResult] = await Promise.all([
|
||||||
|
Withdraw.aggregate(aggregationPipeline),
|
||||||
|
Withdraw.aggregate(countPipeline)
|
||||||
|
])
|
||||||
|
|
||||||
res.status(200).json({ data, totalDocuments, totalPages })
|
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) {
|
} catch (error) {
|
||||||
res.status(500).json({ message: 'An error occurred, please try again.', error: error.message })
|
res.status(500).json({ message: 'An error occurred, please try again.', error: error.message })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user