index.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <template>
  2. <div class="web-home" :style="{
  3. backgroundImage: `url('${ThemeStore.webBgImg}')`
  4. }">
  5. <div class="title">
  6. <img :src="ThemeStore.titleLogo"/>
  7. </div>
  8. <div class="area">
  9. <div class="selected">
  10. <div class="label">搜索范围:</div>
  11. <div class="value" v-if="!noAreaCpt">
  12. <template v-if="searchAreaCpt.text">
  13. {{searchAreaCpt.text}}
  14. </template>
  15. <template v-else>
  16. <template v-for="item in searchAreaCpt.arr">
  17. <div>{{item.treeName}}</div>
  18. </template>
  19. </template>
  20. </div>
  21. </div>
  22. <div class="search-input">
  23. <template v-if="!noAreaCpt">
  24. <div class="left-select __hover" @click="state.showArea = true">
  25. 搜索范围<SvgIcon name="arrow_1" rotate="90" size="14" color="var(--cus-text-color-3)"/>
  26. </div>
  27. </template>
  28. <template v-else>
  29. <div class="left-select __disabled">
  30. 暂无范围
  31. </div>
  32. </template>
  33. <el-input v-model="state.searchText" :placeholder="!noAreaCpt ? '请输入关键字进行查询' : '请先配置搜索范围'" @keyup.enter="toList(state.searchText)" :disabled="noAreaCpt"/>
  34. <div class="right-icon __hover" @click="toList(state.searchText)">
  35. <SvgIcon name="search_1" color="var(--cus-main-color)" size="40"/>
  36. </div>
  37. </div>
  38. </div>
  39. <div class="history" v-if="state.historyList?.length > 0">
  40. <div class="label">搜索记录</div>
  41. <div class="result">
  42. <template v-for="(item, index) in state.historyList">
  43. <span class="__hover" @click="toList(item.keyword, true)">{{index + 1}}.{{item.keyword}}</span>
  44. </template>
  45. </div>
  46. </div>
  47. <CusDialog
  48. :show="state.showArea"
  49. @onClose="$emit('update:show', false)"
  50. width="1000px"
  51. height="auto"
  52. submit-text="关闭"
  53. :show-close="false"
  54. @onSubmit="state.showArea = false"
  55. >
  56. <CusTab :tabs="state.areaList" type="type1" v-model:param="state.areaTab" label-key="treeName" value-key="treeId"/>
  57. <div class="index-list">
  58. <div class="all">
  59. <div class="__check" :class="{active: indexTabAllCpt}" @click="onIndexTabAll">全选</div>
  60. </div>
  61. <div class="list">
  62. <template v-for="(item, index) in indexListCpt">
  63. <div class="list-item">
  64. <div class="__check" :class="{active: item.__select}" @click="item.__select = !item.__select">{{ item.treeName }}</div>
  65. </div>
  66. </template>
  67. </div>
  68. </div>
  69. </CusDialog>
  70. </div>
  71. </template>
  72. <script setup lang="ts">
  73. import {computed, getCurrentInstance, onMounted, reactive} from "vue";
  74. import router from "@/router";
  75. import {ElMessage} from "element-plus";
  76. import {useAppStore, useThemeStore, useWebStore} from "@/stores";
  77. import {mockGetSearchHistory} from "@/api/modules/mock/mock";
  78. import {searchLogsGetKeyWordByUserId} from "@/api/modules/web/list";
  79. const {proxy} = getCurrentInstance()
  80. const AppStore = useAppStore()
  81. const WebStore = useWebStore()
  82. const ThemeStore = useThemeStore()
  83. const state: any = reactive({
  84. searchText: '',
  85. historyList: [],
  86. areaList: [],
  87. showArea: false,
  88. areaTab: ''
  89. })
  90. const indexListCpt = computed(() => {
  91. return state.areaList.filter(v => v.treeId === state.areaTab)?.[0]?.children || []
  92. })
  93. const indexTabAllCpt = computed(() => {
  94. return indexListCpt.value.every(v => v.__select)
  95. })
  96. const searchAreaCpt = computed(() => {
  97. const obj = {
  98. text: '',
  99. arr: []
  100. }
  101. let i = 0
  102. state.areaList.forEach(v => {
  103. v.children.forEach(c => {
  104. i++
  105. if (c.__select) {
  106. obj.arr.push(c)
  107. }
  108. })
  109. })
  110. if (i === obj.arr.length) {
  111. obj.arr = []
  112. }
  113. if (obj.arr.length === 0) {
  114. obj.text = '全部'
  115. }
  116. return obj
  117. })
  118. const noAreaCpt = computed(() => {
  119. return !(state.areaList.length > 0)
  120. })
  121. const initHistory = () => {
  122. searchLogsGetKeyWordByUserId(proxy.$util.formatGetParam({
  123. userId: AppStore.userInfo?.id,
  124. size: 10
  125. })).then(res => {
  126. state.historyList = res.data
  127. })
  128. }
  129. const initArea = () => {
  130. WebStore.getSearchAreaTree().then(({roleTree}: any) => {
  131. state.areaList = JSON.parse(JSON.stringify(roleTree))
  132. state.areaTab = state.areaList[0]?.treeId
  133. })
  134. }
  135. const onIndexTabAll = () => {
  136. const flag = JSON.parse(JSON.stringify(indexTabAllCpt.value))
  137. indexListCpt.value.forEach(v => {
  138. v.__select = !flag
  139. })
  140. }
  141. const toList = (text, isAll = false) => {
  142. if (text) {
  143. const routerUrl = router.resolve({
  144. name: '4f6dd2ea-7c0a-4923-9a57-932ef42235f6',
  145. query: {
  146. text,
  147. index: isAll ? '' : searchAreaCpt.value.arr.map(v => v.treeId).join(',')
  148. }
  149. });
  150. window.open(routerUrl.href, "_blank");
  151. } else {
  152. ElMessage({
  153. message: '请输入关键字进行查询!',
  154. grouping: true,
  155. type: 'warning',
  156. })
  157. }
  158. }
  159. onMounted(() => {
  160. initHistory()
  161. initArea()
  162. })
  163. </script>
  164. <style lang="scss" scoped>
  165. .web-home {
  166. width: 100%;
  167. height: 100%;
  168. background-size: 100% 100%;
  169. background-repeat: no-repeat;
  170. display: flex;
  171. flex-direction: column;
  172. align-items: center;
  173. gap: 40px;
  174. .title {
  175. margin-top: 300px;
  176. >img {
  177. width: 100%;
  178. }
  179. }
  180. .area {
  181. width: 1000px;
  182. .selected {
  183. display: flex;
  184. line-height: 30px;
  185. font-size: 16px;
  186. .label {
  187. font-weight: 500;
  188. color: var(--cus-main-color);
  189. padding-left: 16px;
  190. }
  191. .value {
  192. flex: 1;
  193. color: var(--cus-text-color-2);
  194. display: flex;
  195. flex-wrap: wrap;
  196. column-gap: 20px;
  197. }
  198. }
  199. .search-input {
  200. margin-top: 10px;
  201. display: flex;
  202. align-items: center;
  203. width: 100%;
  204. height: 60px;
  205. background: rgba(255,255,255,0.9);
  206. box-shadow: 0px 0px 2px 0px rgba(167,220,255,0.5);
  207. border-radius: 60px;
  208. border: 1px solid var(--cus-main-color);
  209. .left-select {
  210. display: flex;
  211. align-items: center;
  212. justify-content: center;
  213. width: 184px;
  214. gap: 17px;
  215. color: var(--cus-text-color-4);
  216. font-size: 18px;
  217. position: relative;
  218. &:after {
  219. content: '';
  220. position: absolute;
  221. right: 0;
  222. height: 40px;
  223. width: 1px;
  224. background-color: var(--cus-main-color);
  225. }
  226. }
  227. :deep(.el-input) {
  228. font-size: 18px;
  229. color: var(--cus-text-color-2);
  230. .el-input__wrapper {
  231. box-shadow: none !important;
  232. background-color: transparent;
  233. .el-input__inner {
  234. &::placeholder {
  235. color: var(--cus-text-color-4);
  236. }
  237. }
  238. }
  239. }
  240. .right-icon {
  241. margin-right: 20px;
  242. }
  243. }
  244. }
  245. .history {
  246. width: 1000px;
  247. .label {
  248. font-weight: 500;
  249. font-size: 16px;
  250. color: var(--cus-main-color);
  251. padding-left: 16px;
  252. }
  253. .result {
  254. margin-top: 10px;
  255. width: 100%;
  256. padding: 16px;
  257. background: rgba(255,255,255,0.8);
  258. box-shadow: 0px 4px 4px 0px rgba(255,255,255,0.15);
  259. border-radius: 8px;
  260. font-weight: 400;
  261. font-size: 16px;
  262. color: var(--cus-text-color-2);
  263. display: flex;
  264. flex-wrap: wrap;
  265. gap: 10px 32px;
  266. }
  267. }
  268. }
  269. .cus-tab {
  270. padding: 30px 0 22px 28px;
  271. :deep(.cus-tab-item::after) {
  272. bottom: -23px !important;
  273. }
  274. }
  275. .index-list {
  276. padding: 20px 28px 0;
  277. .list {
  278. margin-top: 10px;
  279. display: flex;
  280. flex-wrap: wrap;
  281. gap: 30px;
  282. }
  283. }
  284. </style>