Browse Source

feat: 主页样式制作

kindring 1 year ago
parent
commit
8c750a9f4d

File diff suppressed because it is too large
+ 625 - 8
package-lock.json


+ 2 - 0
package.json

@@ -15,6 +15,7 @@
     "format": "prettier --write src/"
   },
   "dependencies": {
+    "ant-design-vue": "^4.0.7",
     "pinia": "^2.1.7",
     "vue": "^3.3.10",
     "vue-router": "^4.2.5"
@@ -43,6 +44,7 @@
     "tailwindcss": "^3.3.6",
     "ts-node": "^10.9.1",
     "typescript": "~5.2.0",
+    "unplugin-vue-components": "^0.26.0",
     "vite": "^5.0.5",
     "vite-plugin-nightwatch": "^0.4.5",
     "vue-tsc": "^1.8.25"

+ 4 - 3
src/App.vue

@@ -9,21 +9,21 @@ let navItems:navItem[] = [
     name: '首页',
     actionCode: 'toHome',
     description: '返回首页',
-    icon: 'icon-home',
+    icon: 'system',
   },
   {
     id: 1,
     name: '首页',
     actionCode: 'toHome',
     description: '返回首页',
-    icon: 'icon-home',
+    icon: 'logo',
   },
   {
     id: 1,
     name: '首页',
     actionCode: 'toHome',
     description: '返回首页',
-    icon: 'icon-home',
+    icon: 'logo',
   },
 ]
 </script>
@@ -76,6 +76,7 @@ let navItems:navItem[] = [
   position: absolute;
   left: 0;
   bottom: 0;
+  z-index: 999;
 }
 
 

+ 11 - 1
src/assets/base.css

@@ -17,8 +17,13 @@
 
   --vt-c-text-light-1: var(--vt-c-indigo);
   --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
+  --vt-c-text-light-3: #56a7fb;
+  --vt-c-text-light-title: #000000;
   --vt-c-text-dark-1: var(--vt-c-white);
   --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
+  --vt-c-text-dark-3: #56a7fb;
+  --vt-c-text-light-title: #fffff;
+  --vt-c-text-red: #e74c3c;
 }
 
 /* semantic color variables for this project */
@@ -32,7 +37,9 @@
 
   --color-heading: var(--vt-c-text-light-1);
   --color-text: var(--vt-c-text-light-1);
-
+  --color-text-title: var(--vt-c-text-light-title);
+  --color-text-show: var(--vt-c-text-light-3);
+  --color-text-money: var(--vt-c-text-red);
   --section-gap: 160px;
 }
 
@@ -46,7 +53,10 @@
     --color-border-hover: var(--vt-c-divider-dark-1);
 
     --color-heading: var(--vt-c-text-dark-1);
+    --color-text-title: var(--vt-c-text-dark-title);
     --color-text: var(--vt-c-text-dark-2);
+    --color-text-show: var(--vt-c-text-dark-3);
+    --color-text-money: var(--vt-c-text-red);
   }
 }
 

+ 0 - 0
src/assets/logo.svg → src/assets/svg/logo.svg


+ 1 - 0
src/assets/svg/system.svg

@@ -0,0 +1 @@
+<svg t="1637928171784" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11261" width="200" height="200"><path d="M947.188 835.927l-50.079-35.055c-18.559-12.992-56.418-22.725-85.694-22.725H585.19v-79.844h288.761c2.2 0 4-1.8 4-4V156.702c0-2.2-1.8-4-4-4H176.663c-2.2 0-4 1.8-4 4v537.601c0 2.2 1.8 4 4 4h302.069v79.844H212.585c-29.276 0-67.134 9.734-85.694 22.725l-50.079 35.055c-26.411 18.488-17.538 35.371 22.786 35.371h824.803c40.324 0 49.198-16.883 22.787-35.371zM427.175 491.008a16.001 16.001 0 0 1-27.018 4.917l-66.792-76.29-30.074 34.372a16.002 16.002 0 0 1-12.042 5.464h-38.742c-8.836 0-16-7.164-16-16s7.164-16 16-16h31.481l37.331-42.666a16 16 0 0 1 24.08-0.004l61.215 69.92 60.521-161.261a16 16 0 0 1 30.347 1.168l41.855 144.388c0.045 0.156 0.088 0.313 0.128 0.47l17.727 68.934 53.023-135.33a16.001 16.001 0 0 1 14.896-10.163h0.1a16 16 0 0 1 14.87 10.347l35.146 93.072 36.371-46.095a16 16 0 0 1 12.561-6.089H784.8c8.837 0 16 7.164 16 16s-7.163 16-16 16h-52.885l-49.098 62.224a16 16 0 1 1-27.529-4.259l-30.451-80.64-55.913 142.705a16 16 0 0 1-30.393-1.852l-29.996-116.649-28.371-97.873-52.989 141.19z" p-id="11262"></path></svg>

+ 1 - 0
src/assets/svg/user.svg

@@ -0,0 +1 @@
+<svg t="1702880727120" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4238" width="200" height="200"><path d="M960.8 710.4l-17.9-40.3a4 4 0 0 0-4.7-2.2l-53.7 14.6-31-31 14.6-53.7a4 4 0 0 0-2.2-4.7l-40.3-17.9a4 4 0 0 0-5 1.6l-29.3 48.8h-41.4l-29.3-48.8a4 4 0 0 0-5-1.6l-40.5 18a4 4 0 0 0-2.3 4.4l9.7 53.9-31 31-53.7-14.6a4 4 0 0 0-4.7 2.2l-17.9 40.3a4 4 0 0 0 1.6 5l48.8 29.3v41.4l-48.8 29.3a4 4 0 0 0-1.6 5l18 40.5a4 4 0 0 0 4.4 2.3l53.9-9.7 31 31-14.6 53.7a4 4 0 0 0 2.2 4.7l40.3 17.9a4 4 0 0 0 5-1.6l29.3-48.8h41.4l29.3 48.8a4 4 0 0 0 5 1.6l40.3-17.9a4 4 0 0 0 2.2-4.7l-14.6-53.7 31-31 53.7 14.6a4 4 0 0 0 4.7-2.2l18.1-40.7a4 4 0 0 0-1.2-4.7l-44.2-34.4v-41.4l48.8-29.3a4 4 0 0 0 1.6-5zM768.2 846a78 78 0 1 1 78-78 78 78 0 0 1-78 78z m5.8-504c0-144.7-117.3-262-262-262S250 197.3 250 342a261.7 261.7 0 0 0 117.4 218.5c-140 57.4-239.3 195.4-239.3 355.5v25.5a4 4 0 0 0 4 4h64a4 4 0 0 0 4-4V916a307.1 307.1 0 0 1 24.6-120.9 315.1 315.1 0 0 1 166.4-166.5A307.9 307.9 0 0 1 512 604c144.7 0 262-117.3 262-262zM512 532a189.8 189.8 0 1 1 134.4-55.6A189.1 189.1 0 0 1 512 532z" p-id="4239"></path></svg>

+ 6 - 0
src/components/icons/iconSvg.ts

@@ -0,0 +1,6 @@
+import iconSvg from './iconSvg.vue';
+
+export function bindIconSvg(app: any) {
+    app.component('iconSvg', iconSvg);
+    return app;
+}

+ 36 - 0
src/components/icons/iconSvg.vue

@@ -0,0 +1,36 @@
+<script setup lang="ts">
+import {computed, defineComponent} from 'vue'
+import type {PropType} from 'vue'
+
+let props = defineProps({
+  iconClass: {
+    type: String,
+    required: true,
+  },
+  className: {
+    type: String,
+    default: '',
+  },
+});
+
+let svgClass = computed(() => `svg-icon ${props.className ?? ''}`);
+
+let iconName = computed(() => `#icon-${props.className}`);
+
+</script>
+
+<template>
+  <svg :class="svgClass" aria-hidden="true">
+    <use :xlink:href="iconName"/>
+  </svg>
+</template>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>

+ 87 - 11
src/components/layout/appleBar.vue

@@ -1,5 +1,6 @@
 <script setup lang="ts">
-import {ref, onMounted} from 'vue'
+import {ref, onMounted, defineComponent} from 'vue'
+import {Tooltip} from "ant-design-vue"
 import type{PropType} from 'vue'
 import type{navItem} from '@/types/appleBar'
 
@@ -28,14 +29,21 @@ let props = defineProps({
 
 onMounted(() => {
   startHideTimer();
-  console.log(props.navItems);
 })
 
+
+let emits = defineEmits({
+  action: (actionCode: string) => true
+});
 /**
  * 用户交互时,重置隐藏计时器
  */
 function barActiveHandle(): void{
   isHidden.value = false;
+  if(hideTimer){
+    clearTimeout(hideTimer);
+    hideTimer = null;
+  }
 }
 
 
@@ -43,19 +51,36 @@ function barActiveHandle(): void{
 function startHideTimer(){
   if(hideTimer){
     clearTimeout(hideTimer);
+    hideTimer = null;
   }
   hideTimer = setTimeout(() => {
     isHidden.value = true;
   }, props.hideTime);
 }
 
+
+function actionHandle(actionCode: string): void{
+  emits('action', actionCode);
+}
+
 </script>
 
 <template>
   <div class="appleBarBox" :class="isHidden?'hidden':''">
-    <div class="appleBar" @mousemove="barActiveHandle" @mouseout="startHideTimer">
-      <div class="appleItem" v-for="item in props.navItems" :key="item.id">
-        {{item.name}}
+    <div class="appleBar" @mouseenter="barActiveHandle" @mouseleave="startHideTimer">
+      <div class="bgMask"></div>
+      <div class="appleItemGroup">
+        <div class="appleItem"
+             v-for="item in props.navItems"
+             :key="item.id"
+              @click="actionHandle(item.actionCode)"
+        >
+          <icon-svg class="icon" :class-name="item.icon"></icon-svg>
+        </div>
+      </div>
+<!--      右键-->
+      <div class="appleItem appleUser" @click="actionHandle('user')">
+        <icon-svg class="icon" class-name="user"></icon-svg>
       </div>
     </div>
   </div>
@@ -63,7 +88,7 @@ function startHideTimer(){
 
 <style scoped>
 .appleBarBox{
-  width: 80%;
+  width: 55%;
   height: 100%;
   display: flex;
   flex-direction: row;
@@ -74,21 +99,42 @@ function startHideTimer(){
 .appleBar{
   width: 100%;
   height: 50px;
-  background-color: var(--color-background-soft);
   border-radius: 10px;
-  box-shadow: 0 0 10px 0 rgba(0,0,0,0.2);
-  opacity: 0.6;
+  box-shadow: 0 0 10px 0 var(--color-background-mute);
   transition: all 0.8s;
   margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  position: relative;
+  justify-content: space-between;
+}
+.appleBar .bgMask{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  border-radius: 10px;
+  opacity: 0.6;
+  background-color: var(--color-background-soft);
+  z-index: 1;
+}
+.appleItemGroup{
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 2;
+  position: relative;
 }
-
 .appleItem{
   width: 45px;
   height: 45px;
   display: flex;
   margin: 0 10px;
   border-radius: 50%;
-  box-shadow: 0 0 3px 0 rgba(0,0,0,0.2);
+  box-shadow: 0 0 3px 0 var(--color-text);
   justify-content: center;
   align-items: center;
   font-size: 20px;
@@ -96,8 +142,35 @@ function startHideTimer(){
   color: var(--color-text);
   cursor: pointer;
   transition: all 0.8s;
+  background-color: var(--color-background-soft);
+  opacity: 0.8;
+}
+
+.appleUser{
+  width: 45px;
+  height: 45px;
+  display: flex;
+  flex-shrink: 0;
+  position: relative;
+  z-index: 2;
 }
 
+.appleItem .icon{
+  height: 100%;
+  font-size: 1.5em;
+  color: var(--color-text);
+  transition: all 0.8s;
+}
+
+.appleItem:hover, .appleUser:hover{
+  transform: scale(1.3);
+  box-shadow: 0 0 10px 0 rgba(0,0,0,0.2);
+  color: var(--color-text);
+  background-color: var(--color-background-soft);
+  transition: all 0.8s;
+}
+
+
 .hidden .appleBar{
   width: 10%;
   height: 10px;
@@ -105,7 +178,10 @@ function startHideTimer(){
   opacity: 0.4;
   margin-bottom: 5px;
   cursor: pointer;
+}
 
+.hidden .appleBar .appleItem{
+  display: none;
 }
 
 

+ 126 - 0
src/components/task-tab.vue

@@ -0,0 +1,126 @@
+<script setup lang="ts">
+import type {PropType} from "vue";
+import type {reward_ladder, Task} from "@/types/task";
+
+const props = defineProps({
+  tasks: {
+    type: Array as PropType<Task[]>,
+    default: ():Task[] => []
+  }
+})
+
+function showTaskReward(task:Task):string{
+  let reStr: string = '';
+  let reward: reward_ladder;
+  let ladderKey = task.finishLadderKey;
+  if(task.rewardType === 0){
+    reStr = task.reward
+  }else if(task.rewardType === 1) {
+    reward = task.reward.find((item) => {
+      return item.key === ladderKey
+    });
+    if(reward){
+      reStr = reward.text
+    }else{
+      reStr = '未知奖励'
+    }
+  }
+  return reStr
+}
+
+function taskFinish(task:Task):void{
+  console.log(task)
+
+}
+
+</script>
+
+<template>
+<div class="task-tab">
+  <div class="task-item"
+       v-for="item in props.tasks">
+    <div class="task-info">
+      <!--    任务名称 -->
+      <a-popover
+          class="task-title"
+          :title="item.name"
+          trigger="hover"
+      >
+        <template #content>
+          <div class="task-description">
+            {{ item.description }}
+          </div>
+        </template>
+        <span>{{ item.name }}</span>
+      </a-popover>
+
+
+      <div class="task-option">
+      <span v-if="!item.isFinish">
+        <a-button @click="taskFinish(item)">完成</a-button>
+      </span>
+      <span v-else>
+        <span>
+          {{showTaskReward(item)}}
+        </span>
+      </span>
+      </div>
+    </div>
+
+    <div class="task-process">
+      <a-tooltip :title="`完成:${item.finishDays}/${item.currentDays} 总天数:${item.totalDays}`">
+        <a-progress
+            strokeColor="#777777"
+            :show-info="false"
+            :size="[300, 20]"
+            :percent="item.currentDays/item.totalDays * 100"
+            :success="{
+              percent: item.finishDays/item.totalDays * 100 ,
+              strokeColor: '#52c41a'
+            }" />
+      </a-tooltip>
+    </div>
+  </div>
+</div>
+</template>
+
+<style scoped>
+.task-tab{
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  position: relative;
+  box-sizing: border-box;
+  padding: 0 5px;
+}
+.task-item{
+  width: 100%;
+  height: 90px;
+  margin-top: 5px;
+  overflow: hidden;
+  position: relative;
+  border-radius: 10px;
+  box-shadow: 0 0 3px 0 var(--color-background-mute);
+  z-index: 3;
+}
+
+.task-info{
+  display: flex;
+  width: 100%;
+  height: 60px;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 15px;
+}
+.task-info .task-title{
+  font-size: 1.5em;
+  color: var(--color-text-title);
+}
+.task-process{
+  width: 100%;
+  height: 30px;
+  padding: 0 10px;
+}
+</style>

+ 3 - 0
src/main.ts

@@ -4,11 +4,14 @@ import { createApp } from 'vue'
 import { createPinia } from 'pinia'
 
 import App from './App.vue'
+import {bindIconSvg} from './components/icons/iconSvg.ts'
 import router from './router'
 
 const app = createApp(App)
 
 app.use(createPinia())
 app.use(router)
+bindIconSvg(app)
+
 
 app.mount('#app')

+ 38 - 0
src/types/task.ts

@@ -0,0 +1,38 @@
+export interface reward_ladder {
+    text: string,
+    reward: number,
+    key: string
+}
+
+export interface Task {
+    id: number,
+    name: string,
+    description: string,
+    // 报酬类型 固定报酬:0 阶梯报酬:1
+    rewardType:  0 | 1,
+    // 最低报酬
+    reward: number | reward_ladder[],
+
+    // 周期总天数
+    totalDays: number,
+    // 开启暴击最低天数
+    baseDays: number,
+    // 本周期内已经进行的天数,不计算是否完成
+    currentDays: number,
+    // 完成天数
+    finishDays: number,
+    // 暴击倍数
+    multiple: number,
+
+    // 本周期内是否完成
+    isFinish: boolean,
+    // 完成时间
+    finishTime?: string,
+    // 任务完成对应的阶梯
+    finishLadderKey?: string,
+    // 任务类型 0:日常 1:周常 2:月常
+    type: number,
+    // 任务状态 0:未开始 1:进行中 2:已完成
+    status: number,
+    icon?: string,
+}

+ 221 - 3
src/views/HomeView.vue

@@ -1,9 +1,227 @@
 <script setup lang="ts">
-import TheWelcome from '../components/TheWelcome.vue'
+
+import {ref, onMounted, defineComponent, onBeforeMount} from 'vue'
+import TaskTab from "@/components/task-tab.vue";
+import type {Task, reward_ladder} from "@/types/task";
+
+// refs
+const hours = ref('');
+const minutes = ref('');
+const second = ref('');
+const totalMoney = ref(0);
+
+onBeforeMount(() => {
+  getTimeStr();
+  setInterval(() => {
+    getTimeStr();
+  }, 600);
+});
+
+
+function getTimeStr():void{
+  let date = new Date();
+  let hoursStr = date.getHours().toString();
+  let minutesStr = date.getMinutes().toString();
+  let secondsStr = date.getSeconds().toString();
+  if(hoursStr.length === 1){
+    hoursStr = '0' + hoursStr;
+  }
+  if(minutesStr.length === 1){
+    minutesStr = '0' + minutesStr;
+  }
+  if(secondsStr.length === 1){
+    secondsStr = '0' + secondsStr;
+  }
+  hours.value = hoursStr;
+  minutes.value = minutesStr;
+  second.value = secondsStr;
+}
+
+
+function loadTotalMoney():void{
+  totalMoney.value = 0;
+}
+
+let tasks: Task[] = [
+  {
+    id: 1,
+    name: '任务1',
+    description: '任务1描述每日进行xxx',
+    // 报酬
+    rewardType: 1,
+    reward:  [
+        {
+          text: '80卡',
+          reward: 5,
+          key: '80ka'
+        },
+        {
+          text: '90卡',
+          reward: 6,
+          key: '90ka'
+        },
+        {
+          text: '100卡',
+          reward: 7,
+          key: '100ka'
+        },
+        {
+          text: '110卡',
+          reward: 8,
+          key: '110ka'
+        },
+        {
+          text: '120卡',
+          reward: 9,
+          key: '120ka'
+        },
+        {
+          text: '130',
+          reward: 10,
+          key: '130ka'
+        },
+      ],
+    // 本周期内已经进行的天数,不计算是否完成
+    currentDays: 10,
+    // 周期总天数
+    totalDays: 25,
+    // 暴击倍数
+    multiple: 2,
+    // 开启暴击最低天数
+    baseDays: 15,
+    // 完成天数
+    finishDays: 5,
+    // 本周期内是否完成
+    isFinish: false,
+    // 完成时间
+    finishTime: '',
+    // 任务类型 0:日常 1:周常 2:月常
+    type: 0,
+    // 任务状态 0:未开始 1:进行中 2:已完成
+    status: 1,
+  },
+  {
+    id: 1,
+    name: '签到',
+    description: '每日签到',
+    // 报酬
+    rewardType: 0,
+    reward:  3,
+    // 本周期内已经进行的天数,不计算是否完成
+    currentDays: 10,
+    // 周期总天数
+    totalDays: 30,
+    // 暴击倍数
+    multiple: 2,
+    // 开启暴击最低天数
+    baseDays: 15,
+    // 完成天数
+    finishDays: 1,
+    // 本周期内是否完成
+    isFinish: false,
+    // 完成时间
+    finishTime: '',
+    // 任务类型 0:日常 1:周常 2:月常
+    type: 0,
+    // 任务状态 0:未开始 1:进行中 2:已完成
+    status: 1,
+  }
+
+]
 </script>
 
 <template>
-  <main>
-    <TheWelcome />
+  <main class="main">
+    <div class="info-view">
+
+      <!--    时间 -->
+      <div class="viewBox time-view">
+        <span class="hours">{{hours}}</span>
+        <span >:</span>
+        <span class="minutes">{{minutes}}</span>
+        <span >:</span>
+        <span class="second">{{second}}</span>
+      </div>
+      <!--    总余额-->
+      <div class="viewBox money">
+        <span>{{totalMoney}}</span>
+      </div>
+
+      <!--    任务列表-->
+      <div class="viewBox task-tab">
+        <task-tab class="view" :tasks="tasks"></task-tab>
+      </div>
+
+    </div>
   </main>
 </template>
+
+<style scoped>
+
+.main{
+  overflow: hidden;
+  position: relative;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.info-view{
+  display: grid;
+  grid-template-columns: repeat(6, 100px);
+  grid-template-rows: repeat(5, 100px);
+  grid-gap: 10px;
+  padding: 10px;
+  box-sizing: border-box;
+  grid-template-areas: 'a a b b c c'
+  'd d e e e e'
+  'd d e e e e'
+  'f f e e e e'
+  'g g e e e e';
+
+}
+.viewBox{
+  border-radius: 5px;
+  width: 100%;
+  height: 100%;
+  position: relative;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  box-shadow: 1px 1px 5px 0 var(--color-background);
+}
+.viewBox::before{
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  border-radius: 5px;
+  background-color: var(--color-background);
+  opacity: 0.2;
+}
+.viewBox span,.viewBox .view{
+  position: relative;
+  z-index: 2;
+}
+.time-view{
+  grid-area: a;
+  font-size: 50px;
+  font-weight: bold;
+  color: var(--color-text-show);
+}
+
+.money{
+  grid-area: d;
+  font-size: 50px;
+  font-weight: bold;
+  color: var(--color-text-money);
+  border: purple 1px solid;
+}
+.task-tab{
+  grid-area: e;
+
+}
+</style>

+ 7 - 1
tsconfig.app.json

@@ -1,6 +1,12 @@
 {
   "extends": "@vue/tsconfig/tsconfig.dom.json",
-  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.ts"],
+  "include": [
+    "env.d.ts",
+    "src/**/*",
+    "src/**/*.vue",
+    "src/**/**/*.vue",
+    "src/**/*.ts",
+    "src/**/**/*.ts"],
   "exclude": ["src/**/__tests__/*"],
   "compilerOptions": {
     "composite": true,

+ 2 - 1
tsconfig.node.json

@@ -5,7 +5,8 @@
     "vitest.config.*",
     "cypress.config.*",
     "nightwatch.conf.*",
-    "playwright.config.*"
+    "playwright.config.*",
+    "vitePlugin/*.ts",
   ],
   "compilerOptions": {
     "composite": true,

+ 12 - 0
vite.config.ts

@@ -5,15 +5,27 @@ import vue from '@vitejs/plugin-vue'
 import vueJsx from '@vitejs/plugin-vue-jsx'
 import nightwatchPlugin from 'vite-plugin-nightwatch'
 
+import Components from 'unplugin-vue-components/vite';
+
+import { svgLoader } from './vitePlugin/SVGLoader'
+import {AntDesignVueResolver} from "unplugin-vue-components/resolvers";
 
 // https://vitejs.dev/config/
 export default defineConfig({
   plugins: [
     vue(),
     vueJsx(),
+    svgLoader('./src/assets/svg/'),
     nightwatchPlugin({
       renderPage: './nightwatch/index.html'
     }),
+    Components({
+      resolvers: [
+        AntDesignVueResolver({
+          importStyle: false, // css in js
+        }),
+      ],
+    }),
   ],
   resolve: {
     alias: {

+ 60 - 0
vitePlugin/SVGLoader.ts

@@ -0,0 +1,60 @@
+import { readFileSync, readdirSync } from 'fs'
+let idPerfix = ''
+const svgTitle = /<svg([^>+].*?)>/
+const clearHeightWidth = /(width|height)="([^>+].*?)"/g
+const hasViewBox = /(viewBox="[^>+].*?")/g
+const clearReturn = /(\r)|(\n)/g
+function findSvgFile(dir: string):string[] {
+    const svgRes = []
+    const dirents = readdirSync(dir, {
+        withFileTypes: true
+    })
+    for (const dirent of dirents) {
+        if (dirent.isDirectory()) {
+            svgRes.push(...findSvgFile(dir + dirent.name + '/'))
+        } else {
+            const svg = readFileSync(dir + dirent.name)
+                .toString()
+                .replace(clearReturn, '')
+                .replace(svgTitle, ($1, $2: string) => {
+                    let width: string = '0'
+                    let height: string = '0'
+                    let content = $2.replace(clearHeightWidth, (s1: string, s2: string, s3: string) => {
+                        if (s2 === 'width') {
+                            width = s3
+                        } else if (s2 === 'height') {
+                            height = s3
+                        }
+                        return ''
+                    })
+                    if (!hasViewBox.test($2)) {
+                        content += `viewBox="0 0 ${width} ${height}"`
+                    }
+                    return `<symbol id="${idPerfix}-${dirent.name.replace('.svg', '')}" ${content}>`
+                })
+                .replace('</svg>', '</symbol>')
+            svgRes.push(svg)
+        }
+    }
+    return svgRes
+}
+export const svgLoader = (path: string, perfix = 'icon') => {
+    if (path === '') return
+    idPerfix = perfix
+    console.log('svgLoader');
+    const res = findSvgFile(path)
+    return {
+        name: 'svg-transform',
+        transformIndexHtml(html: any) {
+            return html.replace(
+                '<body>',
+                `
+          <body>
+            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
+              ${res.join('')}
+            </svg>
+        `
+            )
+        }
+    }
+}

Some files were not shown because too many files changed in this diff