修改单位加载,加小程序兼容,未成功
@ -4,6 +4,9 @@ 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
|
||||||
})
|
})
|
||||||
@ -13,6 +16,9 @@ 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'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -21,6 +27,9 @@ 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
|
||||||
})
|
})
|
||||||
@ -30,6 +39,9 @@ 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
|
||||||
})
|
})
|
||||||
@ -39,6 +51,9 @@ 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'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const config = {
|
|||||||
// 应用版本
|
// 应用版本
|
||||||
version: "1.1.0",
|
version: "1.1.0",
|
||||||
// 应用logo
|
// 应用logo
|
||||||
logo: "/static/logo.png",
|
logo: "https://ngtools.cn:3000/static/logo.png",
|
||||||
// 官方网站
|
// 官方网站
|
||||||
site_url: "http://ruoyi.vip",
|
site_url: "http://ruoyi.vip",
|
||||||
// 政策协议
|
// 政策协议
|
||||||
|
|||||||
@ -284,20 +284,20 @@
|
|||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"pagePath": "pages/index",
|
"pagePath": "pages/index",
|
||||||
"iconPath": "static/images/tabbar/work.png",
|
"iconPath": "/static/images/tabbar/work.png",
|
||||||
"selectedIconPath": "static/images/tabbar/work_.png",
|
"selectedIconPath": "/static/images/tabbar/work_.png",
|
||||||
"text": "首页"
|
"text": "首页"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/template",
|
"pagePath": "pages/template",
|
||||||
"iconPath": "static/images/tabbar/work.png",
|
"iconPath": "/static/images/tabbar/work.png",
|
||||||
"selectedIconPath": "static/images/tabbar/work_.png",
|
"selectedIconPath": "/static/images/tabbar/work_.png",
|
||||||
"text": "资料"
|
"text": "资料"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mine",
|
"pagePath": "pages/mine",
|
||||||
"iconPath": "static/images/tabbar/mine.png",
|
"iconPath": "/static/images/tabbar/mine.png",
|
||||||
"selectedIconPath": "static/images/tabbar/mine_.png",
|
"selectedIconPath": "/static/images/tabbar/mine_.png",
|
||||||
"text": "我的"
|
"text": "我的"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -33,97 +33,38 @@
|
|||||||
ref,
|
ref,
|
||||||
onMounted
|
onMounted
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import modal from "@/plugins/modal"
|
import modal from "@/plugins/modal"
|
||||||
import {
|
|
||||||
listConvert
|
|
||||||
} from '@/api/system/unitConverter/sysUnitConverter.js';
|
|
||||||
import {
|
import {
|
||||||
storage
|
storage
|
||||||
} from '@/utils/storageUnit.ts';
|
} from '@/utils/storageUnit.ts';
|
||||||
import {
|
import {
|
||||||
extractModuleData
|
extractModuleData
|
||||||
} from '@/utils/moudlesData.ts';
|
} from '@/utils/moudlesData.ts';
|
||||||
|
import useUnitStore from '@/store/modules/unitData.ts';
|
||||||
|
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([{
|
||||||
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 moudlesGroups = ref([]);
|
||||||
const queryParams = ref({
|
|
||||||
pageNum: 1,
|
onMounted(async() => {
|
||||||
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 {};
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}, {});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getList = () => {
|
|
||||||
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('数据存储成功');
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取单位数据失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
onMounted(() => {
|
|
||||||
moudlesGroups.value = extractModuleData(['流量计算', '参数计算'], false)
|
moudlesGroups.value = extractModuleData(['流量计算', '参数计算'], false)
|
||||||
getList();
|
// 优先从本地缓存恢复,再请求最新数据
|
||||||
|
unitStore.restoreUnitDataFromLocal();
|
||||||
|
await unitStore.getList();
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function navigateToMoudles(item) {
|
function navigateToMoudles(item) {
|
||||||
|
|||||||
@ -67,28 +67,28 @@ function getcolor(color: { hex: string, rgba: { r: number, g: number, b: number,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const menus: Array<Menu> = reactive([
|
const menus: Array<Menu> = reactive([
|
||||||
{ icon: "/static/images/icon/rocket.png", label: '抢单' },
|
{ icon: "https://ngtools.cn:3000/static/images/icon/rocket.png", label: '抢单' },
|
||||||
{ icon: "/static/images/icon/phone.png", label: '回访' },
|
{ icon: "https://ngtools.cn:3000/static/images/icon/phone.png", label: '回访' },
|
||||||
{ icon: "/static/images/icon/message.png", label: '消息' },
|
{ icon: "https://ngtools.cn:3000/static/images/icon/message.png", label: '消息' },
|
||||||
{ icon: "/static/images/icon/dialogue.png", label: '公告' },
|
{ icon: "https://ngtools.cn:3000/static/images/icon/dialogue.png", label: '公告' },
|
||||||
{ icon: "/static/images/icon/knowledge.png", label: '知识库' }
|
{ icon: "https://ngtools.cn:3000/static/images/icon/knowledge.png", label: '知识库' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const commodityList: Array<Commodity> = reactive([
|
const commodityList: Array<Commodity> = reactive([
|
||||||
{
|
{
|
||||||
img: '/static/images/banner/banner01.jpg',
|
img: 'https://ngtools.cn:3000/static/images/banner/banner01.jpg',
|
||||||
title: '商品1',
|
title: '商品1',
|
||||||
subTitle: '商品1简介',
|
subTitle: '商品1简介',
|
||||||
price: 100,
|
price: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
img: '/static/images/banner/banner02.jpg',
|
img: 'https://ngtools.cn:3000/static/images/banner/banner02.jpg',
|
||||||
title: '商品2',
|
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简介',
|
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,
|
price: 300,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
img: '/static/images/banner/banner03.jpg',
|
img: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg',
|
||||||
title: '商品3',
|
title: '商品3',
|
||||||
subTitle: '商品3简介',
|
subTitle: '商品3简介',
|
||||||
price: 200,
|
price: 200,
|
||||||
@ -99,7 +99,7 @@ const orderList: Array<CommodityOrder> = [
|
|||||||
{
|
{
|
||||||
shop: 'geek自营旗舰店',
|
shop: 'geek自营旗舰店',
|
||||||
status: '完成',
|
status: '完成',
|
||||||
img: '/static/images/banner/banner01.jpg',
|
img: 'https://ngtools.cn:3000/static/images/banner/banner01.jpg',
|
||||||
title: '商品1',
|
title: '商品1',
|
||||||
label: '商品1简介',
|
label: '商品1简介',
|
||||||
price: 100.32,
|
price: 100.32,
|
||||||
@ -108,7 +108,7 @@ const orderList: Array<CommodityOrder> = [
|
|||||||
{
|
{
|
||||||
shop: 'geek自营旗舰店',
|
shop: 'geek自营旗舰店',
|
||||||
status: '已取消',
|
status: '已取消',
|
||||||
img: '/static/images/banner/banner03.jpg',
|
img: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg',
|
||||||
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
|
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
|
||||||
label: '商品3简介',
|
label: '商品3简介',
|
||||||
price: 2000.67,
|
price: 2000.67,
|
||||||
@ -117,7 +117,7 @@ const orderList: Array<CommodityOrder> = [
|
|||||||
{
|
{
|
||||||
shop: 'geek自营旗舰店',
|
shop: 'geek自营旗舰店',
|
||||||
status: '已取消',
|
status: '已取消',
|
||||||
img: '/static/images/banner/banner03.jpg',
|
img: 'https://ngtools.cn:3000/static/images/banner/banner03.jpg',
|
||||||
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
|
title: '商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商商品3',
|
||||||
label: '商品3简介',
|
label: '商品3简介',
|
||||||
price: 10.67,
|
price: 10.67,
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="about-container">
|
<view class="about-container">
|
||||||
<view class="header-section text-center">
|
<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>
|
</image>
|
||||||
<uni-title type="h2" title="若依移动端"></uni-title>
|
<uni-title type="h2" title="天然气工具箱"></uni-title>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content-section">
|
<view class="content-section">
|
||||||
|
|||||||
@ -38,9 +38,9 @@
|
|||||||
margin: "150rpx",
|
margin: "150rpx",
|
||||||
index: 0,
|
index: 0,
|
||||||
list: [
|
list: [
|
||||||
"/static/images/douyin/0.jpg",
|
"https://ngtools.cn:3000/static/images/douyin/0.jpg",
|
||||||
"/static/images/douyin/4.jpg",
|
"https://ngtools.cn:3000/static/images/douyin/4.jpg",
|
||||||
"/static/images/douyin/7.jpg",
|
"https://ngtools.cn:3000/static/images/douyin/7.jpg",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,7 +96,7 @@ const getComment = () => {
|
|||||||
likeNum: 21,
|
likeNum: 21,
|
||||||
isLike: false,
|
isLike: false,
|
||||||
allReply: 2,
|
allReply: 2,
|
||||||
url: '../../../static/logo.png',
|
url: 'https://ngtools.cn:3000/static/logo.png',
|
||||||
replyList: [
|
replyList: [
|
||||||
{
|
{
|
||||||
name: 'uview',
|
name: 'uview',
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import logo from '@/static/logo.png';
|
import logo from 'https://ngtools.cn:3000/static/logo.png';
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<view class="taobao">
|
<view class="taobao">
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<view>
|
<view>
|
||||||
<view class="normal-login-container " v-if="page == 'login'">
|
<view class="normal-login-container " v-if="page == 'login'">
|
||||||
<view class="left" @click="back">
|
<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>
|
||||||
<view class="scale-in-center">
|
<view class="scale-in-center">
|
||||||
<view class="logo-content align-center justify-center flex">
|
<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 |
373
src/store/modules/unitData.ts
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 处理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() {
|
||||||
|
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.handleApiError(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 }
|
||||||
|
}
|
||||||
|
return { rows: [], total: 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 从存储加载缓存的单位数据 - 兼容多平台
|
||||||
|
loadFromStorage() {
|
||||||
|
try {
|
||||||
|
let storedData = null
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-LARK || MP-KUAISHOU
|
||||||
|
// 微信小程序等平台使用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 {
|
||||||
|
storedData = uni.getStorageSync('unitData')
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('鸿蒙平台存储获取失败:', e)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
if (storedData) {
|
||||||
|
this.groupedUnitData = JSON.parse(storedData)
|
||||||
|
// 从分组数据中提取所有单位
|
||||||
|
this.unitData = Object.values(this.groupedUnitData).flat()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('从存储加载单位数据失败:', error)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
// 保存单位数据到存储 - 兼容多平台
|
||||||
|
saveUnitDataToStorage() {
|
||||||
|
try {
|
||||||
|
const dataStr = JSON.stringify(this.groupedUnitData)
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-LARK || MP-KUAISHOU
|
||||||
|
// 微信小程序等平台使用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 {
|
||||||
|
uni.setStorageSync('unitData', dataStr)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('鸿蒙平台存储保存失败:', e)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存单位数据到存储失败:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 清除存储中的单位数据 - 兼容多平台
|
||||||
|
clearStorage() {
|
||||||
|
try {
|
||||||
|
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-LARK || MP-KUAISHOU
|
||||||
|
// 微信小程序等平台使用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 {
|
||||||
|
uni.removeStorageSync('unitData')
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('鸿蒙平台存储清除失败:', e)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
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 { login, logout, getInfo } from "@/api/login";
|
||||||
import { getToken, setToken, removeToken } from "@/utils/auth";
|
import { getToken, setToken, removeToken } from "@/utils/auth";
|
||||||
import defAva from "@/static/images/profile.jpg";
|
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export interface LoginForm {
|
export interface LoginForm {
|
||||||
@ -43,10 +42,7 @@ const useUserStore = defineStore("user", {
|
|||||||
getInfo()
|
getInfo()
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const user = res.user;
|
const user = res.user;
|
||||||
const avatar =
|
const avatar =user.avatar;
|
||||||
user.avatar == "" || user.avatar == null
|
|
||||||
? defAva
|
|
||||||
: user.avatar;
|
|
||||||
|
|
||||||
if (res.roles && res.roles.length > 0) {
|
if (res.roles && res.roles.length > 0) {
|
||||||
// 验证返回的roles是否是一个非空数组
|
// 验证返回的roles是否是一个非空数组
|
||||||
|
|||||||
@ -1,38 +1,63 @@
|
|||||||
<template>
|
<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="{
|
<input
|
||||||
|
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 v-if="enableConvert" :ref="'unitLabel'" class="unit-label" :style="{
|
<view
|
||||||
|
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 v-else class="unit-label" :style="{
|
<view
|
||||||
|
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 v-if="showUnitSelector" class="unit-selector" :style="{
|
<view
|
||||||
|
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 v-for="(unit, index) in sortedUnits" :key="unit.id" class="unit-option"
|
<view
|
||||||
:class="{ active: activeIndex === index }" <!-- 动态绑定active类 -->
|
v-for="(unit, index) in sortedUnits"
|
||||||
@tap="() => { selectUnit(unit); setActiveIndex(index); }" <!-- 点击时设置active -->
|
: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>
|
||||||
@ -41,399 +66,358 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { storage } from '@/utils/storageUnit.ts';
|
||||||
storage
|
|
||||||
} from '@/utils/storageUnit.ts';
|
|
||||||
import {
|
|
||||||
ref
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UniUnitConverter',
|
name: 'UniUnitConverter',
|
||||||
emits: ['update:modelValue', 'update:unitOrder', 'conversion'],
|
emits: ['update:modelValue', 'update:unitOrder', 'conversion'],
|
||||||
props: {
|
props: {
|
||||||
unitType: {
|
unitType: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
default: 'length'
|
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: ''
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
data() {
|
unitOrder: {
|
||||||
return {
|
type: Number,
|
||||||
inputValue: this.modelValue,
|
default: 0
|
||||||
unitData: [],
|
|
||||||
showUnitSelector: false,
|
|
||||||
currentUnit: null,
|
|
||||||
baseUnit: null,
|
|
||||||
inputWidth: 100,
|
|
||||||
textUnitName: '',
|
|
||||||
unitSelectorLeft: 0,
|
|
||||||
unitSelectorTop: 0,
|
|
||||||
|
|
||||||
// unitDatalist: [],
|
|
||||||
|
|
||||||
/* 新增三个数据项 */
|
|
||||||
originalValue: this.modelValue, // 原始输入值
|
|
||||||
originalUnit: null, // 原始输入单位
|
|
||||||
isInternalUpdate: false, // 更新锁定标志
|
|
||||||
|
|
||||||
// 新增:管理当前选中的索引
|
|
||||||
activeIndex: -1
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.initComponent();
|
|
||||||
this.setGlobalClickHandler();
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
showEnglishOnly: {
|
||||||
this.removeGlobalClickHandler();
|
type: Boolean,
|
||||||
unitOrder;
|
default: false
|
||||||
},
|
},
|
||||||
computed: {
|
decimalPlaces: {
|
||||||
sortedUnits() {
|
type: Number,
|
||||||
return this.unitData.filter((u) => u.unitType === this.unitType).sort((a, b) => a.unitOrder - b.unitOrder);
|
default: 5,
|
||||||
}
|
validator: (v) => v >= 0 && v <= 10
|
||||||
},
|
},
|
||||||
watch: {
|
width: {
|
||||||
unitType: {
|
type: Number,
|
||||||
immediate: true,
|
default: 180
|
||||||
async handler(newType) {
|
},
|
||||||
if (this.userDefined) {
|
height: {
|
||||||
this.textUnitName = this.userDefinedunitName;
|
type: Number,
|
||||||
this.$nextTick(() => this.updateInputWidth());
|
default: 32
|
||||||
} else {
|
},
|
||||||
await this.loadUnits(newType);
|
enableConvert: {
|
||||||
this.initCurrentUnit();
|
type: Boolean,
|
||||||
}
|
default: true
|
||||||
}
|
},
|
||||||
},
|
userDefined: {
|
||||||
unitOrder(newOrder) {
|
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 {
|
||||||
const target = this.sortedUnits.find((u) => u.unitOrder === newOrder);
|
await this.loadUnits(newType);
|
||||||
if (target) {
|
this.initCurrentUnit();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
unitOrder(newOrder) {
|
||||||
async initComponent() {
|
if (this.userDefined) {
|
||||||
await this.$nextTick();
|
this.textUnitName = this.userDefinedunitName;
|
||||||
this.updateInputWidth();
|
|
||||||
},
|
|
||||||
// 新增:设置active索引
|
|
||||||
setActiveIndex(index) {
|
|
||||||
activeIndex.value = index;
|
|
||||||
},
|
|
||||||
setGlobalClickHandler() {
|
|
||||||
if (typeof document !== 'undefined') {
|
|
||||||
document.addEventListener('click', this.handleClickOutside);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
removeGlobalClickHandler() {
|
|
||||||
if (typeof document !== 'undefined') {
|
|
||||||
document.removeEventListener('click', this.handleClickOutside);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleClickOutside(event) {
|
|
||||||
if (!this.showUnitSelector) return;
|
|
||||||
|
|
||||||
const selector = this.$refs.unitSelector;
|
|
||||||
if (!selector) return;
|
|
||||||
|
|
||||||
const isOutside = !selector.$el.contains(event.target);
|
|
||||||
if (isOutside) {
|
|
||||||
this.showUnitSelector = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async loadUnits(unitType) {
|
|
||||||
try {
|
|
||||||
let tempData = null;
|
|
||||||
|
|
||||||
tempData = storage.getItem('unitData');
|
|
||||||
console.log('从存储获取的数据:', tempData);
|
|
||||||
if (!tempData || !tempData[unitType]) {
|
|
||||||
// console.error(`单位类型 ${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);
|
|
||||||
|
|
||||||
} 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());
|
this.$nextTick(() => this.updateInputWidth());
|
||||||
},
|
} else {
|
||||||
|
const target = this.sortedUnits.find((u) => u.unitOrder === newOrder);
|
||||||
updateInputWidth() {
|
if (target) {
|
||||||
const query = uni.createSelectorQuery().in(this);
|
this.currentUnit = target;
|
||||||
query
|
this.textUnitName = this.showEnglishOnly ? target.unitName.split('(')[0].trim() : target.unitName;
|
||||||
.select('.unit-label')
|
this.$nextTick(() => this.updateInputWidth());
|
||||||
.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();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* 修改单位选择方法 */
|
|
||||||
selectUnit(unit) {
|
|
||||||
this.currentUnit = unit;
|
|
||||||
this.showUnitSelector = false;
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.updateInputWidth();
|
|
||||||
this.convertAndEmit();
|
|
||||||
});
|
|
||||||
activeIndex.value = -1; // 选择后重置active态(可选)
|
|
||||||
},
|
|
||||||
|
|
||||||
/* 修改输入处理 */
|
|
||||||
handleInputChange() {
|
|
||||||
// 记录原始值和单位
|
|
||||||
this.originalValue = this.inputValue;
|
|
||||||
this.originalUnit = this.currentUnit;
|
|
||||||
this.$emit('update:modelValue', this.inputValue);
|
|
||||||
},
|
|
||||||
|
|
||||||
/* 优化后的转换方法 */
|
|
||||||
convertAndEmit() {
|
|
||||||
if (!this.currentUnit || !this.baseUnit || !this.originalUnit) return;
|
|
||||||
|
|
||||||
let newValue = 0;
|
|
||||||
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.inputValue = roundedValue;
|
|
||||||
this.$emit('update:modelValue', roundedValue);
|
|
||||||
this.$emit('update:unitOrder', this.currentUnit.unitOrder);
|
|
||||||
|
|
||||||
this.$emit('conversion', {
|
|
||||||
initialValue: this.originalValue,
|
|
||||||
newValue: roundedValue,
|
|
||||||
oldUnit: this.originalUnit.unitName,
|
|
||||||
newUnit: this.currentUnit.unitName,
|
|
||||||
oldOrder: this.originalUnit.unitOrder,
|
|
||||||
newOrder: this.currentUnit.unitOrder
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/* 优化温度转换方法 */
|
|
||||||
handleTemperatureConversion() {
|
|
||||||
const oldUnit = this.originalUnit;
|
|
||||||
const newUnit = this.currentUnit;
|
|
||||||
const oldOrder = oldUnit.unitOrder;
|
|
||||||
const newOrder = newUnit.unitOrder;
|
|
||||||
|
|
||||||
// 使用原始值计算
|
|
||||||
let celsius;
|
|
||||||
switch (oldOrder) {
|
|
||||||
case 0:
|
|
||||||
celsius = this.originalValue;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
celsius = ((this.originalValue - 32) * 5) / 9;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
modelValue(newVal) {
|
||||||
|
if (!this.isInternalUpdate) {
|
||||||
|
this.originalValue = newVal;
|
||||||
|
this.originalUnit = this.currentUnit;
|
||||||
|
this.inputValue = newVal;
|
||||||
|
}
|
||||||
|
this.isInternalUpdate = false;
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initComponent();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async initComponent() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
selectUnit(unit) {
|
||||||
|
this.currentUnit = unit;
|
||||||
|
this.showUnitSelector = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.updateInputWidth();
|
||||||
|
this.convertAndEmit();
|
||||||
|
});
|
||||||
|
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;
|
||||||
|
|
||||||
|
let newValue = 0;
|
||||||
|
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.inputValue = roundedValue;
|
||||||
|
this.$emit('update:modelValue', roundedValue);
|
||||||
|
this.$emit('update:unitOrder', this.currentUnit.unitOrder);
|
||||||
|
|
||||||
|
this.$emit('conversion', {
|
||||||
|
initialValue: this.originalValue,
|
||||||
|
newValue: roundedValue,
|
||||||
|
oldUnit: this.originalUnit.unitName,
|
||||||
|
newUnit: this.currentUnit.unitName,
|
||||||
|
oldOrder: this.originalUnit.unitOrder,
|
||||||
|
newOrder: this.currentUnit.unitOrder
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleTemperatureConversion() {
|
||||||
|
const oldUnit = this.originalUnit;
|
||||||
|
const newUnit = this.currentUnit;
|
||||||
|
const oldOrder = oldUnit.unitOrder;
|
||||||
|
const newOrder = newUnit.unitOrder;
|
||||||
|
|
||||||
|
let celsius;
|
||||||
|
switch (oldOrder) {
|
||||||
|
case 0:
|
||||||
|
celsius = this.originalValue;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
celsius = ((this.originalValue - 32) * 5) / 9;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
.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;
|
||||||
|
}
|
||||||
|
|
||||||
.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;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.unit-option {
|
.unit-option {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.unit-option:active {
|
.unit-option.active {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unit-option:active {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||