Squashed commit of the following: commit 66d0e5e94c0394d83b47b58bd130ba2addce2930 Author: Sun <95302870@qq.com> Date: Thu Jan 25 13:20:34 2024 +0800 更新1.3.0-beta24-01-25 commit 52a81e5f558b3e7b329f828adbd8255960dd750b Author: Sun <95302870@qq.com> Date: Thu Jan 25 13:13:08 2024 +0800 Squashed commit of the following: commit 908d87357c4e22868eff85f377bb8cd22f3785d7 Author: Sun <95302870@qq.com> Date: Thu Jan 25 13:12:14 2024 +0800 增加前端版本号 commit 8ed2b636476c7a14ae4e1761f7712949b7ce60fc Author: Sun <95302870@qq.com> Date: Thu Jan 25 12:29:49 2024 +0800 增加自动获取前端版本号的git tag commit ba7d70f9cabf020ab9ce682be5e593b649aed071 Author: Sun <95302870@qq.com> Date: Thu Jan 25 10:58:15 2024 +0800 优化代码 commit 104543b96fb4d5f9362d29da22390d9a0565c395 Author: Sun <95302870@qq.com> Date: Wed Jan 24 21:28:31 2024 +0800 增加系统状态组件的部分样式 commit 70c87c94c688a14d3bbe53be191c2186ec469a01 Author: Sun <95302870@qq.com> Date: Wed Jan 24 20:55:05 2024 +0800 时间组件和搜索栏组件增加样式类型 commit 6bab5a264fdb1281763d73bf022335667845dc67 Author: Sun <95302870@qq.com> Date: Wed Jan 24 20:41:33 2024 +0800 将项目列表增加样式并优化减少dom嵌套 commit 99d18df7f0a57ec1cead9bce7b2b4b11427cc2e2 Author: Sun <95302870@qq.com> Date: Wed Jan 24 20:11:07 2024 +0800 增加系统状态、logo等类名并简化部分组件dom commit bf1cc0cc0014f751b6453ebfb357b575b0a54615 Author: Sun <95302870@qq.com> Date: Wed Jan 24 17:17:41 2024 +0800 更新关于页面 commit fceacf58b87b988827f0baa6086e8296c843c495 Author: Sun <95302870@qq.com> Date: Wed Jan 24 14:54:37 2024 +0800 增加隐藏网络模式切换开关 commit e0dcc49f5b23618103c5ee15e13758164d2eddf2 Author: Sun <95302870@qq.com> Date: Wed Jan 24 13:55:28 2024 +0800 优化部分错误码 commit 863cdf0fc1fc406304784d4304ba6be31e5133ff Author: Sun <95302870@qq.com> Date: Wed Jan 24 12:54:55 2024 +0800 声明暴露端口 commit 5b25ef9c194dc0112cd10250c04344dd6f57be27 Author: Sun <95302870@qq.com> Date: Wed Jan 24 12:38:48 2024 +0800 修改命令行所有的输出内容为英文
205 lines
6.3 KiB
Vue
205 lines
6.3 KiB
Vue
<script setup lang="ts">
|
||
import { defineEmits, onMounted, ref } from 'vue'
|
||
import { NAvatar, NCheckbox } from 'naive-ui'
|
||
import { SvgIcon } from '@/components/common'
|
||
import { useModuleConfig } from '@/store/modules'
|
||
import { useAuthStore } from '@/store'
|
||
import { VisitMode } from '@/enums/auth'
|
||
|
||
import SvgSrcBaidu from '@/assets/search_engine_svg/baidu.svg'
|
||
import SvgSrcBing from '@/assets/search_engine_svg/bing.svg'
|
||
import SvgSrcGoogle from '@/assets/search_engine_svg/google.svg'
|
||
|
||
withDefaults(defineProps<{
|
||
background?: string
|
||
textColor?: string
|
||
}>(), {
|
||
background: '#2a2a2a6b',
|
||
textColor: 'white',
|
||
})
|
||
|
||
const emits = defineEmits(['itemSearch'])
|
||
|
||
interface State {
|
||
currentSearchEngine: DeskModule.SearchBox.SearchEngine
|
||
searchEngineList: DeskModule.SearchBox.SearchEngine[]
|
||
newWindowOpen: boolean
|
||
}
|
||
|
||
const moduleConfigName = 'deskModuleSearchBox'
|
||
const moduleConfig = useModuleConfig()
|
||
const authStore = useAuthStore()
|
||
const searchTerm = ref('')
|
||
const isFocused = ref(false)
|
||
const searchSelectListShow = ref(false)
|
||
const defaultSearchEngineList = ref<DeskModule.SearchBox.SearchEngine[]>([
|
||
{
|
||
iconSrc: SvgSrcGoogle,
|
||
title: 'Google',
|
||
url: 'https://www.google.com/search?q=%s',
|
||
},
|
||
{
|
||
iconSrc: SvgSrcBaidu,
|
||
title: 'Baidu',
|
||
url: 'https://www.baidu.com/s?wd=%s',
|
||
},
|
||
{
|
||
iconSrc: SvgSrcBing,
|
||
title: 'Bing',
|
||
url: 'https://www.bing.com/search?q=%s',
|
||
},
|
||
])
|
||
|
||
const defaultState: State = {
|
||
currentSearchEngine: defaultSearchEngineList.value[0],
|
||
searchEngineList: [] || defaultSearchEngineList,
|
||
newWindowOpen: false,
|
||
}
|
||
|
||
const state = ref<State>({ ...defaultState })
|
||
|
||
const onFocus = (): void => {
|
||
isFocused.value = true
|
||
}
|
||
|
||
const onBlur = (): void => {
|
||
isFocused.value = false
|
||
}
|
||
|
||
function handleEngineClick() {
|
||
// 访客模式不允许修改
|
||
if (authStore.visitMode === VisitMode.VISIT_MODE_PUBLIC)
|
||
return
|
||
searchSelectListShow.value = !searchSelectListShow.value
|
||
}
|
||
|
||
function handleEngineUpdate(engine: DeskModule.SearchBox.SearchEngine) {
|
||
state.value.currentSearchEngine = engine
|
||
moduleConfig.saveToCloud(moduleConfigName, state.value)
|
||
searchSelectListShow.value = false
|
||
}
|
||
|
||
function handleSearchClick() {
|
||
const url = state.value.currentSearchEngine.url
|
||
const keyword = searchTerm
|
||
// 如果网址中存在 %s,则直接替换为关键字
|
||
const fullUrl = replaceOrAppendKeywordToUrl(url, keyword.value)
|
||
handleClearSearchTerm()
|
||
if (state.value.newWindowOpen)
|
||
window.open(fullUrl)
|
||
else
|
||
window.location.href = fullUrl
|
||
}
|
||
|
||
function replaceOrAppendKeywordToUrl(url: string, keyword: string) {
|
||
// 如果网址中存在 %s,则直接替换为关键字
|
||
if (url.includes('%s'))
|
||
return url.replace('%s', encodeURIComponent(keyword))
|
||
|
||
// 如果网址中不存在 %s,则将关键字追加到末尾
|
||
return url + (keyword ? `${encodeURIComponent(keyword)}` : '')
|
||
}
|
||
|
||
const handleItemSearch = () => {
|
||
emits('itemSearch', searchTerm.value)
|
||
}
|
||
|
||
function handleClearSearchTerm() {
|
||
searchTerm.value = ''
|
||
emits('itemSearch', searchTerm.value)
|
||
}
|
||
|
||
onMounted(() => {
|
||
moduleConfig.getValueByNameFromCloud<State>('deskModuleSearchBox').then(({ code, data }) => {
|
||
if (code === 0)
|
||
state.value = data || defaultState
|
||
else
|
||
state.value = defaultState
|
||
})
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="search-box w-full" @keydown.enter="handleSearchClick" @keydown.esc="handleClearSearchTerm">
|
||
<div class="search-container flex rounded-2xl items-center justify-center text-white w-full" :style="{ background, color: textColor }" :class="{ focused: isFocused }">
|
||
<div class="search-box-btn-engine w-[40px] flex justify-center cursor-pointer" @click="handleEngineClick">
|
||
<NAvatar :src="state.currentSearchEngine.iconSrc" style="background-color: transparent;" :size="20" />
|
||
</div>
|
||
|
||
<input v-model="searchTerm" :placeholder="$t('deskModule.searchBox.inputPlaceholder')" @focus="onFocus" @blur="onBlur" @input="handleItemSearch">
|
||
|
||
<div v-if="searchTerm !== ''" class="search-box-btn-clear w-[25px] mr-[10px] flex justify-center cursor-pointer" @click="handleClearSearchTerm">
|
||
<SvgIcon style="width: 20px;height: 20px;" icon="line-md:close-small" />
|
||
</div>
|
||
<div class="search-box-btn-search w-[25px] flex justify-center cursor-pointer" @click="handleSearchClick">
|
||
<SvgIcon style="width: 20px;height: 20px;" icon="iconamoon:search-fill" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 搜索引擎选择 -->
|
||
<div v-if="searchSelectListShow" class="w-full mt-[10px] rounded-xl p-[10px]" :style="{ background }">
|
||
<div class="flex items-center">
|
||
<div class="flex items-center">
|
||
<div
|
||
v-for="item, index in defaultSearchEngineList"
|
||
:key="index"
|
||
:title="item.title"
|
||
class="w-[40px] h-[40px] mr-[10px] cursor-pointer bg-[#ffffff] flex items-center justify-center rounded-xl"
|
||
@click="handleEngineUpdate(item)"
|
||
>
|
||
<NAvatar :src="item.iconSrc" style="background-color: transparent;" :size="20" />
|
||
</div>
|
||
<!-- <div class="w-[40px] h-[40px] ml-[10px] flex justify-center items-center cursor-pointer" @click="handleEngineClick">
|
||
<NAvatar style="background-color: transparent;" :size="30">
|
||
<SvgIcon icon="lets-icons:setting-alt-fill" style="font-size: 20px;" />
|
||
</NAvatar>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-[10px]">
|
||
<NCheckbox v-model:checked="state.newWindowOpen" @update-checked="moduleConfig.saveToCloud(moduleConfigName, state)">
|
||
<span :style="{ color: textColor }">
|
||
{{ $t('deskModule.searchBox.openWithNewOpen') }}
|
||
</span>
|
||
</NCheckbox>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.search-container {
|
||
border: 1px solid #ccc;
|
||
transition: box-shadow 0.5s,backdrop-filter 0.5s;
|
||
padding: 2px 10px;
|
||
backdrop-filter:blur(2px)
|
||
}
|
||
|
||
.focused, .search-container:hover {
|
||
box-shadow: 0px 0px 30px -5px rgba(41, 41, 41, 0.45);
|
||
-webkit-box-shadow: 0px 0px 30px -5px rgba(0, 0, 0, 0.45);
|
||
-moz-box-shadow: 0px 0px 30px -5px rgba(0, 0, 0, 0.45);
|
||
backdrop-filter:blur(5px)
|
||
}
|
||
|
||
.before {
|
||
left: 10px;
|
||
}
|
||
|
||
.after {
|
||
right: 10px;
|
||
}
|
||
|
||
input {
|
||
background-color: transparent;
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
height: 40px;
|
||
padding: 10px 5px;
|
||
border: none;
|
||
outline: none;
|
||
font-size: 17px;
|
||
}
|
||
</style>
|