地图查询构造器
This commit is contained in:
parent
912d2d4a12
commit
4ac36abfe3
@ -92,3 +92,20 @@ export const getAllMapRating = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 依据条件搜索地图
|
||||||
|
* @param {Object} params - 查询参数对象,键为参数名,值为参数值
|
||||||
|
* @returns {Promise<any>} 返回一个包含地图信息的Promise对象
|
||||||
|
*/
|
||||||
|
export const searchMapsByConditions = async (params) => {
|
||||||
|
try {
|
||||||
|
// 构建查询字符串
|
||||||
|
const query = new URLSearchParams(params).toString();
|
||||||
|
const response = await axiosInstance.get(`/map/search?${query}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('依据条件搜索地图失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
221
src/utils/MapQuery.js
Normal file
221
src/utils/MapQuery.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/**
|
||||||
|
* 地图查询构造器
|
||||||
|
* 提供链式API来构建 /map/search 的查询参数.
|
||||||
|
*
|
||||||
|
* 根据API要求,不同字段适用不同的查询方法:
|
||||||
|
* - **直接等值查询 (无前缀)**: `id`, `name`, `user` 等. 请使用 `.eq()` 或专用方法如 `.user()`.
|
||||||
|
* - **带规则查询 (有前缀)**: `size`, `player_count`, `download_count`, `favourite_count`. 请使用 `.equ()`, `.lss()`, `.geq()` 等方法.
|
||||||
|
* - **多值查询**: `tags`. 请使用 `.in()` 方法.
|
||||||
|
*
|
||||||
|
* **用法示例:**
|
||||||
|
* const params = new MapQuery()
|
||||||
|
* .user('张三')
|
||||||
|
* .leq('download_count', 100)
|
||||||
|
* .like('name', '测试')
|
||||||
|
* .in('tags', ['PVP', '特殊'])
|
||||||
|
* .build();
|
||||||
|
*/
|
||||||
|
export default class MapQuery {
|
||||||
|
constructor() {
|
||||||
|
this.params = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 id
|
||||||
|
* @param {number} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
id(value) {
|
||||||
|
return this.eq('id', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 name
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
name(value) {
|
||||||
|
return this.eq('name', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 chinese_name
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
chineseName(value) {
|
||||||
|
return this.eq('chinese_name', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 user
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
user(value) {
|
||||||
|
return this.eq('user', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 create_time
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
createTime(value) {
|
||||||
|
return this.eq('create_time', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 author
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
author(value) {
|
||||||
|
return this.eq('author', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 img_file
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
imgFile(value) {
|
||||||
|
return this.eq('img_file', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 thumbnail
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
thumbnail(value) {
|
||||||
|
return this.eq('thumbnail', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 zip_file
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
zipFile(value) {
|
||||||
|
return this.eq('zip_file', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 file_name
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
fileName(value) {
|
||||||
|
return this.eq('file_name', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 verify_status
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
verifyStatus(value) {
|
||||||
|
return this.eq('verify_status', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等于 (e.g., `user='张三'`)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {string|number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
eq(key, value) {
|
||||||
|
this.params[key] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 等于 (带EQU前缀, e.g., `player_count='EQU4'`)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {string|number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
equ(key, value) {
|
||||||
|
this.params[key] = `EQU${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 不等于 (e.g., `download_count='NEQ100'`)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {string|number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
neq(key, value) {
|
||||||
|
this.params[key] = `NEQ${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 小于 (Less Than)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
lss(key, value) {
|
||||||
|
this.params[key] = `LSS${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 小于等于 (Less Than or Equal)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
leq(key, value) {
|
||||||
|
this.params[key] = `LEQ${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 大于 (Greater Than)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
gtr(key, value) {
|
||||||
|
this.params[key] = `GTR${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 大于等于 (Greater Than or Equal)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {number} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
geq(key, value) {
|
||||||
|
this.params[key] = `GEQ${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 模糊匹配
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {string} value - 参数值
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
like(key, value) {
|
||||||
|
this.params[key] = `LIKE${value}`;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 包含于 (用于 tags)
|
||||||
|
* @param {string} key - 参数名
|
||||||
|
* @param {Array<string>} arr - 参数值数组
|
||||||
|
* @returns {MapQuery}
|
||||||
|
*/
|
||||||
|
in(key, arr) {
|
||||||
|
if (Array.isArray(arr)) {
|
||||||
|
this.params[key] = arr.join(',');
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 构建最终的参数对象
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
build() {
|
||||||
|
return { ...this.params };
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,16 @@
|
|||||||
<span class="back-icon">←</span> 返回
|
<span class="back-icon">←</span> 返回
|
||||||
</button>
|
</button>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{{ authorName }}</h1>
|
<h1>{{ authorName }} 的地图</h1>
|
||||||
|
</div>
|
||||||
|
<div class="filters-row">
|
||||||
|
<div class="filters">
|
||||||
|
<label>玩家数:</label>
|
||||||
|
<select v-model="playerCountFilter" class="filter-select" @change="handleFilterChange">
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option v-for="n in [2,3,4,5,6,7,8]" :key="n" :value="n">{{ n }}人</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isLoading" class="loading-container">
|
<div v-if="isLoading" class="loading-container">
|
||||||
<div class="loading-bar">
|
<div class="loading-bar">
|
||||||
@ -92,7 +101,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { getMaps } from '@/api/maps.js'
|
import { searchMapsByConditions } from '@/api/centre_maps.js'
|
||||||
|
import MapQuery from '@/utils/MapQuery.js'
|
||||||
|
import { getAllTags } from '@/api/maps.js'
|
||||||
import ErrorDialog from '@/components/ErrorDialog.vue'
|
import ErrorDialog from '@/components/ErrorDialog.vue'
|
||||||
import '../../assets/styles/common.css'
|
import '../../assets/styles/common.css'
|
||||||
import '../../assets/styles/Maps.css'
|
import '../../assets/styles/Maps.css'
|
||||||
@ -103,6 +114,9 @@ const authorMaps = ref([])
|
|||||||
const authorName = ref('')
|
const authorName = ref('')
|
||||||
const isLoading = ref(true)
|
const isLoading = ref(true)
|
||||||
|
|
||||||
|
// 搜索和筛选
|
||||||
|
const playerCountFilter = ref('')
|
||||||
|
|
||||||
// 错误弹窗相关
|
// 错误弹窗相关
|
||||||
const showError = ref(false)
|
const showError = ref(false)
|
||||||
const errorTitle = ref('')
|
const errorTitle = ref('')
|
||||||
@ -154,6 +168,11 @@ const handleJumpPage = () => {
|
|||||||
jumpPage.value = ''
|
jumpPage.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleFilterChange = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchAuthorMaps()
|
||||||
|
}
|
||||||
|
|
||||||
// 返回上一页
|
// 返回上一页
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
router.push('/author')
|
router.push('/author')
|
||||||
@ -182,35 +201,15 @@ const fetchAuthorMaps = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
authorName.value = author
|
authorName.value = author
|
||||||
|
|
||||||
// 使用原有的API调用方式
|
const query = new MapQuery().user(author)
|
||||||
const cacheKey = 'allMaps'
|
if (playerCountFilter.value) {
|
||||||
let allMaps = []
|
query.equ('player_count', playerCountFilter.value)
|
||||||
const cached = sessionStorage.getItem(cacheKey)
|
|
||||||
if (cached) {
|
|
||||||
allMaps = JSON.parse(cached)
|
|
||||||
} else {
|
|
||||||
// 获取所有地图
|
|
||||||
let page = 1
|
|
||||||
let hasMore = true
|
|
||||||
while (hasMore) {
|
|
||||||
const response = await getMaps({
|
|
||||||
page: page,
|
|
||||||
ordering: '-create_time'
|
|
||||||
})
|
|
||||||
if (response.results && response.results.length > 0) {
|
|
||||||
allMaps = allMaps.concat(response.results)
|
|
||||||
hasMore = !!response.next
|
|
||||||
page++
|
|
||||||
} else {
|
|
||||||
hasMore = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sessionStorage.setItem(cacheKey, JSON.stringify(allMaps))
|
|
||||||
}
|
}
|
||||||
// 根据作者名称过滤地图
|
const params = query.build()
|
||||||
authorMaps.value = allMaps.filter(map => map.user === author)
|
const maps = await searchMapsByConditions(params)
|
||||||
console.log('作者地图列表:', authorMaps.value)
|
authorMaps.value = maps
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取作者地图列表失败:', error)
|
console.error('获取作者地图列表失败:', error)
|
||||||
showErrorMessage('获取作者地图列表失败,请稍后重试')
|
showErrorMessage('获取作者地图列表失败,请稍后重试')
|
||||||
@ -441,4 +440,36 @@ onMounted(() => {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filters-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters label {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #222;
|
||||||
|
margin-right: 6px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-select {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
font-size: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters-row, .filters {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Loading…
x
Reference in New Issue
Block a user