Compare commits
2 Commits
bb71cacfd1
...
33847fef1c
| Author | SHA1 | Date | |
|---|---|---|---|
| 33847fef1c | |||
| 4d837466d0 |
@ -4,6 +4,7 @@ import request from '@/utils/request'
|
||||
export function listConvert(query) {
|
||||
return request({
|
||||
url: '/system/convert/list',
|
||||
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@ -13,6 +14,7 @@ export function listConvert(query) {
|
||||
export function getConvert(id) {
|
||||
return request({
|
||||
url: '/system/convert/' + id,
|
||||
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@ -21,6 +23,7 @@ export function getConvert(id) {
|
||||
export function addConvert(data) {
|
||||
return request({
|
||||
url: '/system/convert',
|
||||
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@ -30,6 +33,7 @@ export function addConvert(data) {
|
||||
export function updateConvert(data) {
|
||||
return request({
|
||||
url: '/system/convert',
|
||||
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
@ -39,6 +43,7 @@ export function updateConvert(data) {
|
||||
export function delConvert(id) {
|
||||
return request({
|
||||
url: '/system/convert/' + id,
|
||||
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ const config = {
|
||||
// 应用版本
|
||||
version: "1.1.0",
|
||||
// 应用logo
|
||||
logo: "/static/logo.png",
|
||||
logo: "https://ngtools.cn:3000/static/logo.png",
|
||||
// 官方网站
|
||||
site_url: "http://ruoyi.vip",
|
||||
// 政策协议
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import App from './App.vue'
|
||||
import plugins from './plugins'
|
||||
import store from './store'
|
||||
import uviewPlus from 'uview-plus'
|
||||
|
||||
|
||||
import { createSSRApp } from 'vue'
|
||||
@ -15,7 +14,6 @@ import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, select
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
app.use(store)
|
||||
app.use(uviewPlus)
|
||||
app.use(plugins)
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true // 忽略版本检查
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {
|
||||
"OAuth" : {}
|
||||
|
||||
@ -284,20 +284,20 @@
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index",
|
||||
"iconPath": "static/images/tabbar/work.png",
|
||||
"selectedIconPath": "static/images/tabbar/work_.png",
|
||||
"iconPath": "/static/images/tabbar/work.png",
|
||||
"selectedIconPath": "/static/images/tabbar/work_.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/template",
|
||||
"iconPath": "static/images/tabbar/work.png",
|
||||
"selectedIconPath": "static/images/tabbar/work_.png",
|
||||
"iconPath": "/static/images/tabbar/work.png",
|
||||
"selectedIconPath": "/static/images/tabbar/work_.png",
|
||||
"text": "资料"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine",
|
||||
"iconPath": "static/images/tabbar/mine.png",
|
||||
"selectedIconPath": "static/images/tabbar/mine_.png",
|
||||
"iconPath": "/static/images/tabbar/mine.png",
|
||||
"selectedIconPath": "/static/images/tabbar/mine_.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
|
||||
@ -34,97 +34,90 @@
|
||||
onMounted
|
||||
} from "vue";
|
||||
import modal from "@/plugins/modal"
|
||||
import {
|
||||
listConvert
|
||||
} from '@/api/system/unitConverter/sysUnitConverter.js';
|
||||
import {
|
||||
storage
|
||||
} from '@/utils/storageUnit.ts';
|
||||
|
||||
import {
|
||||
extractModuleData
|
||||
} from '@/utils/moudlesData.ts';
|
||||
|
||||
import useUnitStore from '@/store/modules/unitData.ts';
|
||||
import {
|
||||
getToken,
|
||||
setToken,
|
||||
removeToken
|
||||
} from "@/utils/auth";
|
||||
|
||||
const unitStore = useUnitStore();
|
||||
|
||||
|
||||
const current = ref(0);
|
||||
const swiperDotIndex = ref(0);
|
||||
const data = ref([{
|
||||
image: '/static/images/banner/banner01.jpg'
|
||||
image: 'https://ngtools.cn:3000/static/images/banner/banner01.jpg'
|
||||
},
|
||||
{
|
||||
image: '/static/images/banner/banner02.jpg'
|
||||
image: 'https://ngtools.cn:3000/static/images/banner/banner02.jpg'
|
||||
},
|
||||
{
|
||||
image: '/static/images/banner/banner03.jpg'
|
||||
image: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg'
|
||||
}
|
||||
]);
|
||||
|
||||
// 核心数据:计算分组和功能项定义
|
||||
const moudlesGroups = ref([]);
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 1000,
|
||||
unitType: null,
|
||||
unitName: null,
|
||||
baseUnit: null,
|
||||
conversionFactor: null,
|
||||
unitTypeName: null,
|
||||
status: null,
|
||||
unitOrder: null
|
||||
});
|
||||
|
||||
// 保留原有单位换算方法
|
||||
const groupByUnitType = (data) => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
console.warn('groupByUnitType: 数据为空或不是数组');
|
||||
return {};
|
||||
// 登录状态校验函数
|
||||
const checkLoginStatus = () => {
|
||||
// 1. 检查本地token是否存在
|
||||
const token = getToken();
|
||||
|
||||
console.log(token)
|
||||
// 2. 无token/用户信息,直接跳转登录
|
||||
if (!token) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login'
|
||||
});
|
||||
return false; // 未登录
|
||||
}
|
||||
|
||||
return data.reduce((acc, unit) => {
|
||||
const type = unit.unitType;
|
||||
if (!acc[type]) acc[type] = [];
|
||||
acc[type].push({
|
||||
id: unit.id,
|
||||
unitType: unit.unitType,
|
||||
unitName: unit.unitName,
|
||||
conversionFactor: unit.conversionFactor,
|
||||
unitOrder: unit.unitOrder,
|
||||
baseUnit: unit.baseUnit,
|
||||
status: unit.status,
|
||||
unitTypeName: unit.unitTypeName
|
||||
});
|
||||
return acc;
|
||||
}, {});
|
||||
return true; // 已登录
|
||||
};
|
||||
|
||||
const getList = () => {
|
||||
onMounted(async () => {
|
||||
// 第一步:优先校验登录状态(核心修复)
|
||||
const isLogin = checkLoginStatus();
|
||||
if (!isLogin) return; // 未登录则终止后续逻辑
|
||||
moudlesGroups.value = extractModuleData(['流量计算', '参数计算'], false)
|
||||
// 优先从本地缓存恢复,再请求最新数据
|
||||
unitStore.restoreUnitDataFromLocal();
|
||||
try {
|
||||
console.log('开始请求单位数据...');
|
||||
const response = listConvert(queryParams.value);
|
||||
console.log('API响应:', JSON.stringify(response));
|
||||
|
||||
if (!response || !response.rows) {
|
||||
console.error('API响应格式错误');
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.rows.length === 0) {
|
||||
console.warn('单位数据为空数组');
|
||||
return;
|
||||
}
|
||||
|
||||
const unitDataGrouped = groupByUnitType(response.rows);
|
||||
console.log('分组后的单位数据:', unitDataGrouped);
|
||||
// 使用统一的存储方法
|
||||
storage.setItem('unitData', unitDataGrouped);
|
||||
console.log('数据存储成功');
|
||||
|
||||
await unitStore.getList();
|
||||
} catch (error) {
|
||||
console.error('获取单位数据失败:', error);
|
||||
|
||||
if (error.code === 401 ||
|
||||
(error.message &&
|
||||
(error.message.includes('会话过期') ||
|
||||
error.message.includes('无效的会话')))) {
|
||||
|
||||
// 清除本地存储
|
||||
uni.removeStorageSync('token');
|
||||
uni.removeStorageSync('userInfo');
|
||||
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/'
|
||||
});
|
||||
} else {
|
||||
// 其他错误:显示具体错误信息
|
||||
const errorMsg = error.message || '数据加载失败,请稍后重试';
|
||||
modal.showToast({
|
||||
title: errorMsg,
|
||||
mask: false,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
moudlesGroups.value = extractModuleData(['流量计算', '参数计算'], false)
|
||||
getList();
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
function navigateToMoudles(item) {
|
||||
console.log(item)
|
||||
|
||||
@ -130,12 +130,17 @@
|
||||
wxLogin,
|
||||
wxAppLogin
|
||||
} from '@/api/oauth'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
import {
|
||||
setToken
|
||||
} from '@/utils/auth'
|
||||
import config from '@/config.js'
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 添加一个标志位,防止重复跳转
|
||||
let isChecking = false;
|
||||
let hasChecked = false;
|
||||
import useUserStore from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
const appName = config.appInfo.name || '天然气工具箱'
|
||||
|
||||
@ -245,13 +250,18 @@
|
||||
|
||||
const res = await login(params.username, params.password, params.code, params.uuid)
|
||||
|
||||
|
||||
if (res.token) {
|
||||
setToken(res.token)
|
||||
await userStore.getInfo()
|
||||
uni.switchTab({
|
||||
url: '/pages/index'
|
||||
});
|
||||
|
||||
// 添加延迟,确保状态更新完成
|
||||
setTimeout(() => {
|
||||
// 使用 reLaunch 关闭所有页面并跳转到首页
|
||||
uni.reLaunch({
|
||||
url: '/pages/index'
|
||||
})
|
||||
}, 300)
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果需要验证码,重新获取
|
||||
@ -405,15 +415,55 @@
|
||||
getCaptcha()
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
// 检查是否有token,如果有则直接跳转
|
||||
const token = uni.getStorageSync('token')
|
||||
if (token) {
|
||||
onLoad(async (options) => {
|
||||
// === 新增:防止重复检查 ===
|
||||
if (isChecking || hasChecked) return;
|
||||
isChecking = true;
|
||||
|
||||
try {
|
||||
const token = uni.getStorageSync('token');
|
||||
|
||||
if (!token) {
|
||||
hasChecked = true;
|
||||
isChecking = false;
|
||||
getCaptcha(); // 确保验证码加载
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅当明确要求跳过自动登录时才中断
|
||||
if (options?.skipAutoLogin === 'true') {
|
||||
hasChecked = true;
|
||||
isChecking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证 token 有效性(关键:使用安全的验证方式)
|
||||
try {
|
||||
await userStore.getInfo(); // 这会触发用户信息请求
|
||||
|
||||
// 成功获取用户信息,跳转首页
|
||||
uni.reLaunch({
|
||||
url: '/pages/index'
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
// === 重点修复:精确处理 token 失效 ===
|
||||
if (error.code === 401 ||
|
||||
(error.message &&
|
||||
(error.message.includes('会话过期') ||
|
||||
error.message.includes('无效的会话')))) {
|
||||
|
||||
// 清除失效 token
|
||||
uni.removeStorageSync('token');
|
||||
uni.removeStorageSync('userInfo');
|
||||
modal.alert('登录已过期,请重新登录');
|
||||
}
|
||||
})
|
||||
getCaptcha(); // 重新加载验证码
|
||||
}
|
||||
} finally {
|
||||
isChecking = false;
|
||||
hasChecked = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -67,28 +67,28 @@ function getcolor(color: { hex: string, rgba: { r: number, g: number, b: number,
|
||||
}
|
||||
|
||||
const menus: Array<Menu> = reactive([
|
||||
{ icon: "/static/images/icon/rocket.png", label: '抢单' },
|
||||
{ icon: "/static/images/icon/phone.png", label: '回访' },
|
||||
{ icon: "/static/images/icon/message.png", label: '消息' },
|
||||
{ icon: "/static/images/icon/dialogue.png", label: '公告' },
|
||||
{ icon: "/static/images/icon/knowledge.png", label: '知识库' }
|
||||
{ icon: "https://ngtools.cn:3000/static/images/icon/rocket.png", label: '抢单' },
|
||||
{ icon: "https://ngtools.cn:3000/static/images/icon/phone.png", label: '回访' },
|
||||
{ icon: "https://ngtools.cn:3000/static/images/icon/message.png", label: '消息' },
|
||||
{ icon: "https://ngtools.cn:3000/static/images/icon/dialogue.png", label: '公告' },
|
||||
{ icon: "https://ngtools.cn:3000/static/images/icon/knowledge.png", label: '知识库' }
|
||||
]);
|
||||
|
||||
const commodityList: Array<Commodity> = reactive([
|
||||
{
|
||||
img: '/static/images/banner/banner01.jpg',
|
||||
img: 'https://ngtools.cn:3000/static/images/banner/banner01.jpg',
|
||||
title: '商品1',
|
||||
subTitle: '商品1简介',
|
||||
price: 100,
|
||||
},
|
||||
{
|
||||
img: '/static/images/banner/banner02.jpg',
|
||||
img: 'https://ngtools.cn:3000/static/images/banner/banner02.jpg',
|
||||
title: '商品2',
|
||||
subTitle: '商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介商品2简介',
|
||||
price: 300,
|
||||
},
|
||||
{
|
||||
img: '/static/images/banner/banner03.jpg',
|
||||
img: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg',
|
||||
title: '商品3',
|
||||
subTitle: '商品3简介',
|
||||
price: 200,
|
||||
@ -99,7 +99,7 @@ const orderList: Array<CommodityOrder> = [
|
||||
{
|
||||
shop: 'geek自营旗舰店',
|
||||
status: '完成',
|
||||
img: '/static/images/banner/banner01.jpg',
|
||||
img: 'https://ngtools.cn:3000/static/images/banner/banner01.jpg',
|
||||
title: '商品1',
|
||||
label: '商品1简介',
|
||||
price: 100.32,
|
||||
@ -108,7 +108,7 @@ const orderList: Array<CommodityOrder> = [
|
||||
{
|
||||
shop: 'geek自营旗舰店',
|
||||
status: '已取消',
|
||||
img: '/static/images/banner/banner03.jpg',
|
||||
img: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg',
|
||||
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
|
||||
label: '商品3简介',
|
||||
price: 2000.67,
|
||||
@ -117,7 +117,7 @@ const orderList: Array<CommodityOrder> = [
|
||||
{
|
||||
shop: 'geek自营旗舰店',
|
||||
status: '已取消',
|
||||
img: '/static/images/banner/banner03.jpg',
|
||||
img: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg',
|
||||
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
|
||||
label: '商品3简介',
|
||||
price: 10.67,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<view class="about-container">
|
||||
<view class="header-section text-center">
|
||||
<image style="width: 150rpx;height: 150rpx;" src="/static/logo.png" mode="widthFix">
|
||||
<image style="width: 150rpx;height: 150rpx;" src="https://ngtools.cn:3000/static/logo.png" mode="widthFix">
|
||||
</image>
|
||||
<uni-title type="h2" title="若依移动端"></uni-title>
|
||||
<uni-title type="h2" title="天然气工具箱"></uni-title>
|
||||
</view>
|
||||
|
||||
<view class="content-section">
|
||||
|
||||
@ -38,9 +38,9 @@
|
||||
margin: "150rpx",
|
||||
index: 0,
|
||||
list: [
|
||||
"/static/images/douyin/0.jpg",
|
||||
"/static/images/douyin/4.jpg",
|
||||
"/static/images/douyin/7.jpg",
|
||||
"https://ngtools.cn:3000/static/images/douyin/0.jpg",
|
||||
"https://ngtools.cn:3000/static/images/douyin/4.jpg",
|
||||
"https://ngtools.cn:3000/static/images/douyin/7.jpg",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ const getComment = () => {
|
||||
likeNum: 21,
|
||||
isLike: false,
|
||||
allReply: 2,
|
||||
url: '../../../static/logo.png',
|
||||
url: 'https://ngtools.cn:3000/static/logo.png',
|
||||
replyList: [
|
||||
{
|
||||
name: 'uview',
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import logo from '@/static/logo.png';
|
||||
</script>
|
||||
<template>
|
||||
<view class="taobao">
|
||||
<view class="title">
|
||||
<view class="left">
|
||||
<image class="buddha" :src="logo" mode="aspectFill"></image>
|
||||
<image class="buddha" src="https://ngtools.cn:3000/static/logo.png" mode="aspectFill"></image>
|
||||
<view class="store">袜子精保护协会</view>
|
||||
</view>
|
||||
<view class="entrance">进店</view>
|
||||
</view>
|
||||
<view class="ticket">
|
||||
<view class="left">
|
||||
<image class="picture" :src="logo" mode="widthFix"></image>
|
||||
<image class="picture" src="https://ngtools.cn:3000/static/logo.png" mode="widthFix"></image>
|
||||
<view class="introduce">
|
||||
<view class="top">
|
||||
¥
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<view>
|
||||
<view class="normal-login-container " v-if="page == 'login'">
|
||||
<view class="left" @click="back">
|
||||
<image src="../../../static/uview/demo/backTop.png" mode="" style="height: 30rpx;"></image>
|
||||
<image src="https://ngtools.cn:3000/static/uview/demo/backTop.png" mode="" style="height: 30rpx;"></image>
|
||||
</view>
|
||||
<view class="scale-in-center">
|
||||
<view class="logo-content align-center justify-center flex">
|
||||
|
||||
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 30 KiB |
335
src/store/modules/unitData.ts
Normal file
@ -0,0 +1,335 @@
|
||||
import { listConvert } from '@/api/system/unitConverter/sysUnitConverter.js'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
// 定义计量单位接口
|
||||
export interface UnitItem {
|
||||
id: number
|
||||
unitType: string
|
||||
unitName: string
|
||||
conversionFactor: number
|
||||
unitOrder: number
|
||||
baseUnit: string
|
||||
status: string
|
||||
unitTypeName: string
|
||||
}
|
||||
|
||||
export interface UnitQueryParams {
|
||||
pageNum: number
|
||||
pageSize: number
|
||||
unitType: string | null
|
||||
unitName: string | null
|
||||
baseUnit: string | null
|
||||
conversionFactor: number | null
|
||||
unitTypeName: string | null
|
||||
status: string | null
|
||||
unitOrder: number | null
|
||||
}
|
||||
|
||||
// 定义按类型分组的单位数据结构
|
||||
export interface GroupedUnitData {
|
||||
[unitType: string]: UnitItem[]
|
||||
}
|
||||
|
||||
export const useUnitStore = defineStore('unit', {
|
||||
state: () => ({
|
||||
// 单位数据列表
|
||||
unitData: [] as UnitItem[],
|
||||
// 按类型分组后的单位数据
|
||||
groupedUnitData: {} as GroupedUnitData,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 1000,
|
||||
unitType: null,
|
||||
unitName: null,
|
||||
baseUnit: null,
|
||||
conversionFactor: null,
|
||||
unitTypeName: null,
|
||||
status: null,
|
||||
unitOrder: null
|
||||
} as UnitQueryParams,
|
||||
// 加载状态
|
||||
loading: false,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 错误信息
|
||||
error: null as string | null
|
||||
}),
|
||||
|
||||
getters: {
|
||||
// 获取所有单位类型
|
||||
unitTypes: (state) => {
|
||||
return Object.keys(state.groupedUnitData)
|
||||
},
|
||||
|
||||
// 获取特定类型的单位列表
|
||||
getUnitsByType: (state) => {
|
||||
return (unitType: string) => {
|
||||
return state.groupedUnitData[unitType] || []
|
||||
}
|
||||
},
|
||||
|
||||
// 获取基本单位
|
||||
getBaseUnit: (state) => {
|
||||
return (unitType: string) => {
|
||||
const units = state.groupedUnitData[unitType] || []
|
||||
// 微信小程序中baseUnit可能是'1',APP可能是'Y',做兼容处理
|
||||
return units.find(unit => unit.baseUnit === '1' || unit.baseUnit === 'Y') || units[0]
|
||||
}
|
||||
},
|
||||
|
||||
// 按类型排序的单位数据
|
||||
sortedUnitTypes: (state) => {
|
||||
return Object.keys(state.groupedUnitData).sort()
|
||||
},
|
||||
|
||||
// 是否有错误
|
||||
hasError: (state) => {
|
||||
return !!state.error
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 按单位类型分组
|
||||
groupByUnitType(data: UnitItem[]): GroupedUnitData {
|
||||
return data.reduce((acc: GroupedUnitData, unit: UnitItem) => {
|
||||
const type = unit.unitType
|
||||
if (!acc[type]) {
|
||||
acc[type] = []
|
||||
}
|
||||
acc[type].push({
|
||||
id: unit.id,
|
||||
unitType: unit.unitType,
|
||||
unitName: unit.unitName,
|
||||
conversionFactor: unit.conversionFactor,
|
||||
unitOrder: unit.unitOrder,
|
||||
baseUnit: unit.baseUnit,
|
||||
status: unit.status,
|
||||
unitTypeName: unit.unitTypeName
|
||||
})
|
||||
// 按单位排序
|
||||
acc[type].sort((a, b) => (a.unitOrder || 0) - (b.unitOrder || 0))
|
||||
return acc
|
||||
}, {})
|
||||
},
|
||||
|
||||
// 设置查询参数
|
||||
setQueryParams(params: Partial<UnitQueryParams>) {
|
||||
this.queryParams = { ...this.queryParams, ...params }
|
||||
},
|
||||
|
||||
// 重置查询参数
|
||||
resetQueryParams() {
|
||||
this.queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 1000,
|
||||
unitType: null,
|
||||
unitName: null,
|
||||
baseUnit: null,
|
||||
conversionFactor: null,
|
||||
unitTypeName: null,
|
||||
status: null,
|
||||
unitOrder: null
|
||||
}
|
||||
},
|
||||
|
||||
// 获取单位列表 - 兼容多平台,带错误处理
|
||||
async getList() {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const response = await listConvert(this.queryParams)
|
||||
console.log('单位数据:', response)
|
||||
this.unitData = response.rows || []
|
||||
this.total = response.total || 0
|
||||
this.groupedUnitData = this.groupByUnitType(this.unitData)
|
||||
|
||||
// 兼容多平台存储
|
||||
this.saveUnitDataToStorage()
|
||||
|
||||
console.log('单位数据获取成功,类型数量:', Object.keys(this.groupedUnitData).length)
|
||||
return response
|
||||
} catch (error) {
|
||||
this.error = error instanceof Error ? error.message : '获取单位数据失败'
|
||||
console.error('获取单位数据出错:', error)
|
||||
throw error
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 安全获取单位列表(失败时使用默认数据)
|
||||
async safeGetList() {
|
||||
try {
|
||||
return await this.getList()
|
||||
} catch (error) {
|
||||
// 如果已经有默认数据,直接返回
|
||||
if (this.unitData.length > 0) {
|
||||
console.log('使用现有单位数据')
|
||||
return { rows: this.unitData, total: this.unitData.length }
|
||||
}
|
||||
// 尝试从缓存加载
|
||||
const cachedData = this.loadFromStorage()
|
||||
if (cachedData && Object.keys(cachedData).length > 0) {
|
||||
console.log('使用缓存中的单位数据')
|
||||
return { rows: this.unitData, total: this.unitData.length }
|
||||
}
|
||||
return { rows: [], total: 0 }
|
||||
}
|
||||
},
|
||||
|
||||
// 从存储加载缓存的单位数据 - 兼容多平台
|
||||
loadFromStorage(): GroupedUnitData | false {
|
||||
try {
|
||||
let storedData = null
|
||||
|
||||
// 统一使用uni API作为基础(跨平台兼容)
|
||||
try {
|
||||
storedData = uni.getStorageSync('unitData')
|
||||
} catch (e) {
|
||||
// 备用方案:H5/localStorage
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
storedData = localStorage.getItem('unitData')
|
||||
}
|
||||
}
|
||||
|
||||
if (!storedData) {
|
||||
console.log('无缓存的单位数据')
|
||||
return false // 明确返回false,避免undefined
|
||||
}
|
||||
|
||||
// 处理JSON字符串和对象两种情况
|
||||
const parsedData = typeof storedData === 'string'
|
||||
? JSON.parse(storedData)
|
||||
: storedData
|
||||
|
||||
// 验证数据结构
|
||||
if (typeof parsedData !== 'object' || parsedData === null) {
|
||||
console.warn('缓存的单位数据格式无效')
|
||||
return false
|
||||
}
|
||||
|
||||
this.groupedUnitData = parsedData
|
||||
// 从分组数据中提取所有单位
|
||||
this.unitData = Object.values(this.groupedUnitData).flat()
|
||||
|
||||
console.log('从缓存加载单位数据成功,类型数:', Object.keys(this.groupedUnitData).length)
|
||||
return this.groupedUnitData
|
||||
} catch (error) {
|
||||
console.error('从存储加载单位数据失败:', error)
|
||||
return false // 明确返回false
|
||||
}
|
||||
},
|
||||
|
||||
// 保存单位数据到存储 - 兼容多平台
|
||||
saveUnitDataToStorage(): boolean {
|
||||
try {
|
||||
const dataStr = JSON.stringify(this.groupedUnitData)
|
||||
|
||||
// 优先使用uni API
|
||||
try {
|
||||
uni.setStorageSync('unitData', dataStr)
|
||||
} catch (e) {
|
||||
// 备用方案:H5/localStorage
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('unitData', dataStr)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
console.log('单位数据已保存到缓存')
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('保存单位数据到存储失败:', error)
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
// 清除存储中的单位数据 - 兼容多平台
|
||||
clearStorage(): boolean {
|
||||
try {
|
||||
// 优先使用uni API
|
||||
try {
|
||||
uni.removeStorageSync('unitData')
|
||||
} catch (e) {
|
||||
// 备用方案:H5/localStorage
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.removeItem('unitData')
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('清除存储单位数据失败:', error)
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
// 单位转换方法
|
||||
convertUnit(value: number, fromUnit: UnitItem, toUnit: UnitItem): number {
|
||||
if (!fromUnit || !toUnit) {
|
||||
throw new Error('单位参数不能为空')
|
||||
}
|
||||
|
||||
if (fromUnit.unitType !== toUnit.unitType) {
|
||||
throw new Error('单位类型不匹配,无法转换')
|
||||
}
|
||||
|
||||
// 先转换到基本单位,再从基本单位转换到目标单位
|
||||
const valueInBaseUnit = value * (fromUnit.conversionFactor || 1)
|
||||
return valueInBaseUnit / (toUnit.conversionFactor || 1)
|
||||
},
|
||||
|
||||
// 根据单位名称查找单位
|
||||
findUnitByName(unitName: string): UnitItem | undefined {
|
||||
return this.unitData.find(unit => unit.unitName === unitName)
|
||||
},
|
||||
|
||||
// 根据ID查找单位
|
||||
findUnitById(id: number): UnitItem | undefined {
|
||||
return this.unitData.find(unit => unit.id === id)
|
||||
},
|
||||
|
||||
// 刷新单位数据
|
||||
async refresh() {
|
||||
return await this.safeGetList()
|
||||
},
|
||||
|
||||
// 获取有效的单位列表(状态为正常的)
|
||||
getActiveUnits(unitType?: string): UnitItem[] {
|
||||
const units = unitType
|
||||
? (this.groupedUnitData[unitType] || [])
|
||||
: this.unitData
|
||||
|
||||
// 状态可能为'0'或'正常',做兼容处理
|
||||
return units.filter(unit =>
|
||||
unit.status === '0' || unit.status === '正常' || unit.status === '1'
|
||||
)
|
||||
},
|
||||
|
||||
// 根据类型和名称模糊查询单位
|
||||
searchUnits(type: string, keyword: string): UnitItem[] {
|
||||
const units = this.groupedUnitData[type] || []
|
||||
return units.filter(unit =>
|
||||
unit.unitName.includes(keyword) ||
|
||||
(unit.unitTypeName && unit.unitTypeName.includes(keyword))
|
||||
)
|
||||
},
|
||||
|
||||
// 恢复单位数据(兼容旧接口名)
|
||||
restoreUnitDataFromLocal() {
|
||||
return this.loadFromStorage()
|
||||
},
|
||||
|
||||
// 清除错误
|
||||
clearError() {
|
||||
this.error = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default useUnitStore
|
||||
@ -1,6 +1,5 @@
|
||||
import { login, logout, getInfo } from "@/api/login";
|
||||
import { getToken, setToken, removeToken } from "@/utils/auth";
|
||||
import defAva from "@/static/images/profile.jpg";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export interface LoginForm {
|
||||
@ -43,10 +42,7 @@ const useUserStore = defineStore("user", {
|
||||
getInfo()
|
||||
.then((res: any) => {
|
||||
const user = res.user;
|
||||
const avatar =
|
||||
user.avatar == "" || user.avatar == null
|
||||
? defAva
|
||||
: user.avatar;
|
||||
const avatar =user.avatar;
|
||||
|
||||
if (res.roles && res.roles.length > 0) {
|
||||
// 验证返回的roles是否是一个非空数组
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class=" a-yjly-inputunit" :style="{ width: width + 'px' }">
|
||||
<view class="a-yjly-inputunit" :style="{ width: width + 'px' }">
|
||||
<!-- 数值输入框 -->
|
||||
<input v-model.number="inputValue" class="input-field" type="number" :ref="'inputRef'" :style="{
|
||||
width: inputWidth + 'px',
|
||||
@ -30,9 +30,7 @@
|
||||
}">
|
||||
<scroll-view scroll-y :style="{ maxHeight: '300px' }">
|
||||
<view v-for="(unit, index) in sortedUnits" :key="unit.id" class="unit-option"
|
||||
:class="{ active: activeIndex === index }" <!-- 动态绑定active类 -->
|
||||
@tap="() => { selectUnit(unit); setActiveIndex(index); }" <!-- 点击时设置active -->
|
||||
>
|
||||
:class="{ active: activeIndex === index }" @tap="selectUnitHandler(unit, index)">
|
||||
{{ showEnglishOnly ? unit.unitName.split('(')[0] : unit.unitName }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
@ -41,12 +39,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
storage
|
||||
} from '@/utils/storageUnit.ts';
|
||||
import {
|
||||
ref
|
||||
} from 'vue';
|
||||
import useUnitStore from '@/store/modules/unitData.ts';
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
name: 'UniUnitConverter',
|
||||
@ -106,30 +101,12 @@
|
||||
textUnitName: '',
|
||||
unitSelectorLeft: 0,
|
||||
unitSelectorTop: 0,
|
||||
|
||||
// unitDatalist: [],
|
||||
|
||||
/* 新增三个数据项 */
|
||||
originalValue: this.modelValue, // 原始输入值
|
||||
originalUnit: null, // 原始输入单位
|
||||
isInternalUpdate: false, // 更新锁定标志
|
||||
|
||||
// 新增:管理当前选中的索引
|
||||
originalValue: this.modelValue,
|
||||
originalUnit: null,
|
||||
isInternalUpdate: false,
|
||||
activeIndex: -1
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
mounted() {
|
||||
this.initComponent();
|
||||
this.setGlobalClickHandler();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.removeGlobalClickHandler();
|
||||
unitOrder;
|
||||
},
|
||||
computed: {
|
||||
sortedUnits() {
|
||||
return this.unitData.filter((u) => u.unitType === this.unitType).sort((a, b) => a.unitOrder - b.unitOrder);
|
||||
@ -163,7 +140,6 @@
|
||||
},
|
||||
modelValue(newVal) {
|
||||
if (!this.isInternalUpdate) {
|
||||
// 外部更新时重置原始值
|
||||
this.originalValue = newVal;
|
||||
this.originalUnit = this.currentUnit;
|
||||
this.inputValue = newVal;
|
||||
@ -171,35 +147,27 @@
|
||||
this.isInternalUpdate = false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initComponent();
|
||||
},
|
||||
methods: {
|
||||
async initComponent() {
|
||||
await this.$nextTick();
|
||||
this.updateInputWidth();
|
||||
},
|
||||
// 新增:设置active索引
|
||||
|
||||
setActiveIndex(index) {
|
||||
activeIndex.value = index;
|
||||
},
|
||||
setGlobalClickHandler() {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.addEventListener('click', this.handleClickOutside);
|
||||
}
|
||||
this.activeIndex = index;
|
||||
},
|
||||
|
||||
removeGlobalClickHandler() {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.removeEventListener('click', this.handleClickOutside);
|
||||
}
|
||||
// 统一处理单位选择
|
||||
selectUnitHandler(unit, index) {
|
||||
this.selectUnit(unit);
|
||||
this.setActiveIndex(index);
|
||||
},
|
||||
|
||||
handleClickOutside(event) {
|
||||
if (!this.showUnitSelector) return;
|
||||
|
||||
const selector = this.$refs.unitSelector;
|
||||
if (!selector) return;
|
||||
|
||||
const isOutside = !selector.$el.contains(event.target);
|
||||
if (isOutside) {
|
||||
handleClickOutside() {
|
||||
if (this.showUnitSelector) {
|
||||
this.showUnitSelector = false;
|
||||
}
|
||||
},
|
||||
@ -208,50 +176,51 @@
|
||||
try {
|
||||
let tempData = null;
|
||||
|
||||
tempData = storage.getItem('unitData');
|
||||
let unitStore = useUnitStore();
|
||||
|
||||
tempData = unitStore.loadFromStorage();
|
||||
|
||||
console.log('从存储获取的数据:', tempData);
|
||||
// 2. 缓存无数据时,调用接口获取
|
||||
if (!tempData || !tempData[unitType]) {
|
||||
// console.error(`单位类型 ${unitType} 的数据不存在`);
|
||||
console.log('缓存无对应类型数据,从接口获取');
|
||||
await unitStore.safeGetList();
|
||||
tempData = unitStore.groupedUnitData;
|
||||
}
|
||||
// 3. 赋值处理
|
||||
this.unitData = tempData[unitType] || [];
|
||||
|
||||
if (this.unitData.length === 0) {
|
||||
console.warn(`未找到${unitType}类型的单位数据`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.unitData = tempData[unitType];
|
||||
// console.log('筛选后的单位数据:', this.unitData);
|
||||
|
||||
if (!this.unitData || this.unitData.length === 0) {
|
||||
// console.error(`单位类型 ${unitType} 的数据为空`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.baseUnit = this.unitData.find((u) => u.baseUnit === 'Y');
|
||||
// console.log('基准单位:', this.baseUnit);
|
||||
// 4. 兼容baseUnit为'1'或'Y'的情况
|
||||
this.baseUnit = this.unitData.find((u) => u.baseUnit === 'Y' || u.baseUnit === '1') || this
|
||||
.unitData[0];
|
||||
|
||||
} catch (e) {
|
||||
console.error('单位数据加载失败:', e);
|
||||
}
|
||||
},
|
||||
|
||||
/* 初始化当前单位补充 */
|
||||
initCurrentUnit() {
|
||||
const target = this.sortedUnits.find((u) => u.unitOrder === this.unitOrder);
|
||||
this.currentUnit = target || this.baseUnit || this.sortedUnits[0];
|
||||
// 初始化原始单位
|
||||
this.originalUnit = this.currentUnit;
|
||||
this.textUnitName = this.showEnglishOnly ? this.currentUnit.unitName.split('(')[0].trim() : this
|
||||
.currentUnit.unitName;
|
||||
this.textUnitName = this.showEnglishOnly ?
|
||||
this.currentUnit.unitName.split('(')[0].trim() :
|
||||
this.currentUnit.unitName;
|
||||
this.$nextTick(() => this.updateInputWidth());
|
||||
},
|
||||
|
||||
updateInputWidth() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.unit-label')
|
||||
.boundingClientRect((res) => {
|
||||
query.select('.unit-label').boundingClientRect(res => {
|
||||
if (res) {
|
||||
this.inputWidth = this.width - res.width - 4;
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}).exec();
|
||||
},
|
||||
|
||||
handleLongPress() {
|
||||
@ -261,23 +230,21 @@
|
||||
|
||||
positionUnitSelector() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.unit-label')
|
||||
.boundingClientRect((res) => {
|
||||
query.select('.unit-label').boundingClientRect(res => {
|
||||
if (res) {
|
||||
this.unitSelectorLeft = res.left;
|
||||
this.unitSelectorTop = res.bottom + 5;
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}).exec();
|
||||
},
|
||||
|
||||
/* 修改单位切换方法 */
|
||||
cycleUnit() {
|
||||
const index = this.sortedUnits.findIndex((u) => u === this.currentUnit);
|
||||
const newUnit = this.sortedUnits[(index + 1) % this.sortedUnits.length];
|
||||
this.currentUnit = newUnit;
|
||||
this.textUnitName = this.showEnglishOnly ? newUnit.unitName.split('(')[0].trim() : newUnit.unitName;
|
||||
this.textUnitName = this.showEnglishOnly ?
|
||||
newUnit.unitName.split('(')[0].trim() :
|
||||
newUnit.unitName;
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.updateInputWidth();
|
||||
@ -292,7 +259,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
/* 修改单位选择方法 */
|
||||
selectUnit(unit) {
|
||||
this.currentUnit = unit;
|
||||
this.showUnitSelector = false;
|
||||
@ -300,18 +266,15 @@
|
||||
this.updateInputWidth();
|
||||
this.convertAndEmit();
|
||||
});
|
||||
activeIndex.value = -1; // 选择后重置active态(可选)
|
||||
this.activeIndex = -1;
|
||||
},
|
||||
|
||||
/* 修改输入处理 */
|
||||
handleInputChange() {
|
||||
// 记录原始值和单位
|
||||
this.originalValue = this.inputValue;
|
||||
this.originalUnit = this.currentUnit;
|
||||
this.$emit('update:modelValue', this.inputValue);
|
||||
},
|
||||
|
||||
/* 优化后的转换方法 */
|
||||
convertAndEmit() {
|
||||
if (!this.currentUnit || !this.baseUnit || !this.originalUnit) return;
|
||||
|
||||
@ -319,13 +282,12 @@
|
||||
if (this.unitType === 'temperature') {
|
||||
newValue = this.handleTemperatureConversion();
|
||||
} else {
|
||||
// 通过基准单位进行两次精确转换
|
||||
const baseValue = this.originalValue / this.originalUnit.conversionFactor;
|
||||
newValue = baseValue * this.currentUnit.conversionFactor;
|
||||
}
|
||||
|
||||
const roundedValue = this.roundValue(newValue);
|
||||
this.isInternalUpdate = true; // 锁定更新
|
||||
this.isInternalUpdate = true;
|
||||
this.inputValue = roundedValue;
|
||||
this.$emit('update:modelValue', roundedValue);
|
||||
this.$emit('update:unitOrder', this.currentUnit.unitOrder);
|
||||
@ -340,14 +302,12 @@
|
||||
});
|
||||
},
|
||||
|
||||
/* 优化温度转换方法 */
|
||||
handleTemperatureConversion() {
|
||||
const oldUnit = this.originalUnit;
|
||||
const newUnit = this.currentUnit;
|
||||
const oldOrder = oldUnit.unitOrder;
|
||||
const newOrder = newUnit.unitOrder;
|
||||
|
||||
// 使用原始值计算
|
||||
let celsius;
|
||||
switch (oldOrder) {
|
||||
case 0:
|
||||
@ -375,7 +335,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
// 四舍六入五成双
|
||||
roundValue(value) {
|
||||
const multiplier = Math.pow(10, this.decimalPlaces);
|
||||
const val = value * multiplier;
|
||||
@ -405,6 +364,7 @@
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
padding: 0 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.unit-label {
|
||||
@ -416,6 +376,7 @@
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
margin-left: 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.unit-selector {
|
||||
@ -426,14 +387,21 @@
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
min-width: 120px;
|
||||
max-height: 300px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.unit-option {
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.unit-option.active {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.unit-option:active {
|
||||
background-color: #f0f0f0;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
@ -1,13 +1,78 @@
|
||||
const TokenKey = 'App-Token'
|
||||
|
||||
export function getToken():string {
|
||||
return uni.getStorageSync(TokenKey)
|
||||
/**
|
||||
* 获取Token(兼容多平台,带错误处理)
|
||||
* @returns string 空字符串表示无Token
|
||||
*/
|
||||
export function getToken(): string {
|
||||
try {
|
||||
// 优先使用uniapp API
|
||||
const token = uni.getStorageSync(TokenKey)
|
||||
// 处理非字符串场景(如存入了null/undefined)
|
||||
return token ? String(token) : ''
|
||||
} catch (error) {
|
||||
// 兼容H5隐私模式/localStorage不可用场景
|
||||
console.warn('获取Token失败:', error)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export function setToken(token:string) {
|
||||
return uni.setStorageSync(TokenKey, token)
|
||||
/**
|
||||
* 设置Token(兼容多平台,带错误处理)
|
||||
* @param token 必须为字符串,非字符串会自动转换
|
||||
* @returns boolean 是否设置成功
|
||||
*/
|
||||
export function setToken(token: string): boolean {
|
||||
try {
|
||||
if (typeof token !== 'string') {
|
||||
console.warn('Token必须为字符串,已自动转换')
|
||||
token = String(token)
|
||||
}
|
||||
uni.setStorageSync(TokenKey, token)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('设置Token失败:', error)
|
||||
// H5兜底:尝试直接操作localStorage
|
||||
if (process.env.VUE_APP_PLATFORM === 'h5' && typeof localStorage !== 'undefined') {
|
||||
try {
|
||||
localStorage.setItem(TokenKey, token)
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('H5 localStorage设置失败:', e)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return uni.removeStorageSync(TokenKey)
|
||||
/**
|
||||
* 移除Token(兼容多平台,带错误处理)
|
||||
* @returns boolean 是否移除成功
|
||||
*/
|
||||
export function removeToken(): boolean {
|
||||
try {
|
||||
uni.removeStorageSync(TokenKey)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('移除Token失败:', error)
|
||||
// H5兜底
|
||||
if (process.env.VUE_APP_PLATFORM === 'h5' && typeof localStorage !== 'undefined') {
|
||||
try {
|
||||
localStorage.removeItem(TokenKey)
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('H5 localStorage移除失败:', e)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查Token是否有效(辅助函数)
|
||||
* @returns boolean
|
||||
*/
|
||||
export function hasValidToken(): boolean {
|
||||
const token = getToken()
|
||||
return !!token && token.trim() !== ''
|
||||
}
|
||||
@ -8,7 +8,7 @@ import useUserStore from '@/store/modules/user'
|
||||
let timeout = 10000
|
||||
const baseUrl = config.baseUrl
|
||||
|
||||
const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
||||
const request = <T>(config : RequestConfig) : Promise<ResponseData<T>> => {
|
||||
// 是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
config.header = config.header || {}
|
||||
@ -37,10 +37,10 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
||||
return
|
||||
} */
|
||||
const res = response
|
||||
const data: ResponseData<T> = res.data as ResponseData<T>
|
||||
const data : ResponseData<T> = res.data as ResponseData<T>
|
||||
const code = data.code || 200
|
||||
// @ts-ignore
|
||||
const msg: string = errorCode[code] || data.msg || errorCode['default']
|
||||
const msg : string = errorCode[code] || data.msg || errorCode['default']
|
||||
if (code === 401) {
|
||||
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
|
||||
if (res.confirm) {
|
||||
@ -63,47 +63,45 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
||||
// === 修复这里的问题 ===
|
||||
let message = '网络请求失败'
|
||||
|
||||
// 安全地获取错误信息
|
||||
if (error) {
|
||||
// 小程序环境错误对象可能有不同的结构
|
||||
if (error.errMsg) {
|
||||
message = error.errMsg
|
||||
} else if (error.message) {
|
||||
message = error.message
|
||||
|
||||
// === 重点修复:安全提取错误信息 ===
|
||||
if (error && typeof error === 'object') {
|
||||
// 优先使用后端返回的错误消息
|
||||
if (error.data?.msg) message = error.data.msg;
|
||||
// 小程序特有的错误结构
|
||||
else if (error.errMsg) message = error.errMsg;
|
||||
// 常规错误消息
|
||||
else if (error.message) message = error.message;
|
||||
} else if (typeof error === 'string') {
|
||||
message = error
|
||||
}
|
||||
message = error;
|
||||
}
|
||||
|
||||
// 安全地使用 includes 方法 - 添加类型检查
|
||||
if (message && typeof message === 'string') {
|
||||
// 特殊错误处理
|
||||
if (message.includes('Network Error')) {
|
||||
message = '后端接口连接异常'
|
||||
message = '网络连接异常';
|
||||
} else if (message.includes('timeout')) {
|
||||
message = '系统接口请求超时'
|
||||
} else if (message.includes('Request failed with status code')) {
|
||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||
message = '请求超时,请检查网络';
|
||||
}
|
||||
} else {
|
||||
// 如果 message 不是字符串,转换为字符串
|
||||
message = String(message || '未知错误')
|
||||
}
|
||||
toast(message)
|
||||
reject(error)
|
||||
|
||||
toast(message);
|
||||
|
||||
// === 关键:返回带code的错误对象 ===
|
||||
const err = new Error(message);
|
||||
err.code = error.statusCode || 500; // 保留HTTP状态码
|
||||
reject(err);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function postAction(url: string, data?: any, isToken: boolean = true) {
|
||||
export function postAction(url : string, data ?: any, isToken : boolean = true) {
|
||||
return request({ data, url, method: 'POST', headers: { isToken }, })
|
||||
}
|
||||
export function getAction(url: string, params?: any, isToken: boolean = true) {
|
||||
export function getAction(url : string, params ?: any, isToken : boolean = true) {
|
||||
return request({ params, url, method: 'GET', headers: { isToken }, })
|
||||
}
|
||||
export function putAction(url: string, data?: any, isToken: boolean = true) {
|
||||
export function putAction(url : string, data ?: any, isToken : boolean = true) {
|
||||
return request({ data, url, method: 'PUT', headers: { isToken }, })
|
||||
}
|
||||
export function deleteAction(url: string, data?: any, isToken: boolean = true) {
|
||||
export function deleteAction(url : string, data ?: any, isToken : boolean = true) {
|
||||
return request({ data, url, method: 'DELETE', headers: { isToken }, })
|
||||
}
|
||||
|
||||
|
||||
@ -26,3 +26,22 @@ export default defineConfig(() => {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
configureWebpack: {
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: 'async', // 仅异步代码抽离
|
||||
minSize: 20000, // 大于20KB才抽离
|
||||
cacheGroups: {
|
||||
commons: {
|
||||
name: 'commons',
|
||||
chunks: 'initial',
|
||||
minChunks: 2, // 被引用2次以上抽离
|
||||
priority: -10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||