feature/login-screen #1
@ -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> 返回
|
||||
</button>
|
||||
<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 v-if="isLoading" class="loading-container">
|
||||
<div class="loading-bar">
|
||||
@ -92,7 +101,9 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
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 '../../assets/styles/common.css'
|
||||
import '../../assets/styles/Maps.css'
|
||||
@ -103,6 +114,9 @@ const authorMaps = ref([])
|
||||
const authorName = ref('')
|
||||
const isLoading = ref(true)
|
||||
|
||||
// 搜索和筛选
|
||||
const playerCountFilter = ref('')
|
||||
|
||||
// 错误弹窗相关
|
||||
const showError = ref(false)
|
||||
const errorTitle = ref('')
|
||||
@ -154,6 +168,11 @@ const handleJumpPage = () => {
|
||||
jumpPage.value = ''
|
||||
}
|
||||
|
||||
const handleFilterChange = () => {
|
||||
currentPage.value = 1
|
||||
fetchAuthorMaps()
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
router.push('/author')
|
||||
@ -182,35 +201,15 @@ const fetchAuthorMaps = async () => {
|
||||
return
|
||||
}
|
||||
authorName.value = author
|
||||
|
||||
// 使用原有的API调用方式
|
||||
const cacheKey = 'allMaps'
|
||||
let allMaps = []
|
||||
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 query = new MapQuery().user(author)
|
||||
if (playerCountFilter.value) {
|
||||
query.equ('player_count', playerCountFilter.value)
|
||||
}
|
||||
// 根据作者名称过滤地图
|
||||
authorMaps.value = allMaps.filter(map => map.user === author)
|
||||
console.log('作者地图列表:', authorMaps.value)
|
||||
const params = query.build()
|
||||
const maps = await searchMapsByConditions(params)
|
||||
authorMaps.value = maps
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取作者地图列表失败:', error)
|
||||
showErrorMessage('获取作者地图列表失败,请稍后重试')
|
||||
@ -441,4 +440,36 @@ onMounted(() => {
|
||||
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>
|
Loading…
x
Reference in New Issue
Block a user