feat(checkin): 启用多附件功能并添加文本折叠与媒体标签页
- 在环境变量中启用多附件功能,支持图片、视频和音频的标签页切换 - 为打卡卡片添加文本内容折叠/展开功能,当文本溢出时显示"全文/收起"按钮 - 重构媒体展示逻辑,当存在多种媒体类型时使用标签页组织,单一类型时保持原有布局 - 添加单元测试确保组件功能正确性,配置Vitest测试环境 - 更新TypeScript类型定义和开发依赖以支持测试
Showing
9 changed files
with
302 additions
and
14 deletions
| ... | @@ -17,7 +17,7 @@ VITE_CONSOLE = 0 | ... | @@ -17,7 +17,7 @@ VITE_CONSOLE = 0 |
| 17 | VITE_APPID=微信appID | 17 | VITE_APPID=微信appID |
| 18 | 18 | ||
| 19 | # 是否开启多附件功能 | 19 | # 是否开启多附件功能 |
| 20 | -VITE_CHECKIN_MULTI_ATTACHMENT = 0 | 20 | +VITE_CHECKIN_MULTI_ATTACHMENT = 1 |
| 21 | 21 | ||
| 22 | # 是否开启打卡草稿缓存功能 | 22 | # 是否开启打卡草稿缓存功能 |
| 23 | VITE_CHECKIN_DRAFT_CACHE = 0 | 23 | VITE_CHECKIN_DRAFT_CACHE = 0 | ... | ... |
This diff could not be displayed because it is too large.
| ... | @@ -58,9 +58,11 @@ | ... | @@ -58,9 +58,11 @@ |
| 58 | "devDependencies": { | 58 | "devDependencies": { |
| 59 | "@vitejs/plugin-vue": "^5.2.1", | 59 | "@vitejs/plugin-vue": "^5.2.1", |
| 60 | "@vitejs/plugin-vue-jsx": "^4.1.2", | 60 | "@vitejs/plugin-vue-jsx": "^4.1.2", |
| 61 | + "@vue/test-utils": "^2.4.6", | ||
| 61 | "@vueuse/core": "^13.0.0", | 62 | "@vueuse/core": "^13.0.0", |
| 62 | "autoprefixer": "^10.4.19", | 63 | "autoprefixer": "^10.4.19", |
| 63 | "axios": "^1.8.4", | 64 | "axios": "^1.8.4", |
| 65 | + "jsdom": "^24.1.3", | ||
| 64 | "less": "^4.2.2", | 66 | "less": "^4.2.2", |
| 65 | "postcss": "^8.4.35", | 67 | "postcss": "^8.4.35", |
| 66 | "qs": "^6.14.0", | 68 | "qs": "^6.14.0", | ... | ... |
| ... | @@ -71,6 +71,6 @@ declare global { | ... | @@ -71,6 +71,6 @@ declare global { |
| 71 | // for type re-export | 71 | // for type re-export |
| 72 | declare global { | 72 | declare global { |
| 73 | // @ts-ignore | 73 | // @ts-ignore |
| 74 | - export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' | 74 | + export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' |
| 75 | import('vue') | 75 | import('vue') |
| 76 | } | 76 | } | ... | ... |
| ... | @@ -37,21 +37,84 @@ | ... | @@ -37,21 +37,84 @@ |
| 37 | <div class="post-content"> | 37 | <div class="post-content"> |
| 38 | <slot name="content-top"></slot> | 38 | <slot name="content-top"></slot> |
| 39 | <PostCountModel :post-data="post" /> | 39 | <PostCountModel :post-data="post" /> |
| 40 | - <div class="post-text">{{ post.content }}</div> | 40 | + <div class="post-text-wrapper relative"> |
| 41 | + <div ref="textRef" class="post-text" :class="{ 'line-clamp-5': !isExpanded }"> | ||
| 42 | + {{ post.content }} | ||
| 43 | + </div> | ||
| 44 | + <div v-if="showExpandBtn" class="expand-btn text-blue-500 text-sm mt-1 cursor-pointer" | ||
| 45 | + @click.stop="toggleExpand"> | ||
| 46 | + {{ isExpanded ? '收起' : '全文' }} | ||
| 47 | + </div> | ||
| 48 | + </div> | ||
| 41 | 49 | ||
| 42 | <!-- 媒体内容 --> | 50 | <!-- 媒体内容 --> |
| 43 | - <div class="post-media"> | 51 | + <div class="post-media mt-2"> |
| 52 | + <!-- 多附件Tab模式 --> | ||
| 53 | + <div v-if="mediaTabs.length > 1" class="media-tabs"> | ||
| 54 | + <van-tabs v-model:active="activeTab" shrink animated swipeable color="#4caf50"> | ||
| 55 | + <van-tab v-for="tab in mediaTabs" :key="tab.name" :title="tab.label" :name="tab.name"> | ||
| 56 | + <div class="pt-2"> | ||
| 57 | + <!-- 图片内容 --> | ||
| 58 | + <template v-if="tab.name === 'image'"> | ||
| 59 | + <div class="post-images"> | ||
| 60 | + <div class="post-image-item" v-for="(image, index) in post.images" :key="index"> | ||
| 61 | + <van-image width="100%" height="100%" fit="cover" | ||
| 62 | + :src="getOptimizedUrl(image)" radius="5" | ||
| 63 | + @click="openImagePreview(index)" /> | ||
| 64 | + </div> | ||
| 65 | + </div> | ||
| 66 | + </template> | ||
| 67 | + | ||
| 68 | + <!-- 视频内容 --> | ||
| 69 | + <template v-if="tab.name === 'video'"> | ||
| 70 | + <div v-for="(v, idx) in post.videoList" :key="idx"> | ||
| 71 | + <!-- 封面图 --> | ||
| 72 | + <div v-if="v.video && !v.isPlaying" | ||
| 73 | + class="relative w-full rounded-lg overflow-hidden" | ||
| 74 | + style="aspect-ratio: 16/9; margin-bottom: 1rem;"> | ||
| 75 | + <img :src="getOptimizedUrl(v.videoCover || 'https://cdn.ipadbiz.cn/mlaj/images/cover_video_2.png')" | ||
| 76 | + :alt="post.content" class="w-full h-full object-contain" /> | ||
| 77 | + <div class="absolute inset-0 flex items-center justify-center cursor-pointer bg-black/20" | ||
| 78 | + @click="startPlay(v)"> | ||
| 79 | + <div | ||
| 80 | + class="w-16 h-16 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors"> | ||
| 81 | + <van-icon name="play-circle-o" class="text-white" size="40" /> | ||
| 82 | + </div> | ||
| 83 | + </div> | ||
| 84 | + </div> | ||
| 85 | + <!-- 视频播放器 --> | ||
| 86 | + <VideoPlayer v-if="v.video && v.isPlaying" :video-url="v.video" | ||
| 87 | + :video-id="v.id || `video-${post.id}-${idx}`" | ||
| 88 | + :use-native-on-ios="false" class="post-video rounded-lg overflow-hidden" | ||
| 89 | + :ref="(el) => setVideoRef(el, v.id)" | ||
| 90 | + @onPlay="(player) => handleVideoPlay(player, v)" | ||
| 91 | + @onPause="handleVideoPause" /> | ||
| 92 | + </div> | ||
| 93 | + </template> | ||
| 94 | + | ||
| 95 | + <!-- 音频内容 --> | ||
| 96 | + <template v-if="tab.name === 'audio'"> | ||
| 97 | + <AudioPlayer v-if="post.audio && post.audio.length" :songs="post.audio" | ||
| 98 | + class="post-audio" :id="post.id" :ref="(el) => setAudioRef(el, post.id)" | ||
| 99 | + @play="handleAudioPlay" /> | ||
| 100 | + </template> | ||
| 101 | + </div> | ||
| 102 | + </van-tab> | ||
| 103 | + </van-tabs> | ||
| 104 | + </div> | ||
| 105 | + | ||
| 106 | + <!-- 单一附件模式 (保持原有布局) --> | ||
| 107 | + <div v-else> | ||
| 44 | <!-- 图片列表 --> | 108 | <!-- 图片列表 --> |
| 45 | - <div v-if="post.images.length" class="post-images"> | 109 | + <div v-if="post.images && post.images.length" class="post-images"> |
| 46 | <div class="post-image-item" v-for="(image, index) in post.images" :key="index"> | 110 | <div class="post-image-item" v-for="(image, index) in post.images" :key="index"> |
| 47 | <van-image width="100%" height="100%" fit="cover" :src="getOptimizedUrl(image)" radius="5" | 111 | <van-image width="100%" height="100%" fit="cover" :src="getOptimizedUrl(image)" radius="5" |
| 48 | @click="openImagePreview(index)" /> | 112 | @click="openImagePreview(index)" /> |
| 49 | </div> | 113 | </div> |
| 50 | </div> | 114 | </div> |
| 51 | - <van-image-preview v-if="post.images.length" v-model:show="showLocalImagePreview" :images="post.images" | ||
| 52 | - :start-position="localStartPosition" :show-index="true" /> | ||
| 53 | 115 | ||
| 54 | <!-- 视频列表 --> | 116 | <!-- 视频列表 --> |
| 117 | + <div v-if="post.videoList && post.videoList.length"> | ||
| 55 | <div v-for="(v, idx) in post.videoList" :key="idx"> | 118 | <div v-for="(v, idx) in post.videoList" :key="idx"> |
| 56 | <!-- 封面图 --> | 119 | <!-- 封面图 --> |
| 57 | <div v-if="v.video && !v.isPlaying" class="relative w-full rounded-lg overflow-hidden" | 120 | <div v-if="v.video && !v.isPlaying" class="relative w-full rounded-lg overflow-hidden" |
| ... | @@ -68,14 +131,19 @@ | ... | @@ -68,14 +131,19 @@ |
| 68 | </div> | 131 | </div> |
| 69 | <!-- 视频播放器 --> | 132 | <!-- 视频播放器 --> |
| 70 | <VideoPlayer v-if="v.video && v.isPlaying" :video-url="v.video" | 133 | <VideoPlayer v-if="v.video && v.isPlaying" :video-url="v.video" |
| 71 | - :video-id="v.id || `video-${post.id}-${idx}`" :use-native-on-ios="false" class="post-video rounded-lg overflow-hidden" | 134 | + :video-id="v.id || `video-${post.id}-${idx}`" :use-native-on-ios="false" |
| 72 | - :ref="(el) => setVideoRef(el, v.id)" @onPlay="(player) => handleVideoPlay(player, v)" | 135 | + class="post-video rounded-lg overflow-hidden" :ref="(el) => setVideoRef(el, v.id)" |
| 73 | - @onPause="handleVideoPause" /> | 136 | + @onPlay="(player) => handleVideoPlay(player, v)" @onPause="handleVideoPause" /> |
| 137 | + </div> | ||
| 74 | </div> | 138 | </div> |
| 75 | 139 | ||
| 76 | <!-- 音频播放器 --> | 140 | <!-- 音频播放器 --> |
| 77 | - <AudioPlayer v-if="post.audio && post.audio.length" :songs="post.audio" class="post-audio" :id="post.id" | 141 | + <AudioPlayer v-if="post.audio && post.audio.length" :songs="post.audio" class="post-audio" |
| 78 | - :ref="(el) => setAudioRef(el, post.id)" @play="handleAudioPlay" /> | 142 | + :id="post.id" :ref="(el) => setAudioRef(el, post.id)" @play="handleAudioPlay" /> |
| 143 | + </div> | ||
| 144 | + | ||
| 145 | + <van-image-preview v-if="post.images && post.images.length" v-model:show="showLocalImagePreview" | ||
| 146 | + :images="post.images" :start-position="localStartPosition" :show-index="true" /> | ||
| 79 | </div> | 147 | </div> |
| 80 | </div> | 148 | </div> |
| 81 | 149 | ||
| ... | @@ -96,7 +164,36 @@ | ... | @@ -96,7 +164,36 @@ |
| 96 | </template> | 164 | </template> |
| 97 | 165 | ||
| 98 | <script setup> | 166 | <script setup> |
| 99 | -import { ref } from 'vue' | 167 | +/** |
| 168 | + * CheckinCard 打卡卡片组件 | ||
| 169 | + * @description 展示用户打卡内容的卡片,支持文本折叠、多媒体(图片/视频/音频)展示、点赞及自定义操作。 | ||
| 170 | + * | ||
| 171 | + * @example | ||
| 172 | + * <template> | ||
| 173 | + * <CheckinCard | ||
| 174 | + * :post="postData" | ||
| 175 | + * :use-cdn-optimization="true" | ||
| 176 | + * @like="handleLike" | ||
| 177 | + * @edit="handleEdit" | ||
| 178 | + * @delete="handleDelete" | ||
| 179 | + * /> | ||
| 180 | + * </template> | ||
| 181 | + * | ||
| 182 | + * // Example data setup | ||
| 183 | + * const postData = { | ||
| 184 | + * id: 1, | ||
| 185 | + * user: { name: 'User', avatar: 'url', time: '2023-01-01' }, | ||
| 186 | + * content: 'Post content...', | ||
| 187 | + * images: ['img1.jpg'], | ||
| 188 | + * videoList: [{ video: 'vid1.mp4', videoCover: 'cover.jpg' }], | ||
| 189 | + * audio: [], | ||
| 190 | + * likes: 10, | ||
| 191 | + * is_liked: false, | ||
| 192 | + * is_my: true | ||
| 193 | + * } | ||
| 194 | + * const handleLike = (post) => console.log('like', post) | ||
| 195 | + */ | ||
| 196 | +import { ref, computed, watchEffect, onMounted, nextTick, watch } from 'vue' | ||
| 100 | import PostCountModel from "@/components/count/postCountModel.vue"; | 197 | import PostCountModel from "@/components/count/postCountModel.vue"; |
| 101 | import VideoPlayer from "@/components/media/VideoPlayer.vue"; | 198 | import VideoPlayer from "@/components/media/VideoPlayer.vue"; |
| 102 | import AudioPlayer from "@/components/media/AudioPlayer.vue"; | 199 | import AudioPlayer from "@/components/media/AudioPlayer.vue"; |
| ... | @@ -121,6 +218,57 @@ const props = defineProps({ | ... | @@ -121,6 +218,57 @@ const props = defineProps({ |
| 121 | 218 | ||
| 122 | const emit = defineEmits(['like', 'edit', 'delete', 'video-play', 'audio-play']) | 219 | const emit = defineEmits(['like', 'edit', 'delete', 'video-play', 'audio-play']) |
| 123 | 220 | ||
| 221 | +// 文本折叠逻辑 | ||
| 222 | +const isExpanded = ref(false) | ||
| 223 | +const showExpandBtn = ref(false) | ||
| 224 | +const textRef = ref(null) | ||
| 225 | + | ||
| 226 | +/** | ||
| 227 | + * @description 切换文本展开/收起状态 | ||
| 228 | + */ | ||
| 229 | +const toggleExpand = () => { | ||
| 230 | + isExpanded.value = !isExpanded.value | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | +/** | ||
| 234 | + * @description 检查文本是否溢出 | ||
| 235 | + */ | ||
| 236 | +const checkTextOverflow = () => { | ||
| 237 | + if (textRef.value) { | ||
| 238 | + // 如果滚动高度大于客户区高度,说明有溢出(因为设置了 line-clamp) | ||
| 239 | + showExpandBtn.value = textRef.value.scrollHeight > textRef.value.clientHeight | ||
| 240 | + } | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +onMounted(() => { | ||
| 244 | + nextTick(() => { | ||
| 245 | + checkTextOverflow() | ||
| 246 | + }) | ||
| 247 | +}) | ||
| 248 | + | ||
| 249 | +watch(() => props.post.content, () => { | ||
| 250 | + isExpanded.value = false // Reset expansion on content change | ||
| 251 | + nextTick(() => { | ||
| 252 | + checkTextOverflow() | ||
| 253 | + }) | ||
| 254 | +}) | ||
| 255 | + | ||
| 256 | +// 多媒体Tab逻辑 | ||
| 257 | +const activeTab = ref('') | ||
| 258 | +const mediaTabs = computed(() => { | ||
| 259 | + const tabs = [] | ||
| 260 | + if (props.post.images && props.post.images.length) tabs.push({ label: '图片', name: 'image' }) | ||
| 261 | + if (props.post.videoList && props.post.videoList.length) tabs.push({ label: '视频', name: 'video' }) | ||
| 262 | + if (props.post.audio && props.post.audio.length) tabs.push({ label: '音频', name: 'audio' }) | ||
| 263 | + return tabs | ||
| 264 | +}) | ||
| 265 | + | ||
| 266 | +watchEffect(() => { | ||
| 267 | + if (mediaTabs.value.length > 0 && !activeTab.value) { | ||
| 268 | + activeTab.value = mediaTabs.value[0].name | ||
| 269 | + } | ||
| 270 | +}) | ||
| 271 | + | ||
| 124 | // 图片预览状态 | 272 | // 图片预览状态 |
| 125 | const showLocalImagePreview = ref(false) | 273 | const showLocalImagePreview = ref(false) |
| 126 | const localStartPosition = ref(0) | 274 | const localStartPosition = ref(0) |
| ... | @@ -256,6 +404,14 @@ defineExpose({ | ... | @@ -256,6 +404,14 @@ defineExpose({ |
| 256 | </script> | 404 | </script> |
| 257 | 405 | ||
| 258 | <style lang="less" scoped> | 406 | <style lang="less" scoped> |
| 407 | +.line-clamp-5 { | ||
| 408 | + display: -webkit-box; | ||
| 409 | + --webkit-box-orient: vertical; | ||
| 410 | + --webkit-line-clamp: 5; | ||
| 411 | + overflow: hidden; | ||
| 412 | + text-overflow: ellipsis; | ||
| 413 | +} | ||
| 414 | + | ||
| 259 | .post-card { | 415 | .post-card { |
| 260 | background: #fff; | 416 | background: #fff; |
| 261 | border-radius: 10px; | 417 | border-radius: 10px; | ... | ... |
| 1 | +import { mount } from '@vue/test-utils' | ||
| 2 | +import { describe, it, expect } from 'vitest' | ||
| 3 | +import CheckinCard from '../CheckinCard.vue' | ||
| 4 | + | ||
| 5 | +describe('CheckinCard.vue', () => { | ||
| 6 | + const defaultPost = { | ||
| 7 | + id: 1, | ||
| 8 | + user: { name: 'Test User', avatar: '' }, | ||
| 9 | + content: 'Test Content', | ||
| 10 | + images: [], | ||
| 11 | + videoList: [], | ||
| 12 | + audio: [], | ||
| 13 | + likes: 0, | ||
| 14 | + is_liked: false, | ||
| 15 | + is_my: false | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + const globalStubs = { | ||
| 19 | + 'van-image': true, | ||
| 20 | + 'van-row': true, | ||
| 21 | + 'van-col': true, | ||
| 22 | + 'van-icon': true, | ||
| 23 | + 'van-image-preview': true, | ||
| 24 | + 'van-tabs': { template: '<div><slot /></div>' }, | ||
| 25 | + 'van-tab': { name: 'van-tab', template: '<div><slot /></div>', props: ['title'] }, | ||
| 26 | + 'PostCountModel': true, | ||
| 27 | + 'VideoPlayer': true, | ||
| 28 | + 'AudioPlayer': true | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + it('renders content correctly', () => { | ||
| 32 | + const wrapper = mount(CheckinCard, { | ||
| 33 | + props: { post: defaultPost }, | ||
| 34 | + global: { | ||
| 35 | + stubs: globalStubs | ||
| 36 | + } | ||
| 37 | + }) | ||
| 38 | + expect(wrapper.text()).toContain('Test Content') | ||
| 39 | + }) | ||
| 40 | + | ||
| 41 | + it('shows expand button when content overflows', async () => { | ||
| 42 | + const wrapper = mount(CheckinCard, { | ||
| 43 | + props: { post: { ...defaultPost, content: 'Long content...' } }, | ||
| 44 | + global: { | ||
| 45 | + stubs: globalStubs | ||
| 46 | + } | ||
| 47 | + }) | ||
| 48 | + | ||
| 49 | + const textEl = wrapper.find('.post-text').element | ||
| 50 | + Object.defineProperty(textEl, 'scrollHeight', { value: 200, configurable: true }) | ||
| 51 | + Object.defineProperty(textEl, 'clientHeight', { value: 100, configurable: true }) | ||
| 52 | + | ||
| 53 | + await wrapper.setProps({ post: { ...defaultPost, content: 'Updated Long Content' } }) | ||
| 54 | + await wrapper.vm.$nextTick() | ||
| 55 | + }) | ||
| 56 | + | ||
| 57 | + it('shows tabs when multiple media types exist', () => { | ||
| 58 | + const postWithMultiMedia = { | ||
| 59 | + ...defaultPost, | ||
| 60 | + images: ['img1.jpg'], | ||
| 61 | + videoList: [{ id: 1, video: 'vid1.mp4' }], | ||
| 62 | + audio: [] | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + const wrapper = mount(CheckinCard, { | ||
| 66 | + props: { post: postWithMultiMedia }, | ||
| 67 | + global: { | ||
| 68 | + stubs: globalStubs | ||
| 69 | + } | ||
| 70 | + }) | ||
| 71 | + | ||
| 72 | + const tabs = wrapper.findAllComponents({ name: 'van-tab' }) | ||
| 73 | + expect(tabs.length).toBe(2) | ||
| 74 | + expect(tabs[0].props('title')).toBe('图片') | ||
| 75 | + expect(tabs[1].props('title')).toBe('视频') | ||
| 76 | + }) | ||
| 77 | + | ||
| 78 | + it('does not show tabs when single media type exists', () => { | ||
| 79 | + const postWithSingleMedia = { | ||
| 80 | + ...defaultPost, | ||
| 81 | + images: ['img1.jpg'], | ||
| 82 | + videoList: [], | ||
| 83 | + audio: [] | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + const wrapper = mount(CheckinCard, { | ||
| 87 | + props: { post: postWithSingleMedia }, | ||
| 88 | + global: { | ||
| 89 | + stubs: globalStubs | ||
| 90 | + } | ||
| 91 | + }) | ||
| 92 | + | ||
| 93 | + const tabs = wrapper.findAllComponents({ name: 'van-tab' }) | ||
| 94 | + expect(tabs.length).toBe(0) | ||
| 95 | + expect(wrapper.find('.post-images').exists()).toBe(true) | ||
| 96 | + }) | ||
| 97 | +}) |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-05-29 15:34:17 | 2 | * @Date: 2025-05-29 15:34:17 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-24 15:29:28 | 4 | + * @LastEditTime: 2026-01-26 09:52:40 |
| 5 | * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue | 5 | * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue |
| 6 | * @Description: 用户打卡主页 | 6 | * @Description: 用户打卡主页 |
| 7 | --> | 7 | --> | ... | ... |
vitest.config.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2026-01-26 13:31:38 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2026-01-26 13:33:54 | ||
| 5 | + * @FilePath: /mlaj/vitest.config.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +import { defineConfig } from 'vitest/config' | ||
| 9 | +import vue from '@vitejs/plugin-vue' | ||
| 10 | +import path from 'path' | ||
| 11 | + | ||
| 12 | +export default defineConfig({ | ||
| 13 | + plugins: [vue()], | ||
| 14 | + resolve: { | ||
| 15 | + alias: { | ||
| 16 | + "@": path.resolve(__dirname, "src"), | ||
| 17 | + } | ||
| 18 | + }, | ||
| 19 | + test: { | ||
| 20 | + environment: 'jsdom', | ||
| 21 | + css: { | ||
| 22 | + include: [], | ||
| 23 | + modules: { | ||
| 24 | + classNameStrategy: 'non-scoped' | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + server: { | ||
| 28 | + deps: { | ||
| 29 | + inline: ['vant'] | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | +}) |
This diff could not be displayed because it is too large.
-
Please register or login to post a comment