diff --git a/pages.json b/pages.json
index 6f767fb..228de21 100644
--- a/pages.json
+++ b/pages.json
@@ -17,6 +17,7 @@
"style": {
// "navigationBarTitleText": "custom",
"navigationStyle": "custom",
+ "enablePullDownRefresh": true,
// "navigationStyle": "default",
// "navigationBarBackgroundColor": "#298DFF",
// "navigationBarTextStyle": "white"
@@ -60,6 +61,7 @@
"path": "pages/cate/index",
"style": {
"navigationBarTitleText": "健康资讯",
+ "enablePullDownRefresh": true,
// 主包异步引用分包 ListSkeleton
"componentPlaceholder": {
"list-skeleton": "view"
@@ -78,6 +80,7 @@
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "消息",
+ "enablePullDownRefresh": true,
// 主包异步引用分包 ListSkeleton
"componentPlaceholder": {
"list-skeleton": "view"
diff --git a/pages/cate/index.vue b/pages/cate/index.vue
index d8db7c3..9a910d3 100644
--- a/pages/cate/index.vue
+++ b/pages/cate/index.vue
@@ -5,7 +5,8 @@
+ @search="toSearch"
+ @clear="clearSearch">
@@ -88,9 +89,18 @@
},
methods: {
- // 搜索
+ // 搜索:按当前分类 + 标题关键词拉文章(不再误调分类接口)
toSearch() {
- this.getList()
+ this.infoList = []
+ this.articleFetchingEmpty = true
+ this.getArticleList()
+ },
+ // 清空搜索词后重新拉当前分类文章
+ clearSearch() {
+ this.keyword = ''
+ this.infoList = []
+ this.articleFetchingEmpty = true
+ this.getArticleList()
},
/*切换需要*/
changeStyle(id) {
@@ -102,16 +112,17 @@
url: '/pages/cate/info-detail?id=' + e
})
},
- //点击药品一级分类e:不清空 infoList,有旧数据则保留到新结果返回
+ // 切分类:立即清空文章出骨架
handleCategory1(e, index) {
this.num = e
this.cid = e
+ this.infoList = []
+ this.articleFetchingEmpty = true
this.getArticleList()
},
-
- //获取药品分类:成功后再覆盖,失败保留旧分类
+ // 获取分类:返回 Promise 供下拉刷新等待
getList() {
- categoriesList({
+ return categoriesList({
method: "post",
data: {
store_id: uni.getStorageSync('store_id') || '11001',
@@ -129,23 +140,28 @@
const firstId = list[0].id
this.num = firstId
this.cid = firstId
- this.getArticleList()
+ return this.getArticleList()
}
}).finally(() => {
this.categoryInitialLoading = false
})
},
- // 文章列表:请求前不清空;仅当当前无文章可展示时打骨架标记
+ // 文章列表:可选 keyword 标题搜索
getArticleList() {
if (!this.infoList || this.infoList.length === 0) {
this.articleFetchingEmpty = true
}
- articleList({
+ const data = {
+ store_id: uni.getStorageSync('store_id') || '11001',
+ cid: this.cid
+ }
+ const kw = (this.keyword || '').trim()
+ if (kw) {
+ data.keyword = kw
+ }
+ return articleList({
method: "get",
- data: {
- store_id: uni.getStorageSync('store_id') || '11001',
- cid: this.cid
- }
+ data
}).then((res) => {
if (res.data.code == 0) {
this.infoList = (res.data.result && res.data.result.list) || []
@@ -154,6 +170,19 @@
this.articleInitialLoading = false
this.articleFetchingEmpty = false
})
+ },
+ /**
+ * 下拉刷新:清空分类/文章并重走开骨架
+ */
+ onPullDownRefresh() {
+ this.categoryLists = []
+ this.infoList = []
+ this.categoryInitialLoading = true
+ this.articleInitialLoading = true
+ this.articleFetchingEmpty = false
+ Promise.resolve(this.getList()).finally(() => {
+ uni.stopPullDownRefresh()
+ })
}
},
mounted() {
diff --git a/pages/home/home.vue b/pages/home/home.vue
index cb5387d..5ce3641 100644
--- a/pages/home/home.vue
+++ b/pages/home/home.vue
@@ -86,14 +86,20 @@
-
+
预约购药
正品保障 · 种类齐全 · 快速配送
-
+
+
+
@@ -200,7 +206,7 @@
更多
-
+
@@ -697,8 +703,8 @@ export default {
})
},
getList() {
- // 不再请求前清空 doctorList,避免 onShow 刷新时出现「先空后满」
- doctorList({
+ // 返回 Promise 供下拉刷新 Promise.all 等待
+ return doctorList({
method: "post",
data: { store_id: uni.getStorageSync('store_id') || '11001' }
}).then((res) => {
@@ -726,7 +732,7 @@ export default {
})
},
getBannered() {
- getBanner({
+ return getBanner({
method: "post",
data: { store_id: uni.getStorageSync('store_id') || '11001' }
}).then((res) => {
@@ -758,7 +764,7 @@ export default {
}
},
getProductList() {
- getStoreDrugListBySalespersonApi({
+ return getStoreDrugListBySalespersonApi({
store_id: uni.getStorageSync('store_id') || '11001',
page: 1,
limit: 3
@@ -772,7 +778,7 @@ export default {
})
},
getHomeTopProducts() {
- getHomeTopProductsApi({
+ return getHomeTopProductsApi({
store_id: uni.getStorageSync('store_id') || '11001',
}).then((res) => {
if (res.data.code == 0 && res.data.result) {
@@ -792,7 +798,7 @@ export default {
}
},
getHomeZones() {
- getHomeZonesApi({
+ return getHomeZonesApi({
store_id: uni.getStorageSync('store_id') || '11001',
}).then((res) => {
if (res.data.code == 0) {
@@ -807,6 +813,32 @@ export default {
this.homeZonesInitialLoading = false
})
},
+ /**
+ * 下拉刷新:清空金刚区与卡片,重新走骨架后再拉数
+ * 为什么:用户期望刷新时看到加载态,而不是短暂保留旧数据
+ */
+ refreshHomeContent() {
+ this.homeZones = [];
+ this.homeZonesInitialLoading = true;
+ this.doctorList = [];
+ this.doctorListInitialLoading = true;
+ this.productList = [];
+ this.topProductsList = [];
+ this.productListInitialLoading = true;
+ this._productFetchDone = 0;
+ return Promise.all([
+ this.getHomeZones(),
+ this.getList(),
+ this.getProductList(),
+ this.getHomeTopProducts(),
+ this.getBannered()
+ ]);
+ },
+ onPullDownRefresh() {
+ this.refreshHomeContent().finally(() => {
+ uni.stopPullDownRefresh();
+ });
+ },
getPlatformQualifications() {
getPlatformQualificationsApi({
store_id: uni.getStorageSync('store_id') || '11001',
@@ -1022,6 +1054,7 @@ $card-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.04);
&::before { content: ''; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: linear-gradient(90deg, #FDFEFF 0%, rgba(255,255,255,0) 100%); z-index: 1; }
.nav-content { position: relative; z-index: 2; .nav-title { font-size: 36rpx; font-weight: 800; margin-bottom: 8rpx; } .nav-desc { font-size: 22rpx; color: #888; } }
.nav-icon-img { position: absolute; right: 0; bottom: 0; width: 128rpx; height: 128rpx; z-index: 1; }
+ .nav-icon-img-256 { position: absolute; right: 0; bottom: 0; width: 256rpx; height: 138rpx; z-index: 1; }
.nav-icon-img-64 { position: absolute; right: 30rpx; top: 30rpx; width: 84rpx; height: 84rpx; z-index: 1; }
}
}
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 60744bb..723f4d0 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -323,7 +323,7 @@ export default {
},
// 拉取 IM 好友会话列表,成功后整份替换,失败不写空
getMyChatFriendsList() {
- getChatFriendsListApi().then((res) => {
+ return getChatFriendsListApi().then((res) => {
const allChatList = res.data.result || []
// 根据type字段区分在线咨询和在线复诊
this.onlineConsultationList = allChatList.filter(item => item.type === 1 || !item.type) // type=1或未设置type的为在线咨询
@@ -338,7 +338,7 @@ export default {
},
// 获取转诊消息列表;失败不重置 transfer,避免闪空
getTransferList() {
- getTransferPrescriptionListApi().then((res) => {
+ return getTransferPrescriptionListApi().then((res) => {
if (res.data && res.data.code == 0) {
const transferList = res.data.result || []
// 统计待确认的转诊消息数量
@@ -358,6 +358,33 @@ export default {
}).catch((error) => {
console.error('获取转诊消息列表失败:', error)
})
+ },
+ /**
+ * 下拉刷新:重置骨架并并行重拉消息概览 / IM / 转诊
+ */
+ refreshMessagePage() {
+ this.noticeInitialLoading = true
+ if (checkDev('open-im')) {
+ this.chatInitialLoading = true
+ this.onlineConsultationList = []
+ this.onlineReconsultationList = []
+ this.imChat = []
+ }
+ const tasks = [
+ this.getInfo(),
+ this.getTransferList()
+ ]
+ if (checkDev('open-im')) {
+ tasks.push(this.getMyChatFriendsList())
+ } else {
+ this.chatInitialLoading = false
+ }
+ return Promise.all(tasks)
+ },
+ onPullDownRefresh() {
+ this.refreshMessagePage().finally(() => {
+ uni.stopPullDownRefresh()
+ })
}
},
mounted() {
diff --git a/request/api/request.js b/request/api/request.js
index 41b488c..c1e546c 100644
--- a/request/api/request.js
+++ b/request/api/request.js
@@ -80,22 +80,18 @@ const isDev = checkDev('dev');
const ENV_URLS = {
// 生产环境
prod: {
- // main: "https://app.xiaokang88.com/member",
- // xkApi: "https://api.xiaokang88.com/api/mobile",
- // shop: "https://shop.xiaokang88.com/member",
- // im: "https://api.ws.g.xiaokang88.com/api",
+ main: "https://app.xiaokang88.com/member",
+ xkApi: "https://api.xiaokang88.com/api/mobile",
+ shop: "https://shop.xiaokang88.com/member",
+ im: "https://api.ws.g.xiaokang88.com/api",
+ },
+ // 测试环境
+ test: {
main: "https://xk.test.saas.api-yii.nailaoyun.cn/member",
xkApi: "https://xk.test.saas.api.nailaoyun.cn/api/mobile",
shop: "https://test.xk.shop.nailaoyun.cn/member1",
im: "https://xk.ws.nailaoyun.cn/api"
},
- // 测试环境
- test: {
- main: "http://xk.test.saas.api.yii.nailaoyun.cn/member",
- xkApi: "http://xk.test.saas.api.nailaoyun.cn/api/mobile",
- shop: "https://test.xk.shop.nailaoyun.cn/member1",
- im: ""
- },
// 本地开发环境
local: {
main: "http://127.0.0.1:18000/member",
@@ -112,7 +108,7 @@ function getEnvUrls() {
return ENV_URLS.local;
}
// 检查是否开启了开发者测试模式
- const devMode = uni.getStorageSync('dev_mode');
+ const devMode = checkDev('test');
return devMode ? ENV_URLS.test : ENV_URLS.prod;
}
diff --git a/subPackages/common/components/ListSkeleton.vue b/subPackages/common/components/ListSkeleton.vue
index b7d254d..2f97ff4 100644
--- a/subPackages/common/components/ListSkeleton.vue
+++ b/subPackages/common/components/ListSkeleton.vue
@@ -1,59 +1,85 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -61,15 +87,15 @@
export default {
name: 'ListSkeleton',
props: {
- // 骨架样式类型
+ // 骨架样式类型(detail 为商品详情整页骨架)
type: {
type: String,
default: 'message',
validator(v) {
- return ['doctor', 'message', 'product', 'article', 'category', 'zone'].indexOf(v) !== -1
+ return ['doctor', 'message', 'product', 'article', 'category', 'zone', 'detail'].indexOf(v) !== -1
}
},
- // 行数
+ // 行数(detail 时表示信息卡片块数)
rows: {
type: [Number, String],
default: 3
@@ -79,6 +105,10 @@ export default {
rowCount() {
const n = Number(this.rows)
return n > 0 ? n : 3
+ },
+ // 详情骨架信息卡数量,默认 3 块
+ detailCardCount() {
+ return this.rowCount
}
}
}
@@ -272,4 +302,45 @@ export default {
width: 40%;
margin-bottom: 0;
}
+
+/* 商品详情骨架:大图 + 基础信息 + 物流条 + 信息卡 */
+.list-skeleton--detail {
+ background: #F5F7FA;
+ min-height: 100vh;
+ padding-bottom: 40rpx;
+}
+
+.sk-detail-hero {
+ width: 100%;
+ height: 750rpx;
+}
+
+.sk-detail-basic {
+ background: #fff;
+ padding: 32rpx 30rpx;
+ margin-bottom: 20rpx;
+
+ .sk-line--price {
+ width: 200rpx;
+ height: 48rpx;
+ margin-bottom: 24rpx;
+ }
+}
+
+.sk-detail-spec {
+ margin-top: 24rpx;
+ padding-top: 16rpx;
+}
+
+.sk-detail-tip {
+ height: 80rpx;
+ margin: 0 0 20rpx;
+ border-radius: 0;
+}
+
+.sk-detail-card {
+ background: #fff;
+ padding: 30rpx;
+ margin-bottom: 20rpx;
+}
diff --git a/subPackages/my/my-drug/drug-info.vue b/subPackages/my/my-drug/drug-info.vue
index d36b33e..36ca4cb 100644
--- a/subPackages/my/my-drug/drug-info.vue
+++ b/subPackages/my/my-drug/drug-info.vue
@@ -1,8 +1,8 @@
-
-
+
+
{{ orderText }}
@@ -90,6 +90,9 @@
{{item.drug_name}}
x{{item.number}}
+
+ 该药品由{{ item.delivery_warehouse_name }}配送
+
@@ -109,6 +112,10 @@
{{ item.drug.usage }}
+
+
+ 该药品由{{ item.delivery_warehouse_name }}配送
+
查看说明书
@@ -300,6 +307,20 @@ export default {
const o = this.orderInfo.ProductOrder
return o.delivery_method == 0 && o.status != 0 && o.address && o.cancel_status == 0
},
+ // 整单存在任一外部配送仓时:隐藏顶部文案,改在药品行展示
+ hasDeliveryWarehouse() {
+ const o = this.orderInfo && this.orderInfo.ProductOrder
+ if (o && Number(o.has_delivery_warehouse) === 1) {
+ return true
+ }
+ const items = (this.orderInfo && this.orderInfo.ProductOrderItems) || []
+ for (let i = 0; i < items.length; i++) {
+ if (Number(items[i].delivery_warehouse_id || 0) > 0) {
+ return true
+ }
+ }
+ return false
+ },
},
onLoad(e) {
this.p_id = e.id
@@ -329,18 +350,27 @@ export default {
url: `/subPackages/product/symptoms?${q}`,
});
},
- // 获取订单提示文本
+ // 获取订单提示文本(无外部配送仓时才用于顶部与支付弹窗)
getOrderText() {
getOrderTextApi().then((res) => {
if (res.data && res.data.result) {
this.orderText = res.data.result;
- // 设置模态框内容
this.modalContent = `${res.data.result}\n\n请在确认以上信息后继续支付。`;
}
}).catch(err => {
console.error('获取订单提示失败:', err);
})
},
+ /**
+ * 有外部配送仓时支付弹窗用中性文案,避免仍写「由萧康医药提供服务」
+ */
+ refreshPayModalContent() {
+ if (this.hasDeliveryWarehouse) {
+ this.modalContent = '请确认配送信息后继续支付。';
+ } else if (this.orderText) {
+ this.modalContent = `${this.orderText}\n\n请在确认以上信息后继续支付。`;
+ }
+ },
// 不需要代煎-代煎费
cancel() {
this.openshow = false;
@@ -538,6 +568,7 @@ export default {
// 查询处方状态
this.getPrescriptionStatus()
+ this.refreshPayModalContent()
}
})
},
@@ -598,7 +629,8 @@ export default {
return
}
- // 先显示物流提示模态框
+ // 先显示物流提示模态框(有配送仓时弹窗为中性确认文案)
+ this.refreshPayModalContent();
this.showOrderTextModal = true;
},
@@ -751,6 +783,12 @@ export default {
line-height: 1.4;
border-left: 6rpx solid #1890ff;
}
+ .wh-tip {
+ margin-top: 8rpx;
+ font-size: 24rpx;
+ color: #1890ff;
+ line-height: 1.4;
+ }
.head_cancle {
padding: 20rpx 42rpx;
diff --git a/subPackages/my/record-pay.vue b/subPackages/my/record-pay.vue
index 57d602d..b7d42e6 100644
--- a/subPackages/my/record-pay.vue
+++ b/subPackages/my/record-pay.vue
@@ -1,8 +1,8 @@
-
-
+
+
{{ orderText }}
@@ -70,16 +70,12 @@
-
{{item.name}}
x{{item.number}}
-
+
+ 该药品由{{ item.delivery_warehouse_name }}配送
+
@@ -89,13 +85,9 @@
{{item.name}}
x{{item.number}}
-
+
+ 该药品由{{ item.delivery_warehouse_name }}配送
+
@@ -110,6 +102,9 @@
{{item.content.usage}}
+
+ 该药品由{{ item.delivery_warehouse_name }}配送
+
0) {
+ return true
+ }
+ }
+ return false
+ },
+ },
onLoad(e) {
this.p_id = e.id
// 获取订单提示文本
@@ -301,18 +312,27 @@
methods: {
canShowUsage,
canShowInstruction,
- // 获取订单提示文本
+ // 获取订单提示文本(无外部配送仓时才用于顶部与支付弹窗)
getOrderText() {
getOrderTextApi().then((res) => {
if (res.data && res.data.result) {
this.orderText = res.data.result;
- // 设置模态框内容
this.modalContent = `${res.data.result}\n\n请在确认以上信息后继续支付。`;
}
}).catch(err => {
console.error('获取订单提示失败:', err);
})
},
+ /**
+ * 有外部配送仓时支付弹窗用中性文案
+ */
+ refreshPayModalContent() {
+ if (this.hasDeliveryWarehouse) {
+ this.modalContent = '请确认配送信息后继续支付。';
+ } else if (this.orderText) {
+ this.modalContent = `${this.orderText}\n\n请在确认以上信息后继续支付。`;
+ }
+ },
// 物流提示确认 - 用户选择"我知道了"
handleOrderTextConfirm() {
this.showOrderTextModal = false;
@@ -521,6 +541,7 @@
}
}
this.getPrescriptionStatus()
+ this.refreshPayModalContent()
}
})
},
@@ -609,7 +630,8 @@
// 支付
toPay() {
- // 先显示物流提示模态框
+ // 先显示物流提示模态框(有配送仓时弹窗为中性确认文案)
+ this.refreshPayModalContent();
this.showOrderTextModal = true;
},
@@ -736,6 +758,12 @@
line-height: 1.4;
border-left: 6rpx solid #1890ff;
}
+ .wh-tip {
+ margin-top: 8rpx;
+ font-size: 24rpx;
+ color: #1890ff;
+ line-height: 1.4;
+ }
.head_cancle {
padding: 20rpx 42rpx;
diff --git a/subPackages/product/product.vue b/subPackages/product/product.vue
index d69eb1e..5696a9d 100644
--- a/subPackages/product/product.vue
+++ b/subPackages/product/product.vue
@@ -21,105 +21,125 @@
-
-
-
-
-
- {{ zone.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.drug ? item.drug.drug_name : '' }}
+
+
+ {{ getProductTag(item.drug).label }}
+
+ {{ (item.drug && item.drug.specification) ? item.drug.specification : '标准规格' }}
+
+
+
+ ¥
+ {{ item.price }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ item.drug ? item.drug.drug_name : '' }}
-
-
- {{ getProductTag(item.drug).label }}
-
- {{ (item.drug && item.drug.specification) ? item.drug.specification : '标准规格' }}
-
-
-
- ¥
- {{ item.price }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
({
+ name: z.title || ''
+ }));
+ },
+ // 左侧分类骨架:首次加载,或分类请求中且尚无分类可展示
+ showCategorySkeleton() {
+ if (this.pageInitialLoading) {
+ return true;
+ }
+ return this.categoryFetching && this.categoryList.length === 0;
+ },
+ // 右侧商品骨架:首次加载,或请求中且当前无商品可保留
+ showProductSkeleton() {
+ if (this.pageInitialLoading) {
+ return true;
+ }
+ return this.listFetching && this.products.length === 0;
+ },
getProductImage() {
return (this.currentProduct.drug && this.currentProduct.drug.image) ? this.currentProduct.drug.image : 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/mine/avatar_1.png';
},
@@ -221,15 +267,11 @@ export default {
this.doctorId = e.doctor_id;
this.r_type = e.register_type;
this.delegateStoreId = e.delegate_store_id || '';
-
- // 根据首页传入的专区类型初始化
if (e.zone_type) {
this.selectedZoneType = e.zone_type;
} else {
this.selectedZoneType = 'otc';
}
-
- // 获取专区列表
this.getHomeZones();
},
methods: {
@@ -240,19 +282,14 @@ export default {
}).then((res) => {
if (res.data.code == 0) {
this.homeZones = res.data.result || res.data.data || [];
-
- // 根据传入的zone_type找到对应的索引
if (this.homeZones.length > 0) {
const index = this.homeZones.findIndex(z => z.type === this.selectedZoneType);
this.selectedZoneIndex = index >= 0 ? index : 0;
- this.selectedZoneType = this.homeZones[this.selectedZoneIndex]?.type || 'otc';
+ this.selectedZoneType = this.homeZones[this.selectedZoneIndex].type || 'otc';
}
-
- // 获取分类列表
this.getCategoryList();
}
}).catch(() => {
- // 使用默认专区
this.homeZones = [
{ id: 1, title: 'OTC', type: 'otc' },
{ id: 2, title: '保健食品', type: 'health_food' }
@@ -260,27 +297,25 @@ export default {
this.getCategoryList();
});
},
-
- // 获取分类列表
- getCategoryList() {
+ // 获取分类列表;不清空旧商品,避免切专区闪空
+ getCategoryList(callback) {
+ this.categoryFetching = true;
getDrugCategoriesApi({
zone_type: this.selectedZoneType
}).then((res) => {
if (res.data.code == 0) {
- // 将树形结构扁平化为一级分类列表
const categories = res.data.result || [];
this.categoryList = this.flattenCategories(categories);
}
}).catch(() => {
this.categoryList = [];
}).finally(() => {
- // 重置分类选择并获取商品列表
+ this.categoryFetching = false;
this.selectedCategoryId = 0;
- this.getList();
+ this.getList(callback);
});
},
-
- // 扁平化分类树(只取一级分类,或展开所有层级)
+ // 扁平化分类树
flattenCategories(categories, result = []) {
for (const cat of categories) {
result.push({
@@ -295,37 +330,59 @@ export default {
}
return result;
},
-
- // 专区切换
+ // Tab 点击切换(与订单列表 onTabChange 一致)
+ onTabChange(index) {
+ if (this.tabChanging) return;
+ const tabIndex = Number(index) || 0;
+ // 已是当前项时不重复请求;也可挡住 swiper 回写
+ if (tabIndex === this.selectedZoneIndex) return;
+ this.tabChanging = true;
+ this.onZoneChange(tabIndex);
+ this.$nextTick(() => {
+ this.tabChanging = false;
+ });
+ },
+ // swiper 滑动切换
+ onSwiperChange(e) {
+ if (this.tabChanging) return;
+ const tabIndex = Number(e.detail.current) || 0;
+ if (tabIndex === this.selectedZoneIndex) return;
+ this.tabChanging = true;
+ this.onZoneChange(tabIndex);
+ this.$nextTick(() => {
+ this.tabChanging = false;
+ });
+ },
+ // 专区切换:立即清空旧数据出骨架,再拉分类+商品
onZoneChange(index) {
- this.selectedZoneIndex = index;
- this.selectedZoneType = this.homeZones[index]?.type || 'otc';
+ const tabIndex = Number(index) || 0;
+ this.selectedZoneIndex = tabIndex;
+ this.selectedZoneType = (this.homeZones[tabIndex] && this.homeZones[tabIndex].type) || 'otc';
this.selectedCategoryId = 0;
+ this.products = [];
+ this.categoryList = [];
+ this.listFetching = true;
+ this.categoryFetching = true;
this.getCategoryList();
},
-
- onZoneTouchStart(e) {
- const touch = e.touches[0] || e.changedTouches[0];
- if (!touch) return;
- this.zoneTouch.startX = touch.clientX;
- this.zoneTouch.startY = touch.clientY;
- },
-
- onZoneTouchEnd(e) {
- const dx = e.changedTouches[0].clientX - this.zoneTouch.startX;
- const dy = e.changedTouches[0].clientY - this.zoneTouch.startY;
- if (Math.abs(dx) < 60 || Math.abs(dx) < Math.abs(dy)) return;
- const next = dx < 0 ? this.selectedZoneIndex + 1 : this.selectedZoneIndex - 1;
- if (next < 0 || next >= this.homeZones.length) return;
- this.onZoneChange(next);
- },
-
- // 分类选择
+ // 分类选择:清空商品出骨架后再请求
selectCategory(categoryId) {
this.selectedCategoryId = categoryId;
+ this.products = [];
+ this.listFetching = true;
this.getList();
},
-
+ // 右侧下拉刷新:清空分类+商品出骨架,再重拉
+ onRefresherRefresh() {
+ this.isRefreshing = true;
+ this.products = [];
+ this.categoryList = [];
+ this.listFetching = true;
+ this.categoryFetching = true;
+ this.getCategoryList(() => {
+ this.isRefreshing = false;
+ });
+ },
// 核心标签判断逻辑
getProductTag(drug) {
if (!drug) return { label: 'OTC', className: 'tag-green' };
@@ -339,41 +396,43 @@ export default {
return { label: 'Rx', className: 'tag-red' };
}
}
+ return { label: 'OTC', className: 'tag-green' };
},
-
- getList() {
+ // 拉取商品列表;callback 供下拉刷新收尾
+ getList(callback) {
+ this.listFetching = true;
const params = {
store_id: uni.getStorageSync('store_id') || '11001',
page: 1,
limit: 100,
category: this.selectedZoneType
};
-
if (this.selectedCategoryId > 0) {
params.category_id = this.selectedCategoryId;
}
-
if (this.searchKeyword) {
params.keyword = this.searchKeyword;
}
-
getStoreDrugListBySalespersonApi(params).then((res) => {
if (res.data.code == 0) {
this.products = res.data.result.records || [];
this.cartCount = res.data.result.cart_count || 0;
}
+ }).finally(() => {
+ this.listFetching = false;
+ this.pageInitialLoading = false;
+ if (typeof callback === 'function') {
+ callback();
+ }
});
},
-
handleSearch() {
this.getList();
},
-
clearSearch() {
this.searchKeyword = "";
this.getList();
},
-
handClickProduct(item) {
let url = `/subPackages/product/symptoms?id=${item.drug.id}&drug_name=${item.drug.drug_name}&is_otc=${item.drug.is_otc}&image=${item.drug.image}&price=${item.price}`;
if (this.delegateStoreId) {
@@ -381,7 +440,6 @@ export default {
}
uni.navigateTo({ url });
},
-
// 悬浮球逻辑
initCartPosition() {
const systemInfo = uni.getSystemInfoSync();
@@ -433,7 +491,6 @@ export default {
},
quantityChange(value) {},
confirmAddToCart() {
- // 检查是否为处方药:is_otc === 0 && type == 2
if (this.currentProduct.drug && this.currentProduct.drug.is_otc === 0 && this.currentProduct.drug.type == 2) {
uni.showToast({
title: '处方药不能加入购物车,请通过提交预定购买',
@@ -442,7 +499,6 @@ export default {
});
return;
}
-
saveCartApi({
store_id: uni.getStorageSync('store_id') || '11001',
drug_id: this.currentProduct.drug.id,
@@ -502,58 +558,33 @@ export default {
background: #fff;
padding: 16rpx 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
-
+ flex-shrink: 0;
+
.search-box {
width: 100%;
}
}
-/* 2. 顶部专区Tab */
-.zone-tabs-wrapper {
+/* 2. 顶部专区 Tab(u-tabs) */
+.zone-tabs-head {
+ width: 750rpx;
+ height: 80rpx;
+ flex-shrink: 0;
background: #fff;
border-bottom: 2rpx solid #f0f0f0;
-
- .zone-tabs-scroll {
- white-space: nowrap;
- }
-
- .zone-tabs {
- display: inline-flex;
- padding: 0 24rpx;
-
- .zone-tab-item {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: 24rpx 32rpx;
- font-size: 28rpx;
- color: #666;
- position: relative;
- transition: all 0.2s;
-
- &.active {
- color: #2B85E4;
- font-weight: bold;
-
- &::after {
- content: '';
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 48rpx;
- height: 6rpx;
- background: linear-gradient(90deg, #5CADFF, #2B85E4);
- border-radius: 3rpx;
- }
- }
- }
- }
+ z-index: 99;
}
-/* 3. 主体内容区 */
-.main-content {
+/* 3. 专区 swiper:占满剩余高度,与订单列表 order-swiper 一致 */
+.zone-swiper {
flex: 1;
+ height: 0;
+ min-height: 0;
+}
+
+/* 主体内容区 */
+.main-content {
+ height: 100%;
display: flex;
overflow: hidden;
}
@@ -563,11 +594,12 @@ export default {
width: 180rpx;
background: #fff;
flex-shrink: 0;
-
+ height: 100%;
+
.category-scroll {
height: 100%;
}
-
+
.category-item {
height: 100rpx;
display: flex;
@@ -577,17 +609,17 @@ export default {
color: #666;
position: relative;
padding: 0 12rpx;
-
+
text {
text-align: center;
max-width: 100%;
}
-
+
&.active {
background: #F5F7FA;
color: #2B85E4;
font-weight: bold;
-
+
&::before {
content: '';
position: absolute;
@@ -607,7 +639,8 @@ export default {
.product-area {
flex: 1;
overflow: hidden;
-
+ height: 100%;
+
.product-scroll {
height: 100%;
padding: 16rpx;
@@ -628,32 +661,29 @@ export default {
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04);
-
+
&:active {
transform: scale(0.98);
}
-
+
.product-img-box {
width: 100%;
height: 240rpx;
background: #f8f8f8;
-
+
.product-img {
width: 100%;
height: 100%;
-
+
&.prescription-blur {
- /* 暂时禁用模糊
- filter: blur(8px);
- -webkit-filter: blur(8px);
- */
+ /* 暂时禁用模糊 */
}
}
}
-
+
.product-info {
padding: 16rpx;
-
+
.product-title {
font-size: 26rpx;
font-weight: 600;
@@ -662,13 +692,13 @@ export default {
height: 72rpx;
margin-bottom: 12rpx;
}
-
+
.product-tags {
display: flex;
align-items: center;
margin-bottom: 12rpx;
gap: 8rpx;
-
+
.tag-label {
font-size: 18rpx;
padding: 2rpx 8rpx;
@@ -676,12 +706,12 @@ export default {
font-weight: 500;
border: 1px solid;
flex-shrink: 0;
-
+
&.tag-green { color: #10B981; border-color: #10B981; background: #ECFDF5; }
&.tag-red { color: #EF4444; border-color: #EF4444; background: #FEF2F2; }
&.tag-orange { color: #F59E0B; border-color: #F59E0B; background: #FFFBEB; }
}
-
+
.tag-spec {
font-size: 20rpx;
color: #999;
@@ -689,20 +719,20 @@ export default {
min-width: 0;
}
}
-
+
.product-bottom {
display: flex;
justify-content: space-between;
align-items: center;
-
+
.price-box {
color: #EF4444;
font-weight: bold;
-
+
.price-symbol { font-size: 22rpx; }
.price-val { font-size: 32rpx; font-family: 'DIN Alternate', sans-serif; }
}
-
+
.cart-btn {
width: 48rpx;
height: 48rpx;
@@ -721,7 +751,7 @@ export default {
.cart-float {
position: fixed;
z-index: 999;
-
+
.cart-icon-inner {
width: 100rpx;
height: 100rpx;
@@ -732,7 +762,7 @@ export default {
justify-content: center;
box-shadow: 0 8rpx 20rpx rgba(74, 144, 226, 0.4);
position: relative;
-
+
.badge {
position: absolute;
top: -6rpx;
@@ -756,7 +786,7 @@ export default {
.product-header-row {
display: flex;
margin-bottom: 40rpx;
-
+
.popup-img {
width: 180rpx;
height: 180rpx;
@@ -764,13 +794,13 @@ export default {
margin-right: 24rpx;
background: #f8f8f8;
}
-
+
.popup-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-end;
-
+
.price-row {
color: #EF4444;
font-size: 28rpx;
@@ -799,7 +829,7 @@ export default {
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
-
+
&.add-cart {
background: linear-gradient(90deg, #4A90E2, #5B8FF9);
color: #fff;
@@ -809,17 +839,17 @@ export default {
}
}
-.empty-state {
- margin-top: 100rpx;
+.empty-state {
+ margin-top: 100rpx;
}
-.u-line-1 {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
+.u-line-1 {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
}
-.u-line-2 {
+.u-line-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
diff --git a/subPackages/product/symptoms.vue b/subPackages/product/symptoms.vue
index ec5ca0c..e0e325e 100644
--- a/subPackages/product/symptoms.vue
+++ b/subPackages/product/symptoms.vue
@@ -1,6 +1,9 @@
+
+
+
-
-
+
+
- {{ orderText }}
+ {{ logisticsTipText }}
@@ -169,6 +172,7 @@
+
@@ -268,7 +272,11 @@ export default {
indications: '',
indications_array: [],
compliance_tip: '', // 合规提示文案,由后端返回
- supplier: null
+ supplier: null,
+ // 配送仓字段需预声明,否则 Vue2 Object.assign 新 key 不触发视图更新
+ has_delivery_warehouse: 0,
+ delivery_warehouse_id: 0,
+ delivery_warehouse_name: ''
},
formData: {
id: '',
@@ -290,6 +298,12 @@ export default {
showBuyPopup: false,
buyQuantity: 1,
orderText: '本次商品物流配送,由萧康医药提供服务。',
+ // 物流仓提示单独挂 data,保证详情接口返回后一定能驱动 computed 重算
+ deliveryWarehouseFlag: 0,
+ deliveryWarehouseId: 0,
+ deliveryWarehouseName: '',
+ // 首次详情请求结束前展示骨架
+ detailInitialLoading: true,
introductionImages: [], // 商品介绍图数组
delegateStoreId: '', // 委托诊所ID
fromOrderId: '',
@@ -316,6 +330,29 @@ export default {
manufacturerName() {
return (this.productDetail.supplier && this.productDetail.supplier.name) || '';
},
+ // 有仓药绑定时用仓文案,替代萧康 order-text(优先读独立字段,避免嵌套对象漏更新)
+ hasDeliveryWarehouse() {
+ if (Number(this.deliveryWarehouseFlag) === 1) {
+ return true;
+ }
+ if (Number(this.deliveryWarehouseId || 0) > 0) {
+ return true;
+ }
+ const d = this.productDetail || {};
+ if (Number(d.has_delivery_warehouse) === 1) {
+ return true;
+ }
+ return Number(d.delivery_warehouse_id || 0) > 0;
+ },
+ logisticsTipText() {
+ const whName = this.deliveryWarehouseName
+ || (this.productDetail && this.productDetail.delivery_warehouse_name)
+ || '';
+ if (this.hasDeliveryWarehouse && whName) {
+ return '该商品由' + whName + '供应及配送';
+ }
+ return this.orderText || '';
+ },
showFunctionSection() {
if (isHealthFood(this.productDetail)) return false;
return canShowFunction(this.productDetail, this.prescriptionApproved)
@@ -395,6 +432,10 @@ export default {
});
},
getOrderText() {
+ // 有配送仓时不请求萧康默认文案
+ if (this.hasDeliveryWarehouse) {
+ return;
+ }
getOrderTextApi().then((res) => {
if (res.data && res.data.result) {
this.orderText = res.data.result;
@@ -404,7 +445,6 @@ export default {
})
},
getDetail() {
- this.getOrderText();
const params = {
id: this.productDetail.id,
};
@@ -417,8 +457,13 @@ export default {
}
getStoreDrugDetailApi(params).then((res) => {
if (res.data.code === 0) {
- const data = res.data.result;
- Object.assign(this.productDetail, data);
+ const data = res.data.result || {};
+ // 整对象替换:列表进详情时 name/price 常与接口一致,Object.assign 不会触发 Vue2 更新
+ this.productDetail = Object.assign({}, this.productDetail, data);
+ // 仓字段再写到顶层 data,确保物流提示 computed 一定重算
+ this.deliveryWarehouseFlag = Number(data.has_delivery_warehouse || 0);
+ this.deliveryWarehouseId = Number(data.delivery_warehouse_id || 0);
+ this.deliveryWarehouseName = data.delivery_warehouse_name || '';
if (data.prescription_approved !== undefined) {
this.prescriptionApproved = !!data.prescription_approved;
}
@@ -438,9 +483,14 @@ export default {
} else {
this.introductionImages = [];
}
+ // 详情返回后再决定是否拉萧康 order-text
+ this.getOrderText();
}
}).catch(error => {
console.error('加载商品详情失败:', error);
+ }).finally(() => {
+ // 无论成功失败都关闭骨架,避免一直卡住
+ this.detailInitialLoading = false;
});
},
previewImage(index) {
diff --git a/utils/ws/websocket.js b/utils/ws/websocket.js
index 18e6bae..0416e08 100644
--- a/utils/ws/websocket.js
+++ b/utils/ws/websocket.js
@@ -331,6 +331,6 @@ export class WebSocketManager {
// 全局WebSocket实例
// export const webSocketManager = new WebSocketManager('ws://127.0.0.1:12080/ws');
-// const wsUrl = checkDev('dev')? 'ws://127.0.0.1:12080/ws':'wss://api.ws.g.xiaokang88.com/ws';
-const wsUrl = checkDev('dev')? 'ws://127.0.0.1:12080/ws':'wss://xk.ws.nailaoyun.cn/ws';
+const wsUrl = checkDev('dev')? 'ws://127.0.0.1:12080/ws': checkDev('test')? 'wss://xk.ws.nailaoyun.cn/ws':'wss://api.ws.g.xiaokang88.com/ws';
+// const wsUrl = checkDev('dev')? 'ws://127.0.0.1:12080/ws':'wss://xk.ws.nailaoyun.cn/ws';
export const webSocketManager = new WebSocketManager(wsUrl);
\ No newline at end of file