Compare commits

...

3 Commits

Author SHA1 Message Date
xjs 757369ebc6 feat: 增加登陆提示 2025-05-26 10:39:06 +08:00
xjs 3306cab187 feat: 线上线下数据对接 2025-05-26 10:30:43 +08:00
xjs c4fcc28ed2 docs: 说明调整 2025-05-26 10:10:59 +08:00
6 changed files with 30 additions and 99 deletions

View File

@ -1,81 +1,3 @@
# Vue 3 + TypeScript + Vite 6.x + VueRouter 4.x + Pinia 模板
# 支付统计项目
pnpm作为包管理主要可以解决幽灵依赖包的问题
1. Pinia 状态管理库带加密功能
本地建立.env
文件中`VITE_SECRET_KEY=xxx`
2. 自定义Axios 加密参数 错误日志记录
3. VueRouter 4.x 路由 权限控制 动态缓存
import { removeKeepAliveCache, resetKeepAliveCache } from '@/router/keepAlive'
const instance = getCurrentInstance()!
onBeforeRouteLeave((to) => {
if (to.path === '/C') {
removeKeepAliveCache(instance)
} else {
resetKeepAliveCache(instance)
}
})
通过 removeKeepAliveCache, resetKeepAliveCache 来维护exclude数组里面的内容达到 a 进入C后返回到A页面时a页面的缓存被清楚进入其他页面返回则不被清除缓存
权限控制
有身份权限的写在privateRoutes.ts中
没有身份权限的写在publicRoutes.ts中
4. 项目版本检测确保启动顺利。检测node版本和工具包的版本是否符合要求。
可以根据项目需求修改package.json中的engines字段。
``` shell
pnpm run check-env
```
5. prettier 统一的代码格式这样保存格式化的时候就不会因为不同的格式化工具导致其他的内容也出现修改。vscode配合prettier插件
.prettierrc.json的内容就是指定代码的格式的配置文件
6. SvgIcon组件更加优雅的使用svg图片
将图片放入到 /public/icons 下面name就是图片的名字例如certificate.svg
``` html
<SvgIcon name="certificate" class="w-10 h-10"></SvgIcon>
```
推荐使用较少的svg代码图片不然html的体积会进一步增大
如果是大的背景图推荐使用`vite`的动态导入
```typescript
const getPath = async () => {
const { default: svg } = await import("/src/assets/svg-img/certificate.svg?raw");
test.value = svg;
};
getPath();
```
7. unocss 即时原子 CSS 引擎。主要想解决遍地css文件的麻烦。预设了tailwind css的预算值。所以可以直接对着tailwind css的官方文档编写
8. composables 这个文件夹推荐将业务逻辑写在此处的x.ts文件内然后搭配 vue3的组合式语法。解决视图层和业务层的代码分离。
9. 异步加载动态组件, 针对大的页面要加载很多的JS可以异步错开或者等待条件允许再加载。看个人业务需求
```html
<component :is="currentComponent"></component>
```
```typescript
let currentComponent = ref(defineAsyncComponent(() => import('@/components/TestComponent.vue')))
let flag = false
const handleClick = () => {
if (flag) {
currentComponent.value = defineAsyncComponent(() => import('@/components/TestComponent2.vue'));
} else {
currentComponent.value = defineAsyncComponent(() => import('@/components/TestComponent.vue'));
}
flag = !flag
}
```
深泉支付统计项目

View File

@ -6,7 +6,6 @@ import { useUserStore } from "@/store/user";
* @LastEditors: error: git config user.name & please set dead value or install git
* @LastEditTime: 2024-09-01
* @Description:
* @FilePath: /free-music-react/src/lib/customFetch.ts
*/
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

View File

@ -18,7 +18,7 @@
</div>
<div class="leading-[1] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-3 flex items-center flex-col font-700 italic">
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent flex items-baseline">
<div class="text-[25px]">690</div>
<div class="text-[25px]">{{ offlineTotal }}</div>
<div class="text-[20px]"></div>
</div>
<div class="text-[#FFFFFF] text-[16px] text-shadow-[0px_2px_2px_rgba(12,32,72,0.42)] mt-[7px]">线下</div>
@ -70,7 +70,7 @@
};
const colorList = ref(["#0783FA", "#07D1FA", "#20E6A4", "#FFD15C"]);
const askSectionData = inject("askSectionData", ref<{ offline: any[] }>({ offline: [] }));
const askSectionData = inject("askSectionData", ref<{ offline: any[],scource:any[] }>({ offline: [],scource:[] }));
const chartData = ref<any[]>([]);
@ -81,6 +81,8 @@
},
);
const offlineTotal = ref<any>({})
const initData = () => {
if (askSectionData.value.offline && askSectionData.value.offline.length > 0) {
chartData.value = askSectionData.value.offline.map((item, index) => ({
@ -88,6 +90,7 @@
value: item.total,
color: colorList.value[index % colorList.value.length],
}));
offlineTotal.value = askSectionData.value.scource.filter(item => item.tag==="线下")[0].total
}
}

View File

@ -18,7 +18,7 @@
</div>
<div class="leading-[1] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-3 flex items-center flex-col font-700 italic">
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent flex items-baseline">
<div class="text-[25px]">690</div>
<div class="text-[25px]">{{ onlineTotal }}</div>
<div class="text-[20px]"></div>
</div>
<div class="text-[#FFFFFF] text-[16px] text-shadow-[0px_2px_2px_rgba(12,32,72,0.42)] mt-[7px]">线上</div>
@ -71,23 +71,28 @@
const colorList = ref(["#0783FA", "#07D1FA", "#20E6A4", "#FFD15C"]);
const askSectionData = inject("askSectionData", ref<{ online: any[] }>({ online: [] }));
const askSectionData = inject("askSectionData", ref<{ online: any[]; scource: any[] }>({ online: [], scource: [] }));
const chartData = ref<any[]>([]);
const onlineTotal = ref<any>({});
watch(() => askSectionData.value, () => {
initData()
});
watch(
() => askSectionData.value,
() => {
initData();
},
);
const initData = () => {
if (askSectionData.value.online && askSectionData.value.online.length > 0) {
chartData.value = askSectionData.value.online.map((item, index) => ({
name: item.tag,
value: item.total,
color: colorList.value[index % colorList.value.length],
color: colorList.value[index % colorList.value.length],
}));
onlineTotal.value = askSectionData.value.scource.filter((item) => item.tag === "线上")[0].total;
}
}
};
onBeforeMount(() => {
getHeaderLeftSvg();

View File

@ -4,7 +4,6 @@
<script setup lang="ts">
import * as echarts from "echarts";
import { ref, onMounted, onUnmounted, defineProps, watch } from "vue";
interface DataItem {
tag: string;

View File

@ -83,15 +83,18 @@
{ headers: { "content-type": "application/json; charset=utf-8" } },
).then((resp) => {
if (resp.code === 200) {
// token
const { accessToken, refreshToken } = resp.result as { refreshToken: string; accessToken: string };
userStore.setAccessToken(accessToken);
userStore.setRefreshToken(refreshToken);
//
router.push("/");
if(resp.result == 401){
alert("账号或密码错误");
}else{
// token
const { accessToken, refreshToken } = resp.result as { refreshToken: string; accessToken: string };
userStore.setAccessToken(accessToken);
userStore.setRefreshToken(refreshToken);
//
router.push("/");
}
} else {
//
//
alert(resp.message || "登录失败");
}
});