refactor: update env configs, replace uni-ui and fix issues

- add VITE_CLIENT_ID environment variable to all .env files, adjust API and socket URLs across dev/staging/prod environments
- update request utility to use env var for client ID instead of hardcoded "6"
- refactor GoodDetail component: replace uni-icons with van-icon, switch markdown renderer to vue3-markdown-it
- refactor Calendar component: swap uni-popup for van-popup, remove deprecated SCSS styles, update markup and toast calls
- fix ImageSwiper: rename handler methods, update preview navigation to use vue router, remove redundant code
- correct margin class syntax in goods index page
This commit is contained in:
DEV_DSW
2026-05-28 10:18:04 +08:00
parent 4edf19ce0c
commit 9d0890b541
10 changed files with 54 additions and 152 deletions

View File

@@ -9,3 +9,6 @@ VITE_API_TIMEOUT_MS = 10000
# Socket 基础 URL
VITE_SOCKET_BASE_URL = "/ingress/agent/ws/chat"
# Client ID
VITE_CLIENT_ID = "12"

View File

@@ -8,4 +8,7 @@ VITE_API_BASE_URL = 'https://biz.nianxx.cn'
VITE_API_TIMEOUT_MS = 10000
# Socket 基础 URL
VITE_SOCKET_BASE_URL = "wss://biz.nianxx.cn/ingress/agent/ws/chat"
VITE_SOCKET_BASE_URL = "wss://biz.nianxx.cn/ingress/agent/ws/chat"
# Client ID
VITE_CLIENT_ID = "12"

View File

@@ -2,10 +2,13 @@
VITE_APP_ENV = 'staging'
# API 基础 URL
VITE_API_BASE_URL = 'https://onefeel.brother7.cn/ingress'
VITE_API_BASE_URL = 'https://abroadbiz.nianxx.com/ingress'
# API 请求超时时间(毫秒)
VITE_API_TIMEOUT_MS = 10000
# Socket 基础 URL
VITE_SOCKET_BASE_URL = "wss://onefeel.brother7.cn/ingress/agent/ws/chat"
VITE_SOCKET_BASE_URL = "wss://abroadbiz.nianxx.com/ingress/agent/ws/chat"
# Client ID
VITE_CLIENT_ID = "12"

View File

@@ -1,21 +1,22 @@
<template>
<uni-popup ref="popup" type="bottom" :safe-area="false" @maskClick="handleMaskClick">
<van-popup ref="popup" position="bottom" @maskClick="handleMaskClick">
<!-- 弹窗主体 -->
<div class="calendar-popup" @tap.stop>
<div class="relative w-full bg-white rounded-[12px] overflow-hidden">
<!-- 头部区域 -->
<div class="calendar-header">
<div class="header-content">
<span class="header-title">日历选择</span>
<span v-if="props.rangeRequirePrice" class="header-subtitle">选择住宿日期以下价格为单晚参考价</span>
<div class="flex items-start justify-between p-[12px] border-b border-[#d9d9d9] bg-white">
<div class="flex-1 flex flex-col gap-[4px]">
<span class="text-[18px] font-semibold text-[#333] leading-[1.4]">日历选择</span>
<span v-if="props.rangeRequirePrice" class="text-[14px] text-[#8c8c8c] leading-[1.4]">选择住宿日期以下价格为单晚参考价</span>
</div>
<div class="header-close" @tap="handleClose">
<uni-icons type="closeempty" size="20" color="#8c8c8c"></uni-icons>
<div class="flex items-center justify-center w-[32px] h-[32px] " @click="handleClose">
<van-icon name="cross" size="20" color="#8c8c8c"></van-icon>
</div>
</div>
<!-- 周标题行 - 固定显示 -->
<div class="week-header">
<span class="week-day" v-for="day in weekDays" :key="day">
<div class="flex p-[16px_12px_8px] bg-white border-b border-[#d9d9d9] border-solid">
<span class="flex-1 text-center text-[14px] text-[#8c8c8c] font-medium leading-[1.4]" v-for="day in weekDays"
:key="day">
{{ day }}
</span>
</div>
@@ -23,10 +24,10 @@
<!-- 日历主体区域 -->
<div class="calendar-body">
<!-- 全年月份显示区域 -->
<div class="year-container">
<div class="month-section" v-for="monthData in yearMonthsGrid" :key="monthData.key">
<div class="flex flex-col gap-[32px]">
<div class="flex flex-col" v-for="monthData in yearMonthsGrid" :key="monthData.key">
<span class="month-title">{{ monthData.title }}</span>
<div class="date-grid">
<div class="grid grid-cols-7 gap-[4px]">
<div class="date-cell" v-for="(dateInfo, index) in monthData.grid" :key="index"
:class="getDateCellClass(dateInfo)" @tap="handleDateClick(dateInfo)">
<template v-if="dateInfo">
@@ -44,7 +45,7 @@
</div>
</div>
</div>
</uni-popup>
</van-popup>
</template>
<script setup>
@@ -62,7 +63,7 @@ defineOptions({
name: "Calendar",
});
// uni-popup组件引用
// van-popup组件引用
const popup = ref(null);
// 定义Props
@@ -322,7 +323,7 @@ const getDateLabel = (dateStr) => {
// 获取日期格子样式类
const getDateCellClass = (dateInfo) => {
if (!dateInfo) return "date-cell-empty";
if (!dateInfo) return "bg-transparent cursor-default";
const classes = ["date-cell-content"];
@@ -345,7 +346,7 @@ const getDateCellClass = (dateInfo) => {
const handleDateClick = (dateInfo) => {
if (!dateInfo) return;
if (dateInfo.disabled) {
uni.showToast({ title: "该日期不可选", icon: "none" });
showToast("该日期不可选");
// 仍然触发点击事件,供上层参考
emit("date-click", {
date: dateInfo.date,
@@ -399,14 +400,11 @@ const handleRangeSelection = (dateInfo) => {
dateInfo.price !== undefined &&
dateInfo.price !== "-";
if (!hasPrice) {
uni.showToast({ title: "所选日期不可预订,请重新选择", icon: "none" });
showToast('所选日期不可预订,请重新选择');
return;
}
if (dateInfo.stock !== undefined && Number(dateInfo.stock) <= 0) {
uni.showToast({
title: "所选日期库存不足,请选择其他日期",
icon: "none",
});
showToast("所选日期库存不足,请选择其他日期");
return;
}
}
@@ -419,7 +417,7 @@ const handleRangeSelection = (dateInfo) => {
// 否则为结束日期(完成选择)
if (rangeStart.value === dateInfo.date) {
uni.showToast({ title: "离店日期不能与入住日期相同", icon: "none" });
showToast("离店日期不能与入住日期相同");
return;
}
@@ -434,11 +432,7 @@ const handleRangeSelection = (dateInfo) => {
// 检查日期跨度是否超过28天
const daysBetween = calculateDaysBetween(rangeStart.value, rangeEnd.value);
if (daysBetween > 28) {
uni.showToast({
title: "预定时间不能超过28天",
icon: "none",
duration: 3000,
});
showToast("预定时间不能超过28天");
rangeStart.value = null;
rangeEnd.value = null;
isRangeSelecting.value = false;
@@ -452,10 +446,7 @@ const handleRangeSelection = (dateInfo) => {
(d) => d.price === null || d.price === undefined || d.price === "-",
);
if (missing) {
uni.showToast({
title: "所选区间包含无价格日期,请重新选择",
icon: "none",
});
showToast("所选区间包含无价格日期,请重新选择");
rangeStart.value = null;
rangeEnd.value = null;
return;
@@ -466,10 +457,7 @@ const handleRangeSelection = (dateInfo) => {
return item && item.stock !== undefined && Number(item.stock) <= 0;
});
if (badStock) {
uni.showToast({
title: "所选区间包含库存不足的日期,请重新选择",
icon: "none",
});
showToast("所选区间包含库存不足的日期,请重新选择");
rangeStart.value = null;
rangeEnd.value = null;
return;
@@ -554,7 +542,7 @@ const calculateDaysBetween = (startDate, endDate) => {
return days === 0 ? 1 : days;
};
// 监听visible属性变化控制uni-popup显示
// 监听visible属性变化控制van-popup显示
watch(
() => props.visible,
(newVisible) => {

View File

@@ -33,68 +33,6 @@ $font-size-date: 16px;
$font-size-price: 12px;
$font-size-label: 10px;
// uni-popup会自动处理遮罩层和定位这里移除相关样式
// 弹窗主体
.calendar-popup {
position: relative;
width: 100%;
background-color: $background-white;
border-radius: $modal-border-radius;
overflow: hidden;
}
// 头部区域
.calendar-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: $modal-padding;
border-bottom: 1px solid $border-color;
background-color: $background-white;
}
.header-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.header-title {
font-size: $font-size-title;
font-weight: 600;
color: $text-primary;
line-height: 1.4;
}
.header-subtitle {
font-size: $font-size-subtitle;
color: $text-secondary;
line-height: 1.4;
}
.header-close {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
transition: background-color 0.2s;
&:active {
background-color: $background-gray;
}
}
// 周标题行 - 固定显示
.week-header {
display: flex;
padding: 16px $modal-padding 8px;
background-color: $background-white;
border-bottom: 1px solid #eeeeee;
}
// 日历主体区域
.calendar-body {
@@ -108,28 +46,6 @@ $font-size-label: 10px;
}
}
.week-day {
flex: 1;
text-align: center;
font-size: $font-size-subtitle;
color: $text-secondary;
font-weight: 500;
line-height: 1.4;
}
// 全年容器
.year-container {
display: flex;
flex-direction: column;
gap: 32px;
}
// 月份区域
.month-section {
display: flex;
flex-direction: column;
}
.month-title {
font-size: $font-size-title;
font-weight: 600;
@@ -140,13 +56,6 @@ $font-size-label: 10px;
line-height: 1.4;
}
// 日期网格
.date-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: $date-cell-gap;
}
// 日期格子基础样式
.date-cell {
position: relative;
@@ -162,12 +71,6 @@ $font-size-label: 10px;
cursor: pointer;
}
// 空白格子
.date-cell-empty {
background-color: transparent;
cursor: default;
}
// 有内容的格子
.date-cell-content {
background-color: $background-white;
@@ -280,4 +183,4 @@ $font-size-label: 10px;
font-weight: 500;
text-align: center;
min-height: 12px;
}
}

View File

@@ -12,9 +12,9 @@
1,
}">
<div class="flex flex-items-center flex-row flex-shrink-0 mr-8">
<uni-icons fontFamily="znicons" size="20" color="#333">
<van-icon fontFamily="znicons" size="20" color="#333">
{{ zniconsMap[moduleItem.moduleIcon] }}
</uni-icons>
</van-icon>
<span class="ml-4 font-size-14 color-171717 line-height-20">
{{ moduleItem.moduleTitle }}
</span>
@@ -25,14 +25,15 @@
</div>
</div>
</div>
<zero-markdown-div v-else :markdown="goodsData.commodityTip" :aiMode="true" />
<vue3-markdown-it v-else :source="goodsData.commodityTip" :html="true" />
</div>
</template>
<script setup>
import { defineProps } from "vue";
import Vue3MarkdownIt from 'vue3-markdown-it';
import ModuleTitle from "@/components/ModuleTitle/index.vue";
import { zniconsMap } from "@/assets/fonts/znicons";
import { defineProps } from "vue";
// Props定义
const props = defineProps({

View File

@@ -1,7 +1,7 @@
<template>
<div class="relative w-full">
<van-swipe class="overflow-hidden" :style="swiperStyle" @change="handleSwiperChange">
<van-swipe-item class="swiper-item" v-for="(item, index) in thumbnails" :key="index">
<van-swipe-item v-for="(item, index) in thumbnails" :key="index">
<img class="w-full h-full" :src="item.photoUrl">
</van-swipe-item>
</van-swipe>
@@ -21,7 +21,7 @@
</div>
<div class="ml-[12px] bg-[rgba(0,0,0,0.5)] rounded-[50px] p-[0_6px_4px_8px] flex-auto shrink-0 whitespace-nowrap"
@click="handlePredivClick">
@click="handlePreviewClick">
<van-icon name="arrow-left" size="10" color="#fff"></van-icon>
<span class="mx-[4px] text-[10px] text-white align-center">
{{ thumbnails.length }}
@@ -34,9 +34,11 @@
<script setup>
import { ref, computed, nextTick } from "vue";
import { useRouter } from 'vue-router'
import { usePictureStore } from "@/store";
const pictureStore = usePictureStore();
const router = useRouter();
// Props定义
const props = defineProps({
@@ -136,10 +138,9 @@ const handleSwiperChange = (e) => {
scrollToActiveItem(currentIndex);
};
const handlePredivClick = () => {
pictureStore.setPredivImageData(thumbnails.value);
uni.navigateTo({
url: `/pages/goods/album/index`,
});
const handlePreviewClick = () => {
pictureStore.setPreviewImageData(thumbnails.value);
router.push({ name: 'album' })
};
</script>

View File

@@ -4,7 +4,7 @@
<div class="flex-1 overflow-y-auto" @scroll="handleScroll">
<ImageSwiper :border-radius="0" :height="300" :images="goodsData.commodityPhotoList" thumbnailBottom="42px" />
<div class="bg-white py-[20px] relative -mt-[30px] z-10 rounded-t-[28px]">
<div class="bg-white py-[20px] relative mt-[-30px] z-10 rounded-t-[28px]">
<!-- 商品信息组件 -->
<GoodInfo :goodsData="goodsData" />

View File

@@ -34,7 +34,7 @@ const http = axios.create({
let context: RequestContext = {
token: null,
clientId: "6",
clientId: import.meta.env.VITE_CLIENT_ID,
latitude: null,
longitude: null,
language: null,

View File

@@ -40,7 +40,7 @@ export default defineConfig({
open: false,
proxy: {
"/ingress": {
target: "https://onefeel.brother7.cn",
target: "https://abroadbiz.nianxx.com",
changeOrigin: true,
ws: true,
secure: false,