修改单位存储,获取错误,微信小程序发布成功
This commit is contained in:
parent
4d837466d0
commit
33847fef1c
@ -4,9 +4,7 @@ import request from '@/utils/request'
|
|||||||
export function listConvert(query) {
|
export function listConvert(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/convert/list',
|
url: '/system/convert/list',
|
||||||
headers: {
|
|
||||||
isToken: false
|
|
||||||
},
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
@ -16,9 +14,7 @@ export function listConvert(query) {
|
|||||||
export function getConvert(id) {
|
export function getConvert(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/convert/' + id,
|
url: '/system/convert/' + id,
|
||||||
headers: {
|
|
||||||
isToken: false
|
|
||||||
},
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -27,9 +23,7 @@ export function getConvert(id) {
|
|||||||
export function addConvert(data) {
|
export function addConvert(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/convert',
|
url: '/system/convert',
|
||||||
headers: {
|
|
||||||
isToken: false
|
|
||||||
},
|
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
@ -39,9 +33,7 @@ export function addConvert(data) {
|
|||||||
export function updateConvert(data) {
|
export function updateConvert(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/convert',
|
url: '/system/convert',
|
||||||
headers: {
|
|
||||||
isToken: false
|
|
||||||
},
|
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
@ -51,9 +43,7 @@ export function updateConvert(data) {
|
|||||||
export function delConvert(id) {
|
export function delConvert(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/convert/' + id,
|
url: '/system/convert/' + id,
|
||||||
headers: {
|
|
||||||
isToken: false
|
|
||||||
},
|
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import plugins from './plugins'
|
import plugins from './plugins'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
import uviewPlus from 'uview-plus'
|
|
||||||
|
|
||||||
|
|
||||||
import { createSSRApp } from 'vue'
|
import { createSSRApp } from 'vue'
|
||||||
@ -14,8 +13,7 @@ import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, select
|
|||||||
|
|
||||||
export function createApp() {
|
export function createApp() {
|
||||||
const app = createSSRApp(App)
|
const app = createSSRApp(App)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.use(uviewPlus)
|
|
||||||
app.use(plugins)
|
app.use(plugins)
|
||||||
|
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
|
|||||||
@ -16,6 +16,9 @@
|
|||||||
"autoclose" : true,
|
"autoclose" : true,
|
||||||
"delay" : 0
|
"delay" : 0
|
||||||
},
|
},
|
||||||
|
"compatible" : {
|
||||||
|
"ignoreVersion" : true // 忽略版本检查
|
||||||
|
},
|
||||||
/* 模块配置 */
|
/* 模块配置 */
|
||||||
"modules" : {
|
"modules" : {
|
||||||
"OAuth" : {}
|
"OAuth" : {}
|
||||||
|
|||||||
@ -33,16 +33,22 @@
|
|||||||
ref,
|
ref,
|
||||||
onMounted
|
onMounted
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import modal from "@/plugins/modal"
|
import modal from "@/plugins/modal"
|
||||||
import {
|
|
||||||
storage
|
|
||||||
} from '@/utils/storageUnit.ts';
|
|
||||||
import {
|
import {
|
||||||
extractModuleData
|
extractModuleData
|
||||||
} from '@/utils/moudlesData.ts';
|
} from '@/utils/moudlesData.ts';
|
||||||
import useUnitStore from '@/store/modules/unitData.ts';
|
|
||||||
|
import useUnitStore from '@/store/modules/unitData.ts';
|
||||||
|
import {
|
||||||
|
getToken,
|
||||||
|
setToken,
|
||||||
|
removeToken
|
||||||
|
} from "@/utils/auth";
|
||||||
|
|
||||||
const unitStore = useUnitStore();
|
const unitStore = useUnitStore();
|
||||||
|
|
||||||
|
|
||||||
const current = ref(0);
|
const current = ref(0);
|
||||||
const swiperDotIndex = ref(0);
|
const swiperDotIndex = ref(0);
|
||||||
const data = ref([{
|
const data = ref([{
|
||||||
@ -58,14 +64,60 @@
|
|||||||
|
|
||||||
// 核心数据:计算分组和功能项定义
|
// 核心数据:计算分组和功能项定义
|
||||||
const moudlesGroups = ref([]);
|
const moudlesGroups = ref([]);
|
||||||
|
|
||||||
onMounted(async() => {
|
// 登录状态校验函数
|
||||||
|
const checkLoginStatus = () => {
|
||||||
|
// 1. 检查本地token是否存在
|
||||||
|
const token = getToken();
|
||||||
|
|
||||||
|
console.log(token)
|
||||||
|
// 2. 无token/用户信息,直接跳转登录
|
||||||
|
if (!token) {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/login'
|
||||||
|
});
|
||||||
|
return false; // 未登录
|
||||||
|
}
|
||||||
|
return true; // 已登录
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 第一步:优先校验登录状态(核心修复)
|
||||||
|
const isLogin = checkLoginStatus();
|
||||||
|
if (!isLogin) return; // 未登录则终止后续逻辑
|
||||||
moudlesGroups.value = extractModuleData(['流量计算', '参数计算'], false)
|
moudlesGroups.value = extractModuleData(['流量计算', '参数计算'], false)
|
||||||
// 优先从本地缓存恢复,再请求最新数据
|
// 优先从本地缓存恢复,再请求最新数据
|
||||||
unitStore.restoreUnitDataFromLocal();
|
unitStore.restoreUnitDataFromLocal();
|
||||||
await unitStore.getList();
|
try {
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function navigateToMoudles(item) {
|
function navigateToMoudles(item) {
|
||||||
console.log(item)
|
console.log(item)
|
||||||
|
|||||||
@ -130,12 +130,17 @@
|
|||||||
wxLogin,
|
wxLogin,
|
||||||
wxAppLogin
|
wxAppLogin
|
||||||
} from '@/api/oauth'
|
} from '@/api/oauth'
|
||||||
import useUserStore from '@/store/modules/user'
|
|
||||||
import {
|
import {
|
||||||
setToken
|
setToken
|
||||||
} from '@/utils/auth'
|
} from '@/utils/auth'
|
||||||
import config from '@/config.js'
|
import config from '@/config.js'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 添加一个标志位,防止重复跳转
|
||||||
|
let isChecking = false;
|
||||||
|
let hasChecked = false;
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const appName = config.appInfo.name || '天然气工具箱'
|
const appName = config.appInfo.name || '天然气工具箱'
|
||||||
|
|
||||||
@ -245,13 +250,18 @@
|
|||||||
|
|
||||||
const res = await login(params.username, params.password, params.code, params.uuid)
|
const res = await login(params.username, params.password, params.code, params.uuid)
|
||||||
|
|
||||||
|
|
||||||
if (res.token) {
|
if (res.token) {
|
||||||
setToken(res.token)
|
setToken(res.token)
|
||||||
await userStore.getInfo()
|
await userStore.getInfo()
|
||||||
uni.switchTab({
|
|
||||||
url: '/pages/index'
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 添加延迟,确保状态更新完成
|
||||||
|
setTimeout(() => {
|
||||||
|
// 使用 reLaunch 关闭所有页面并跳转到首页
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index'
|
||||||
|
})
|
||||||
|
}, 300)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 如果需要验证码,重新获取
|
// 如果需要验证码,重新获取
|
||||||
@ -348,7 +358,7 @@
|
|||||||
|
|
||||||
if (platform === 'android' || platform === 'ios') {
|
if (platform === 'android' || platform === 'ios') {
|
||||||
// APP 端
|
// APP 端
|
||||||
code = await wechatLoginApp();
|
code = await wechatLoginApp();
|
||||||
|
|
||||||
console.log(code);
|
console.log(code);
|
||||||
|
|
||||||
@ -405,15 +415,55 @@
|
|||||||
getCaptcha()
|
getCaptcha()
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(async (options) => {
|
||||||
// 检查是否有token,如果有则直接跳转
|
// === 新增:防止重复检查 ===
|
||||||
const token = uni.getStorageSync('token')
|
if (isChecking || hasChecked) return;
|
||||||
if (token) {
|
isChecking = true;
|
||||||
uni.reLaunch({
|
|
||||||
url: '/pages/index'
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -1,18 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import logo from 'https://ngtools.cn:3000/static/logo.png';
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<view class="taobao">
|
<view class="taobao">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
<view class="left">
|
<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 class="store">袜子精保护协会</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="entrance">进店</view>
|
<view class="entrance">进店</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="ticket">
|
<view class="ticket">
|
||||||
<view class="left">
|
<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="introduce">
|
||||||
<view class="top">
|
<view class="top">
|
||||||
¥
|
¥
|
||||||
|
|||||||
@ -133,32 +133,6 @@ export const useUnitStore = defineStore('unit', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 处理API错误
|
|
||||||
handleApiError(error: any) {
|
|
||||||
console.error('API请求错误:', error)
|
|
||||||
this.error = error.message || '请求失败'
|
|
||||||
|
|
||||||
// 如果是403错误,可能是未登录或权限不足
|
|
||||||
if (error.statusCode === 403 || error.errMsg?.includes('403')) {
|
|
||||||
console.warn('获取单位数据失败,可能是未登录或权限不足')
|
|
||||||
this.error = '未登录或权限不足,将使用默认单位数据'
|
|
||||||
|
|
||||||
// 检查是否已登录
|
|
||||||
try {
|
|
||||||
const token = uni.getStorageSync('token')
|
|
||||||
if (!token) {
|
|
||||||
console.log('用户未登录')
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('检查登录状态失败:', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取单位列表 - 兼容多平台,带错误处理
|
// 获取单位列表 - 兼容多平台,带错误处理
|
||||||
async getList() {
|
async getList() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
@ -166,7 +140,7 @@ export const useUnitStore = defineStore('unit', {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await listConvert(this.queryParams)
|
const response = await listConvert(this.queryParams)
|
||||||
console.log('单位数据:', response)
|
console.log('单位数据:', response)
|
||||||
this.unitData = response.rows || []
|
this.unitData = response.rows || []
|
||||||
this.total = response.total || 0
|
this.total = response.total || 0
|
||||||
this.groupedUnitData = this.groupByUnitType(this.unitData)
|
this.groupedUnitData = this.groupByUnitType(this.unitData)
|
||||||
@ -177,7 +151,8 @@ export const useUnitStore = defineStore('unit', {
|
|||||||
console.log('单位数据获取成功,类型数量:', Object.keys(this.groupedUnitData).length)
|
console.log('单位数据获取成功,类型数量:', Object.keys(this.groupedUnitData).length)
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.handleApiError(error)
|
this.error = error instanceof Error ? error.message : '获取单位数据失败'
|
||||||
|
console.error('获取单位数据出错:', error)
|
||||||
throw error
|
throw error
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
@ -194,76 +169,77 @@ export const useUnitStore = defineStore('unit', {
|
|||||||
console.log('使用现有单位数据')
|
console.log('使用现有单位数据')
|
||||||
return { rows: this.unitData, total: this.unitData.length }
|
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 }
|
return { rows: [], total: 0 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 从存储加载缓存的单位数据 - 兼容多平台
|
// 从存储加载缓存的单位数据 - 兼容多平台
|
||||||
loadFromStorage() {
|
loadFromStorage(): GroupedUnitData | false {
|
||||||
try {
|
try {
|
||||||
let storedData = null
|
let storedData = null
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-LARK || MP-KUAISHOU
|
// 统一使用uni API作为基础(跨平台兼容)
|
||||||
// 微信小程序等平台使用uni.getStorageSync
|
|
||||||
storedData = uni.getStorageSync('unitData')
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS || H5
|
|
||||||
// App和H5平台使用localStorage
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
storedData = localStorage.getItem('unitData')
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef HARMONY
|
|
||||||
// 鸿蒙平台使用鸿蒙API(这里需要根据鸿蒙API调整)
|
|
||||||
// 暂时使用uni.getStorageSync作为备选
|
|
||||||
try {
|
try {
|
||||||
storedData = uni.getStorageSync('unitData')
|
storedData = uni.getStorageSync('unitData')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('鸿蒙平台存储获取失败:', e)
|
// 备用方案:H5/localStorage
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
storedData = localStorage.getItem('unitData')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endif
|
|
||||||
|
|
||||||
if (storedData) {
|
if (!storedData) {
|
||||||
this.groupedUnitData = JSON.parse(storedData)
|
console.log('无缓存的单位数据')
|
||||||
// 从分组数据中提取所有单位
|
return false // 明确返回false,避免undefined
|
||||||
this.unitData = Object.values(this.groupedUnitData).flat()
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理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) {
|
} catch (error) {
|
||||||
console.error('从存储加载单位数据失败:', error)
|
console.error('从存储加载单位数据失败:', error)
|
||||||
|
return false // 明确返回false
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存单位数据到存储 - 兼容多平台
|
// 保存单位数据到存储 - 兼容多平台
|
||||||
saveUnitDataToStorage() {
|
saveUnitDataToStorage(): boolean {
|
||||||
try {
|
try {
|
||||||
const dataStr = JSON.stringify(this.groupedUnitData)
|
const dataStr = JSON.stringify(this.groupedUnitData)
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-LARK || MP-KUAISHOU
|
// 优先使用uni API
|
||||||
// 微信小程序等平台使用uni.setStorageSync
|
|
||||||
uni.setStorageSync('unitData', dataStr)
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS || H5
|
|
||||||
// App和H5平台使用localStorage
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
localStorage.setItem('unitData', dataStr)
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef HARMONY
|
|
||||||
// 鸿蒙平台使用鸿蒙API(这里需要根据鸿蒙API调整)
|
|
||||||
// 暂时使用uni.setStorageSync作为备选
|
|
||||||
try {
|
try {
|
||||||
uni.setStorageSync('unitData', dataStr)
|
uni.setStorageSync('unitData', dataStr)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('鸿蒙平台存储保存失败:', e)
|
// 备用方案:H5/localStorage
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
localStorage.setItem('unitData', dataStr)
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endif
|
|
||||||
|
|
||||||
|
console.log('单位数据已保存到缓存')
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存单位数据到存储失败:', error)
|
console.error('保存单位数据到存储失败:', error)
|
||||||
@ -272,29 +248,19 @@ export const useUnitStore = defineStore('unit', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 清除存储中的单位数据 - 兼容多平台
|
// 清除存储中的单位数据 - 兼容多平台
|
||||||
clearStorage() {
|
clearStorage(): boolean {
|
||||||
try {
|
try {
|
||||||
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-LARK || MP-KUAISHOU
|
// 优先使用uni API
|
||||||
// 微信小程序等平台使用uni.removeStorageSync
|
|
||||||
uni.removeStorageSync('unitData')
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS || H5
|
|
||||||
// App和H5平台使用localStorage
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
localStorage.removeItem('unitData')
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef HARMONY
|
|
||||||
// 鸿蒙平台使用鸿蒙API(这里需要根据鸿蒙API调整)
|
|
||||||
// 暂时使用uni.removeStorageSync作为备选
|
|
||||||
try {
|
try {
|
||||||
uni.removeStorageSync('unitData')
|
uni.removeStorageSync('unitData')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('鸿蒙平台存储清除失败:', e)
|
// 备用方案:H5/localStorage
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
localStorage.removeItem('unitData')
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endif
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -359,10 +325,6 @@ export const useUnitStore = defineStore('unit', {
|
|||||||
return this.loadFromStorage()
|
return this.loadFromStorage()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 清除错误
|
// 清除错误
|
||||||
clearError() {
|
clearError() {
|
||||||
this.error = null
|
this.error = null
|
||||||
|
|||||||
@ -1,63 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="a-yjly-inputunit" :style="{ width: width + 'px' }">
|
<view class="a-yjly-inputunit" :style="{ width: width + 'px' }">
|
||||||
<!-- 数值输入框 -->
|
<!-- 数值输入框 -->
|
||||||
<input
|
<input v-model.number="inputValue" class="input-field" type="number" :ref="'inputRef'" :style="{
|
||||||
v-model.number="inputValue"
|
|
||||||
class="input-field"
|
|
||||||
type="number"
|
|
||||||
:ref="'inputRef'"
|
|
||||||
:style="{
|
|
||||||
width: inputWidth + 'px',
|
width: inputWidth + 'px',
|
||||||
height: height + 'px',
|
height: height + 'px',
|
||||||
lineHeight: height + 'px'
|
lineHeight: height + 'px'
|
||||||
}"
|
}" @input="handleInputChange" />
|
||||||
@input="handleInputChange"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 单位标签 -->
|
<!-- 单位标签 -->
|
||||||
<view
|
<view v-if="enableConvert" :ref="'unitLabel'" class="unit-label" :style="{
|
||||||
v-if="enableConvert"
|
|
||||||
:ref="'unitLabel'"
|
|
||||||
class="unit-label"
|
|
||||||
:style="{
|
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
height: height + 'px',
|
height: height + 'px',
|
||||||
lineHeight: height + 'px'
|
lineHeight: height + 'px'
|
||||||
}"
|
}" @tap="cycleUnit" @longpress="handleLongPress">
|
||||||
@tap="cycleUnit"
|
|
||||||
@longpress="handleLongPress"
|
|
||||||
>
|
|
||||||
{{ textUnitName }}
|
{{ textUnitName }}
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view v-else class="unit-label" :style="{
|
||||||
v-else
|
|
||||||
class="unit-label"
|
|
||||||
:style="{
|
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
height: height + 'px',
|
height: height + 'px',
|
||||||
lineHeight: height + 'px'
|
lineHeight: height + 'px'
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
{{ textUnitName }}
|
{{ textUnitName }}
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 单位选择弹出窗口 -->
|
<!-- 单位选择弹出窗口 -->
|
||||||
<view
|
<view v-if="showUnitSelector" class="unit-selector" :style="{
|
||||||
v-if="showUnitSelector"
|
|
||||||
class="unit-selector"
|
|
||||||
:style="{
|
|
||||||
left: unitSelectorLeft + 'px',
|
left: unitSelectorLeft + 'px',
|
||||||
top: unitSelectorTop + 'px'
|
top: unitSelectorTop + 'px'
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
<scroll-view scroll-y :style="{ maxHeight: '300px' }">
|
<scroll-view scroll-y :style="{ maxHeight: '300px' }">
|
||||||
<view
|
<view v-for="(unit, index) in sortedUnits" :key="unit.id" class="unit-option"
|
||||||
v-for="(unit, index) in sortedUnits"
|
:class="{ active: activeIndex === index }" @tap="selectUnitHandler(unit, index)">
|
||||||
:key="unit.id"
|
|
||||||
class="unit-option"
|
|
||||||
:class="{ active: activeIndex === index }"
|
|
||||||
@tap="selectUnitHandler(unit, index)"
|
|
||||||
>
|
|
||||||
{{ showEnglishOnly ? unit.unitName.split('(')[0] : unit.unitName }}
|
{{ showEnglishOnly ? unit.unitName.split('(')[0] : unit.unitName }}
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
@ -66,358 +39,369 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { storage } from '@/utils/storageUnit.ts';
|
import useUnitStore from '@/store/modules/unitData.ts';
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'UniUnitConverter',
|
|
||||||
emits: ['update:modelValue', 'update:unitOrder', 'conversion'],
|
export default {
|
||||||
props: {
|
name: 'UniUnitConverter',
|
||||||
unitType: {
|
emits: ['update:modelValue', 'update:unitOrder', 'conversion'],
|
||||||
type: String,
|
props: {
|
||||||
required: true,
|
unitType: {
|
||||||
default: 'length'
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: 'length'
|
||||||
|
},
|
||||||
|
unitOrder: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
showEnglishOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
decimalPlaces: {
|
||||||
|
type: Number,
|
||||||
|
default: 5,
|
||||||
|
validator: (v) => v >= 0 && v <= 10
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 180
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 32
|
||||||
|
},
|
||||||
|
enableConvert: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
userDefined: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
userDefinedunitName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
unitOrder: {
|
data() {
|
||||||
type: Number,
|
return {
|
||||||
default: 0
|
inputValue: this.modelValue,
|
||||||
|
unitData: [],
|
||||||
|
showUnitSelector: false,
|
||||||
|
currentUnit: null,
|
||||||
|
baseUnit: null,
|
||||||
|
inputWidth: 100,
|
||||||
|
textUnitName: '',
|
||||||
|
unitSelectorLeft: 0,
|
||||||
|
unitSelectorTop: 0,
|
||||||
|
originalValue: this.modelValue,
|
||||||
|
originalUnit: null,
|
||||||
|
isInternalUpdate: false,
|
||||||
|
activeIndex: -1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modelValue: {
|
computed: {
|
||||||
type: Number,
|
sortedUnits() {
|
||||||
required: true
|
return this.unitData.filter((u) => u.unitType === this.unitType).sort((a, b) => a.unitOrder - b.unitOrder);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
showEnglishOnly: {
|
watch: {
|
||||||
type: Boolean,
|
unitType: {
|
||||||
default: false
|
immediate: true,
|
||||||
},
|
async handler(newType) {
|
||||||
decimalPlaces: {
|
if (this.userDefined) {
|
||||||
type: Number,
|
this.textUnitName = this.userDefinedunitName;
|
||||||
default: 5,
|
this.$nextTick(() => this.updateInputWidth());
|
||||||
validator: (v) => v >= 0 && v <= 10
|
} else {
|
||||||
},
|
await this.loadUnits(newType);
|
||||||
width: {
|
this.initCurrentUnit();
|
||||||
type: Number,
|
}
|
||||||
default: 180
|
}
|
||||||
},
|
},
|
||||||
height: {
|
unitOrder(newOrder) {
|
||||||
type: Number,
|
|
||||||
default: 32
|
|
||||||
},
|
|
||||||
enableConvert: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
userDefined: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
userDefinedunitName: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
inputValue: this.modelValue,
|
|
||||||
unitData: [],
|
|
||||||
showUnitSelector: false,
|
|
||||||
currentUnit: null,
|
|
||||||
baseUnit: null,
|
|
||||||
inputWidth: 100,
|
|
||||||
textUnitName: '',
|
|
||||||
unitSelectorLeft: 0,
|
|
||||||
unitSelectorTop: 0,
|
|
||||||
originalValue: this.modelValue,
|
|
||||||
originalUnit: null,
|
|
||||||
isInternalUpdate: false,
|
|
||||||
activeIndex: -1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
sortedUnits() {
|
|
||||||
return this.unitData.filter((u) => u.unitType === this.unitType).sort((a, b) => a.unitOrder - b.unitOrder);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
unitType: {
|
|
||||||
immediate: true,
|
|
||||||
async handler(newType) {
|
|
||||||
if (this.userDefined) {
|
if (this.userDefined) {
|
||||||
this.textUnitName = this.userDefinedunitName;
|
this.textUnitName = this.userDefinedunitName;
|
||||||
this.$nextTick(() => this.updateInputWidth());
|
this.$nextTick(() => this.updateInputWidth());
|
||||||
} else {
|
} else {
|
||||||
await this.loadUnits(newType);
|
const target = this.sortedUnits.find((u) => u.unitOrder === newOrder);
|
||||||
this.initCurrentUnit();
|
if (target) {
|
||||||
|
this.currentUnit = target;
|
||||||
|
this.textUnitName = this.showEnglishOnly ? target.unitName.split('(')[0].trim() : target.unitName;
|
||||||
|
this.$nextTick(() => this.updateInputWidth());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
modelValue(newVal) {
|
||||||
|
if (!this.isInternalUpdate) {
|
||||||
|
this.originalValue = newVal;
|
||||||
|
this.originalUnit = this.currentUnit;
|
||||||
|
this.inputValue = newVal;
|
||||||
|
}
|
||||||
|
this.isInternalUpdate = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unitOrder(newOrder) {
|
mounted() {
|
||||||
if (this.userDefined) {
|
this.initComponent();
|
||||||
this.textUnitName = this.userDefinedunitName;
|
|
||||||
this.$nextTick(() => this.updateInputWidth());
|
|
||||||
} else {
|
|
||||||
const target = this.sortedUnits.find((u) => u.unitOrder === newOrder);
|
|
||||||
if (target) {
|
|
||||||
this.currentUnit = target;
|
|
||||||
this.textUnitName = this.showEnglishOnly ? target.unitName.split('(')[0].trim() : target.unitName;
|
|
||||||
this.$nextTick(() => this.updateInputWidth());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
modelValue(newVal) {
|
methods: {
|
||||||
if (!this.isInternalUpdate) {
|
async initComponent() {
|
||||||
this.originalValue = newVal;
|
await this.$nextTick();
|
||||||
|
this.updateInputWidth();
|
||||||
|
},
|
||||||
|
|
||||||
|
setActiveIndex(index) {
|
||||||
|
this.activeIndex = index;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 统一处理单位选择
|
||||||
|
selectUnitHandler(unit, index) {
|
||||||
|
this.selectUnit(unit);
|
||||||
|
this.setActiveIndex(index);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClickOutside() {
|
||||||
|
if (this.showUnitSelector) {
|
||||||
|
this.showUnitSelector = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadUnits(unitType) {
|
||||||
|
try {
|
||||||
|
let tempData = null;
|
||||||
|
|
||||||
|
let unitStore = useUnitStore();
|
||||||
|
|
||||||
|
tempData = unitStore.loadFromStorage();
|
||||||
|
|
||||||
|
console.log('从存储获取的数据:', tempData);
|
||||||
|
// 2. 缓存无数据时,调用接口获取
|
||||||
|
if (!tempData || !tempData[unitType]) {
|
||||||
|
console.log('缓存无对应类型数据,从接口获取');
|
||||||
|
await unitStore.safeGetList();
|
||||||
|
tempData = unitStore.groupedUnitData;
|
||||||
|
}
|
||||||
|
// 3. 赋值处理
|
||||||
|
this.unitData = tempData[unitType] || [];
|
||||||
|
|
||||||
|
if (this.unitData.length === 0) {
|
||||||
|
console.warn(`未找到${unitType}类型的单位数据`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.originalUnit = this.currentUnit;
|
||||||
this.inputValue = newVal;
|
this.textUnitName = this.showEnglishOnly ?
|
||||||
}
|
this.currentUnit.unitName.split('(')[0].trim() :
|
||||||
this.isInternalUpdate = false;
|
this.currentUnit.unitName;
|
||||||
}
|
this.$nextTick(() => this.updateInputWidth());
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.initComponent();
|
updateInputWidth() {
|
||||||
},
|
const query = uni.createSelectorQuery().in(this);
|
||||||
methods: {
|
query.select('.unit-label').boundingClientRect(res => {
|
||||||
async initComponent() {
|
if (res) {
|
||||||
await this.$nextTick();
|
this.inputWidth = this.width - res.width - 4;
|
||||||
this.updateInputWidth();
|
}
|
||||||
},
|
}).exec();
|
||||||
|
},
|
||||||
setActiveIndex(index) {
|
|
||||||
this.activeIndex = index;
|
handleLongPress() {
|
||||||
},
|
this.toggleUnitSelector();
|
||||||
|
|
||||||
// 统一处理单位选择
|
|
||||||
selectUnitHandler(unit, index) {
|
|
||||||
this.selectUnit(unit);
|
|
||||||
this.setActiveIndex(index);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleClickOutside() {
|
|
||||||
if (this.showUnitSelector) {
|
|
||||||
this.showUnitSelector = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async loadUnits(unitType) {
|
|
||||||
try {
|
|
||||||
let tempData = null;
|
|
||||||
|
|
||||||
tempData = storage.getItem('unitData');
|
|
||||||
console.log('从存储获取的数据:', tempData);
|
|
||||||
if (!tempData || !tempData[unitType]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.unitData = tempData[unitType];
|
|
||||||
|
|
||||||
if (!this.unitData || this.unitData.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.baseUnit = this.unitData.find((u) => u.baseUnit === 'Y');
|
|
||||||
|
|
||||||
} 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.$nextTick(() => this.updateInputWidth());
|
|
||||||
},
|
|
||||||
|
|
||||||
updateInputWidth() {
|
|
||||||
const query = uni.createSelectorQuery().in(this);
|
|
||||||
query.select('.unit-label').boundingClientRect(res => {
|
|
||||||
if (res) {
|
|
||||||
this.inputWidth = this.width - res.width - 4;
|
|
||||||
}
|
|
||||||
}).exec();
|
|
||||||
},
|
|
||||||
|
|
||||||
handleLongPress() {
|
|
||||||
this.toggleUnitSelector();
|
|
||||||
this.positionUnitSelector();
|
|
||||||
},
|
|
||||||
|
|
||||||
positionUnitSelector() {
|
|
||||||
const query = uni.createSelectorQuery().in(this);
|
|
||||||
query.select('.unit-label').boundingClientRect(res => {
|
|
||||||
if (res) {
|
|
||||||
this.unitSelectorLeft = res.left;
|
|
||||||
this.unitSelectorTop = res.bottom + 5;
|
|
||||||
}
|
|
||||||
}).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.$nextTick(() => {
|
|
||||||
this.updateInputWidth();
|
|
||||||
this.convertAndEmit();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleUnitSelector() {
|
|
||||||
this.showUnitSelector = !this.showUnitSelector;
|
|
||||||
if (this.showUnitSelector) {
|
|
||||||
this.positionUnitSelector();
|
this.positionUnitSelector();
|
||||||
}
|
},
|
||||||
},
|
|
||||||
|
positionUnitSelector() {
|
||||||
selectUnit(unit) {
|
const query = uni.createSelectorQuery().in(this);
|
||||||
this.currentUnit = unit;
|
query.select('.unit-label').boundingClientRect(res => {
|
||||||
this.showUnitSelector = false;
|
if (res) {
|
||||||
this.$nextTick(() => {
|
this.unitSelectorLeft = res.left;
|
||||||
this.updateInputWidth();
|
this.unitSelectorTop = res.bottom + 5;
|
||||||
this.convertAndEmit();
|
}
|
||||||
});
|
}).exec();
|
||||||
this.activeIndex = -1;
|
},
|
||||||
},
|
|
||||||
|
cycleUnit() {
|
||||||
handleInputChange() {
|
const index = this.sortedUnits.findIndex((u) => u === this.currentUnit);
|
||||||
this.originalValue = this.inputValue;
|
const newUnit = this.sortedUnits[(index + 1) % this.sortedUnits.length];
|
||||||
this.originalUnit = this.currentUnit;
|
this.currentUnit = newUnit;
|
||||||
this.$emit('update:modelValue', this.inputValue);
|
this.textUnitName = this.showEnglishOnly ?
|
||||||
},
|
newUnit.unitName.split('(')[0].trim() :
|
||||||
|
newUnit.unitName;
|
||||||
convertAndEmit() {
|
|
||||||
if (!this.currentUnit || !this.baseUnit || !this.originalUnit) return;
|
this.$nextTick(() => {
|
||||||
|
this.updateInputWidth();
|
||||||
let newValue = 0;
|
this.convertAndEmit();
|
||||||
if (this.unitType === 'temperature') {
|
});
|
||||||
newValue = this.handleTemperatureConversion();
|
},
|
||||||
} else {
|
|
||||||
const baseValue = this.originalValue / this.originalUnit.conversionFactor;
|
toggleUnitSelector() {
|
||||||
newValue = baseValue * this.currentUnit.conversionFactor;
|
this.showUnitSelector = !this.showUnitSelector;
|
||||||
}
|
if (this.showUnitSelector) {
|
||||||
|
this.positionUnitSelector();
|
||||||
const roundedValue = this.roundValue(newValue);
|
}
|
||||||
this.isInternalUpdate = true;
|
},
|
||||||
this.inputValue = roundedValue;
|
|
||||||
this.$emit('update:modelValue', roundedValue);
|
selectUnit(unit) {
|
||||||
this.$emit('update:unitOrder', this.currentUnit.unitOrder);
|
this.currentUnit = unit;
|
||||||
|
this.showUnitSelector = false;
|
||||||
this.$emit('conversion', {
|
this.$nextTick(() => {
|
||||||
initialValue: this.originalValue,
|
this.updateInputWidth();
|
||||||
newValue: roundedValue,
|
this.convertAndEmit();
|
||||||
oldUnit: this.originalUnit.unitName,
|
});
|
||||||
newUnit: this.currentUnit.unitName,
|
this.activeIndex = -1;
|
||||||
oldOrder: this.originalUnit.unitOrder,
|
},
|
||||||
newOrder: this.currentUnit.unitOrder
|
|
||||||
});
|
handleInputChange() {
|
||||||
},
|
this.originalValue = this.inputValue;
|
||||||
|
this.originalUnit = this.currentUnit;
|
||||||
handleTemperatureConversion() {
|
this.$emit('update:modelValue', this.inputValue);
|
||||||
const oldUnit = this.originalUnit;
|
},
|
||||||
const newUnit = this.currentUnit;
|
|
||||||
const oldOrder = oldUnit.unitOrder;
|
convertAndEmit() {
|
||||||
const newOrder = newUnit.unitOrder;
|
if (!this.currentUnit || !this.baseUnit || !this.originalUnit) return;
|
||||||
|
|
||||||
let celsius;
|
let newValue = 0;
|
||||||
switch (oldOrder) {
|
if (this.unitType === 'temperature') {
|
||||||
case 0:
|
newValue = this.handleTemperatureConversion();
|
||||||
celsius = this.originalValue;
|
} else {
|
||||||
break;
|
const baseValue = this.originalValue / this.originalUnit.conversionFactor;
|
||||||
case 1:
|
newValue = baseValue * this.currentUnit.conversionFactor;
|
||||||
celsius = ((this.originalValue - 32) * 5) / 9;
|
}
|
||||||
break;
|
|
||||||
case 2:
|
const roundedValue = this.roundValue(newValue);
|
||||||
celsius = this.originalValue - 273.15;
|
this.isInternalUpdate = true;
|
||||||
break;
|
this.inputValue = roundedValue;
|
||||||
default:
|
this.$emit('update:modelValue', roundedValue);
|
||||||
throw new Error('无效温度单位');
|
this.$emit('update:unitOrder', this.currentUnit.unitOrder);
|
||||||
}
|
|
||||||
|
this.$emit('conversion', {
|
||||||
switch (newOrder) {
|
initialValue: this.originalValue,
|
||||||
case 0:
|
newValue: roundedValue,
|
||||||
return celsius;
|
oldUnit: this.originalUnit.unitName,
|
||||||
case 1:
|
newUnit: this.currentUnit.unitName,
|
||||||
return (celsius * 9) / 5 + 32;
|
oldOrder: this.originalUnit.unitOrder,
|
||||||
case 2:
|
newOrder: this.currentUnit.unitOrder
|
||||||
return celsius + 273.15;
|
});
|
||||||
default:
|
},
|
||||||
throw new Error('无效温度单位');
|
|
||||||
}
|
handleTemperatureConversion() {
|
||||||
},
|
const oldUnit = this.originalUnit;
|
||||||
|
const newUnit = this.currentUnit;
|
||||||
roundValue(value) {
|
const oldOrder = oldUnit.unitOrder;
|
||||||
const multiplier = Math.pow(10, this.decimalPlaces);
|
const newOrder = newUnit.unitOrder;
|
||||||
const val = value * multiplier;
|
|
||||||
const intVal = Math.trunc(val);
|
let celsius;
|
||||||
const decimalPart = val - intVal;
|
switch (oldOrder) {
|
||||||
if (decimalPart < 0.5) {
|
case 0:
|
||||||
return intVal / multiplier;
|
celsius = this.originalValue;
|
||||||
} else if (decimalPart > 0.5) {
|
break;
|
||||||
return (intVal + 1) / multiplier;
|
case 1:
|
||||||
} else {
|
celsius = ((this.originalValue - 32) * 5) / 9;
|
||||||
return intVal % 2 === 0 ? intVal / multiplier : (intVal + 1) / multiplier;
|
break;
|
||||||
|
case 2:
|
||||||
|
celsius = this.originalValue - 273.15;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('无效温度单位');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (newOrder) {
|
||||||
|
case 0:
|
||||||
|
return celsius;
|
||||||
|
case 1:
|
||||||
|
return (celsius * 9) / 5 + 32;
|
||||||
|
case 2:
|
||||||
|
return celsius + 273.15;
|
||||||
|
default:
|
||||||
|
throw new Error('无效温度单位');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
roundValue(value) {
|
||||||
|
const multiplier = Math.pow(10, this.decimalPlaces);
|
||||||
|
const val = value * multiplier;
|
||||||
|
const intVal = Math.trunc(val);
|
||||||
|
const decimalPart = val - intVal;
|
||||||
|
if (decimalPart < 0.5) {
|
||||||
|
return intVal / multiplier;
|
||||||
|
} else if (decimalPart > 0.5) {
|
||||||
|
return (intVal + 1) / multiplier;
|
||||||
|
} else {
|
||||||
|
return intVal % 2 === 0 ? intVal / multiplier : (intVal + 1) / multiplier;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.a-yjly-inputunit {
|
.a-yjly-inputunit {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.input-field {
|
||||||
border: 1px solid #d6d5d5;
|
border: 1px solid #d6d5d5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit-label {
|
.unit-label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
border: 1px solid #d6d5d5;
|
border: 1px solid #d6d5d5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit-selector {
|
.unit-selector {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border: 1px solid #cccccc;
|
border: 1px solid #cccccc;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit-option {
|
.unit-option {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit-option.active {
|
.unit-option.active {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit-option:active {
|
.unit-option:active {
|
||||||
background-color: #e0e0e0;
|
background-color: #e0e0e0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -1,13 +1,78 @@
|
|||||||
const TokenKey = 'App-Token'
|
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,103 +8,101 @@ import useUserStore from '@/store/modules/user'
|
|||||||
let timeout = 10000
|
let timeout = 10000
|
||||||
const baseUrl = config.baseUrl
|
const baseUrl = config.baseUrl
|
||||||
|
|
||||||
const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
const request = <T>(config : RequestConfig) : Promise<ResponseData<T>> => {
|
||||||
// 是否需要设置 token
|
// 是否需要设置 token
|
||||||
const isToken = (config.headers || {}).isToken === false
|
const isToken = (config.headers || {}).isToken === false
|
||||||
config.header = config.header || {}
|
config.header = config.header || {}
|
||||||
if (getToken() && !isToken) {
|
if (getToken() && !isToken) {
|
||||||
config.header['Authorization'] = 'Bearer ' + getToken()
|
config.header['Authorization'] = 'Bearer ' + getToken()
|
||||||
}
|
}
|
||||||
// get请求映射params参数
|
// get请求映射params参数
|
||||||
if (config.params) {
|
if (config.params) {
|
||||||
let url = config.url + '?' + tansParams(config.params)
|
let url = config.url + '?' + tansParams(config.params)
|
||||||
url = url.slice(0, -1)
|
url = url.slice(0, -1)
|
||||||
config.url = url
|
config.url = url
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
uni.request({
|
uni.request({
|
||||||
method: config.method || 'GET',
|
method: config.method || 'GET',
|
||||||
timeout: config.timeout || timeout,
|
timeout: config.timeout || timeout,
|
||||||
url: (config.baseUrl || baseUrl) + config.url,
|
url: (config.baseUrl || baseUrl) + config.url,
|
||||||
data: config.data,
|
data: config.data,
|
||||||
header: config.header,
|
header: config.header,
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
/* let [error, res] = response
|
/* let [error, res] = response
|
||||||
if (error) {
|
if (error) {
|
||||||
toast('后端接口连接异常')
|
toast('后端接口连接异常')
|
||||||
reject('后端接口连接异常')
|
reject('后端接口连接异常')
|
||||||
return
|
return
|
||||||
} */
|
} */
|
||||||
const res = response
|
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
|
const code = data.code || 200
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const msg: string = errorCode[code] || data.msg || errorCode['default']
|
const msg : string = errorCode[code] || data.msg || errorCode['default']
|
||||||
if (code === 401) {
|
if (code === 401) {
|
||||||
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
|
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
useUserStore().logOut().then(res => {
|
useUserStore().logOut().then(res => {
|
||||||
uni.reLaunch({ url: '/pages/login' })
|
uni.reLaunch({ url: '/pages/login' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
reject('无效的会话,或者会话已过期,请重新登录。')
|
reject('无效的会话,或者会话已过期,请重新登录。')
|
||||||
} else if (code === 500) {
|
} else if (code === 500) {
|
||||||
toast(msg)
|
toast(msg)
|
||||||
reject('500')
|
reject('500')
|
||||||
} else if (code !== 200) {
|
} else if (code !== 200) {
|
||||||
toast(msg)
|
toast(msg)
|
||||||
reject(code)
|
reject(code)
|
||||||
}
|
}
|
||||||
resolve(data)
|
resolve(data)
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// === 修复这里的问题 ===
|
// === 修复这里的问题 ===
|
||||||
let message = '网络请求失败'
|
let message = '网络请求失败'
|
||||||
|
|
||||||
// 安全地获取错误信息
|
|
||||||
if (error) {
|
// === 重点修复:安全提取错误信息 ===
|
||||||
// 小程序环境错误对象可能有不同的结构
|
if (error && typeof error === 'object') {
|
||||||
if (error.errMsg) {
|
// 优先使用后端返回的错误消息
|
||||||
message = error.errMsg
|
if (error.data?.msg) message = error.data.msg;
|
||||||
} else if (error.message) {
|
// 小程序特有的错误结构
|
||||||
message = error.message
|
else if (error.errMsg) message = error.errMsg;
|
||||||
} else if (typeof error === 'string') {
|
// 常规错误消息
|
||||||
message = error
|
else if (error.message) message = error.message;
|
||||||
}
|
} else if (typeof error === 'string') {
|
||||||
}
|
message = error;
|
||||||
|
}
|
||||||
// 安全地使用 includes 方法 - 添加类型检查
|
|
||||||
if (message && typeof message === 'string') {
|
// 特殊错误处理
|
||||||
if (message.includes('Network Error')) {
|
if (message.includes('Network Error')) {
|
||||||
message = '后端接口连接异常'
|
message = '网络连接异常';
|
||||||
} else if (message.includes('timeout')) {
|
} else if (message.includes('timeout')) {
|
||||||
message = '系统接口请求超时'
|
message = '请求超时,请检查网络';
|
||||||
} else if (message.includes('Request failed with status code')) {
|
}
|
||||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
|
||||||
}
|
toast(message);
|
||||||
} else {
|
|
||||||
// 如果 message 不是字符串,转换为字符串
|
// === 关键:返回带code的错误对象 ===
|
||||||
message = String(message || '未知错误')
|
const err = new Error(message);
|
||||||
}
|
err.code = error.statusCode || 500; // 保留HTTP状态码
|
||||||
toast(message)
|
reject(err);
|
||||||
reject(error)
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
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) {
|
||||||
|
return request({ params, url, method: 'GET', headers: { isToken }, })
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
return request({ data, url, method: 'DELETE', headers: { isToken }, })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postAction(url: string, data?: any, isToken: boolean = true) {
|
export default request
|
||||||
return request({ data, url, method: 'POST', headers: { isToken }, })
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
return request({ data, url, method: 'PUT', headers: { isToken }, })
|
|
||||||
}
|
|
||||||
export function deleteAction(url: string, data?: any, isToken: boolean = true) {
|
|
||||||
return request({ data, url, method: 'DELETE', headers: { isToken }, })
|
|
||||||
}
|
|
||||||
|
|
||||||
export default request
|
|
||||||
@ -25,4 +25,23 @@ export default defineConfig(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
configureWebpack: {
|
||||||
|
optimization: {
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'async', // 仅异步代码抽离
|
||||||
|
minSize: 20000, // 大于20KB才抽离
|
||||||
|
cacheGroups: {
|
||||||
|
commons: {
|
||||||
|
name: 'commons',
|
||||||
|
chunks: 'initial',
|
||||||
|
minChunks: 2, // 被引用2次以上抽离
|
||||||
|
priority: -10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user