SsService.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <script setup lang="ts">
  2. import {useGlobalStore} from "@/stores/global"
  3. import {onMounted} from "vue";
  4. const global = useGlobalStore()
  5. const itemClass = (index: number) => {
  6. switch (index % 5) {
  7. case 0:
  8. return ' hover-scale'
  9. case 1:
  10. return ' hover-scale yellow right'
  11. case 2:
  12. return ' center'
  13. case 3:
  14. return ' hover-scale yellow bottom no-margin-bottom'
  15. case 4:
  16. return ' hover-scale right bottom no-margin-bottom'
  17. }
  18. }
  19. const emit = defineEmits(['loadService', 'loaded'])
  20. const loadService = (categoryId: number, title: string, cover: string) => {
  21. emit('loadService', categoryId, title, cover)
  22. }
  23. onMounted(() => {
  24. emit('loaded', 'service')
  25. })
  26. </script>
  27. <template>
  28. <div class="service">
  29. <template v-for="(item, index) in global.categories">
  30. <div class="service-item" :class="itemClass(index)" @click="loadService(item.id, item.categoryName, item.imgUrl)">
  31. <div class="service-item-content">
  32. <div class="service-item-content-child">
  33. <div class="title">{{ item.categoryName }}</div>
  34. <div class="subject is-pc">{{ item.profile }}</div>
  35. <div class="subject is-mobile">{{ item.profileWap }}</div>
  36. </div>
  37. </div>
  38. <div v-if="index === 2" class="service-item-bg">
  39. <el-image class="service-item-image" fit="contain" :src="getImageUrl(item.imgUrl)"/>
  40. </div>
  41. <el-image v-else class="service-item-image" fit="contain" :src="getImageUrl(item.imgUrl)"/>
  42. </div>
  43. </template>
  44. </div>
  45. </template>
  46. <style scoped lang="scss">
  47. .service {
  48. display: flex;
  49. flex-wrap: wrap;
  50. justify-content: space-between;
  51. position: relative;
  52. .service-item {
  53. width: calc(50% - 0.44rem);
  54. position: relative;
  55. height: 7.5rem;
  56. border-radius: var(--border-radius);
  57. overflow: hidden;
  58. background: linear-gradient(180deg, rgba(250, 255, 253, 0.8), rgba(225, 245, 248, 0.8));
  59. box-shadow: 0 0.25rem 1.25rem 0 rgba(52, 149, 239, 0.4);
  60. margin-bottom: 1rem;
  61. cursor: pointer;
  62. min-height: var(--min-touch-target);
  63. .service-item-content {
  64. position: absolute;
  65. top: 0;
  66. left: 0;
  67. right: 0;
  68. bottom: 0;
  69. z-index: 2;
  70. padding: calc(var(--spacing-unit) * 1.5) calc(var(--spacing-unit) * 1.25);
  71. display: flex;
  72. .service-item-content-child {
  73. position: absolute;
  74. width: calc(100% - 3rem);
  75. .title {
  76. color: #101333;
  77. font-size: var(--subtitle-font-size);
  78. font-weight: 600;
  79. }
  80. .subject {
  81. font-size: var(--small-font-size);
  82. line-height: 1.25em;
  83. color: #7E8AA2;
  84. &.is-mobile {
  85. width: 72%;
  86. }
  87. }
  88. }
  89. }
  90. .service-item-image {
  91. position: absolute;
  92. bottom: 0;
  93. right: 3.8rem;
  94. z-index: 1;
  95. width: 7.3rem;
  96. height: 5.56rem;
  97. opacity: 0.2;
  98. }
  99. &.yellow {
  100. background: linear-gradient(180deg, rgba(255, 255, 255, 0.7), rgba(246, 240, 239, 0.7));
  101. }
  102. &.right {
  103. text-align: right;
  104. .service-item-content {
  105. justify-content: end;
  106. .service-item-content-child {
  107. .subject {
  108. &.is-mobile {
  109. float: right;
  110. }
  111. }
  112. }
  113. }
  114. .service-item-image {
  115. right: unset;
  116. left: 3.8rem;
  117. }
  118. }
  119. &.bottom {
  120. .service-item-content {
  121. .service-item-content-child {
  122. position: absolute;
  123. bottom: calc(var(--spacing-unit) * 1.5);
  124. }
  125. }
  126. }
  127. &.no-margin-bottom {
  128. margin-bottom: 0;
  129. }
  130. &.center {
  131. position: absolute;
  132. top: 50%;
  133. left: 50%;
  134. transform: translate(-50%, -50%);
  135. z-index: 10;
  136. text-align: center;
  137. width: 12rem;
  138. height: 12rem;
  139. border-radius: 6rem;
  140. box-shadow: inset 0 0.25rem 1.25rem 0 rgba(52, 149, 239, 0.4);
  141. background: linear-gradient(90deg, #c2dff9, #c6e2fa);
  142. .service-item-content {
  143. transition: all 0.3s ease;
  144. .service-item-content-child {
  145. .subject {
  146. &.is-mobile {
  147. height: 2rem;
  148. margin: 0 auto;
  149. overflow: hidden;
  150. display: -webkit-box;
  151. -webkit-box-orient: vertical;
  152. -webkit-line-clamp: 2;
  153. text-overflow: ellipsis;
  154. }
  155. }
  156. }
  157. }
  158. .service-item-bg {
  159. transition: all 0.3s ease;
  160. }
  161. &:hover {
  162. .service-item-content {
  163. transform: scale(1.1);
  164. }
  165. .service-item-bg {
  166. transform: scale(1.1);
  167. }
  168. }
  169. .service-item-content {
  170. width: 100%;
  171. padding: unset;
  172. .service-item-content-child {
  173. position: absolute;
  174. top: 50%;
  175. left: 50%;
  176. transform: translate(-50%, -50%);
  177. }
  178. }
  179. .service-item-bg {
  180. position: absolute;
  181. top: 1rem;
  182. left: 1rem;
  183. right: 1rem;
  184. bottom: 1rem;
  185. border-radius: 5rem;
  186. z-index: 1;
  187. background: linear-gradient(180deg, #FFFFFF, #E8EBFF);
  188. box-shadow: 0 0.25rem 1.25rem 0 rgba(52, 149, 239, 0.4);
  189. }
  190. .service-item-image {
  191. top: 50%;
  192. left: 50%;
  193. right: unset;
  194. bottom: unset;
  195. width: 6rem;
  196. height: 6rem;
  197. transform: translate(-50%, -50%);
  198. }
  199. }
  200. }
  201. }
  202. /* 1080x1920 中等尺寸设备 */
  203. @media screen and (min-width: 751px) and (max-width: 1200px) and (min-height: 1700px) {
  204. .service {
  205. .service-item {
  206. height: 9rem;
  207. box-shadow: 0 0.5rem 1.5rem 0 rgba(52, 149, 239, 0.5);
  208. margin-bottom: 1.25rem;
  209. .service-item-content {
  210. padding: calc(var(--spacing-unit) * 2) calc(var(--spacing-unit) * 1.75);
  211. .service-item-content-child {
  212. width: calc(100% - 3.5rem);
  213. .title {
  214. font-size: 1.25rem; /* 1.125rem → 1.25rem */
  215. margin-bottom: 0.5rem;
  216. }
  217. }
  218. }
  219. .service-item-image {
  220. width: 8.5rem;
  221. height: 6.5rem;
  222. right: 4.5rem;
  223. }
  224. &.right {
  225. .service-item-image {
  226. left: 4.5rem;
  227. }
  228. }
  229. &.bottom {
  230. .service-item-content {
  231. .service-item-content-child {
  232. bottom: calc(var(--spacing-unit) * 2);
  233. }
  234. }
  235. }
  236. &.center {
  237. width: 14rem;
  238. height: 14rem;
  239. .service-item-content {
  240. .service-item-content-child {
  241. .title {
  242. font-size: 1.5rem; /* 1.25rem → 1.5rem */
  243. }
  244. }
  245. }
  246. .service-item-bg {
  247. top: 1.25rem;
  248. left: 1.25rem;
  249. right: 1.25rem;
  250. bottom: 1.25rem;
  251. }
  252. .service-item-image {
  253. width: 7rem;
  254. height: 7rem;
  255. }
  256. }
  257. }
  258. }
  259. }
  260. @media screen and (max-width: 1000px) {
  261. .service {
  262. .service-item {
  263. &.center {
  264. width: 10rem;
  265. height: 10rem;
  266. .service-item-bg {
  267. top: 1rem;
  268. left: 1rem;
  269. right: 1rem;
  270. bottom: 1rem;
  271. }
  272. .service-item-image {
  273. width: 4.12rem;
  274. height: 4.25rem;
  275. }
  276. }
  277. }
  278. }
  279. }
  280. @media screen and (max-width: 750px) {
  281. .service {
  282. .service-item {
  283. height: 5.25rem;
  284. .service-item-content {
  285. padding: 1rem 0.75rem;
  286. .service-item-content-child {
  287. width: calc(100% - 1.5rem);
  288. }
  289. }
  290. .service-item-image {
  291. width: 4.25rem;
  292. height: 3.81rem;
  293. right: 2rem;
  294. }
  295. &.right {
  296. .service-item-image {
  297. left: 2.06rem;
  298. }
  299. }
  300. &.bottom {
  301. .service-item-content {
  302. .service-item-content-child {
  303. bottom: 1rem;
  304. }
  305. }
  306. }
  307. &.center {
  308. width: 7.5rem;
  309. height: 7.5rem;
  310. .service-item-bg {
  311. top: 0.75rem;
  312. left: 0.75rem;
  313. right: 0.75rem;
  314. bottom: 0.75rem;
  315. }
  316. .service-item-image {
  317. width: 4.12rem;
  318. height: 4.25rem;
  319. }
  320. }
  321. }
  322. }
  323. }
  324. </style>