hookehuyr

feat(SearchBar): 改进搜索栏兼容性并优化课程页交互

- 将输入框类型改为search并添加表单提交处理,提升iOS设备兼容性
- 课程详情页增加咨询按钮显示并优化课程大纲条件渲染
......@@ -54,3 +54,9 @@ https://oa-dev.onwall.cn/f/mlaj
- 行为:接口返回 `code=401` 时,不再对公开页面(如课程详情 `/courses/:id`)进行登录重定向;仅当当前路由确实需要登录权限时才跳转至登录页。
- 原理:响应拦截器调用路由守卫 `checkAuth` 判断当前路由是否为受限页面,受限则清理登录信息并附带 `redirect` 重定向至登录页;公开页面保持当前页,由业务自行处理401。
- 位置:`/src/utils/axios.js`,在响应拦截器中按需处理重定向。
- 搜索栏回车搜索兼容性提升
- 行为:将输入框类型改为 `search`,并可选开启 `form @submit.prevent` 机制以提升 iOS 设备软键盘“搜索”键触发稳定性;同时保留 `@keyup.enter` 回车触发搜索。
- 路由行为:
- 课程页(`isCoursePage=true`):回车或搜索键触发后跳转至 `/courses-list` 并携带 `keyword` 参数。
- 列表页:仅更新当前路由的查询参数 `keyword`
- 位置:`/src/components/ui/SearchBar.vue`,新增 `useFormSubmit` 可选参数(默认开启)。
......
<template>
<FrostedGlass class="px-4 py-2 mx-4 my-3 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input
type="text"
:placeholder="placeholder"
v-model="localValue"
class="bg-transparent outline-none flex-1 text-gray-700 placeholder-gray-400"
@input="handleSearch"
@blur="handleBlur"
/>
</FrostedGlass>
<FrostedGlass class="px-4 py-2 mx-4 my-3 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<template v-if="props.useFormSubmit">
<form @submit.prevent="handleSubmit" action="javascript:return true" class="flex-1">
<input
type="search"
:placeholder="placeholder"
v-model="localValue"
class="bg-transparent outline-none w-full text-gray-700 placeholder-gray-400"
@input="handleSearch"
@blur="handleBlur"
@keyup.enter="handleEnter"
/>
</form>
</template>
<template v-else>
<input
type="search"
:placeholder="placeholder"
v-model="localValue"
class="bg-transparent outline-none flex-1 text-gray-700 placeholder-gray-400"
@input="handleSearch"
@blur="handleBlur"
@keyup.enter="handleEnter"
/>
</template>
</FrostedGlass>
</template>
<script setup>
......@@ -33,6 +49,10 @@ const props = defineProps({
isCoursePage: {
type: Boolean,
default: false
},
useFormSubmit: {
type: Boolean,
default: true
}
})
......@@ -44,11 +64,23 @@ watch(() => props.modelValue, (newValue) => {
localValue.value = newValue
})
/**
* @function handleSearch
* @description 输入变更时触发搜索事件与 v-model 同步(即时搜索)。
* @returns {void}
*/
const handleSearch = () => {
emit('update:modelValue', localValue.value)
emit('search', localValue.value)
}
/**
* @function handleBlur
* @description 失焦时根据页面类型进行跳转或更新 URL 参数。
* - 课程页:跳转至课程列表页并携带关键字参数。
* - 列表页:仅更新当前路由的查询参数。
* @returns {void}
*/
const handleBlur = () => {
const query = localValue.value
emit('blur', query)
......@@ -64,4 +96,23 @@ const handleBlur = () => {
router.replace({ query: { ...router.currentRoute.value.query, keyword: localValue.value } })
}
}
/**
* @function handleEnter
* @description 键盘回车触发与失焦同等的搜索行为,保证“回车搜索”有效。
* @returns {void}
*/
const handleEnter = () => {
// 复用失焦逻辑以保持一致的路由行为
handleBlur()
}
/**
* @function handleSubmit
* @description 表单提交(移动端键盘“搜索”)触发与失焦同等的搜索行为,增强 iOS 兼容性。
* @returns {void}
*/
const handleSubmit = () => {
handleBlur()
}
</script>
......
......@@ -49,7 +49,7 @@
</FrostedGlass> -->
<!-- Tab Navigation -->
<FrostedGlass class="mb-6 rounded-xl overflow-hidden">
<FrostedGlass v-if="curriculumItems.length" class="mb-6 rounded-xl overflow-hidden">
<div class="border-b border-gray-200">
<div class="flex">
<button v-for="(item, index) in curriculumItems" :key="index" @click="activeTab = item.title" :class="[
......@@ -223,7 +223,7 @@
</svg>
收藏
</button>
<!-- <button class="flex flex-col items-center text-gray-500 text-xs" @click="open_consult_dialog">
<button class="flex flex-col items-center text-gray-500 text-xs" @click="open_consult_dialog">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
......@@ -239,7 +239,7 @@
/>
</svg>
咨询
</button> -->
</button>
</div>
<div class="flex items-center">
<div v-if="!course?.is_buy" class="mr-2">
......