feat(home/chat): 列表骨架屏、聊天室己方头像与协议/医生详情优化
- 新增分包组件 ListSkeleton(doctor/message/product/article/category/zone) - 首页/消息/资讯首次加载改用骨架屏,刷新不再清空旧数据避免闪空 · 去掉 home getList、消息 onShow 中的数组清空 · 三页 pages.json 增加 easycom 与 componentPlaceholder 主包异步引用 - 聊天室己方头像改为读取本地 userinfo.avatarurl(登录后微信头像), mycollection 上传头像成功后同步写回 storage - 修复协议抽屉点不开:page-container 改为 v-if + :show; 协议名单独可点节点,匹配放宽 name/desc 双向 includes - 医生气泡头像可点击进入 doctor-detail?readonly=1 只读医生详情, 隐藏预约挂号区
This commit is contained in:
@@ -8,3 +8,5 @@ alwaysApply: true
|
||||
3. 有封装好的方法、组件需要复用,不要重复造轮子
|
||||
4. 小程序端的抽屉全部需要用page-container来防止用户意外退出页面(记得使用v-if而不是v-show)
|
||||
5. 数据库的(created_at、updated_at、deleted_at)统一使用时间戳,不要使用字符串,并且我在查询器中一级格式化成字符串了,无需再次格式化
|
||||
6. 微信小程序 `.vue` 模板(会编译成 WXML)禁止使用 `??`、`?.` 等现代运算符,否则会报 `unexpected token '?'`;模板里用 `||` / 显式判断,脚本里可用 `??`/`?.`
|
||||
7. 微信小程序模板里 `:class` / `:style` 禁止写 `fn(arg)` 方法调用(如 `:class="sexClass(p)"` 会编译失败);用对象/数组字面量(如 `:class="{ male: p.sex == 1 }"`),或把结果先算进 data/computed 再绑定
|
||||
|
||||
@@ -8,3 +8,5 @@ alwaysApply: true
|
||||
3. 有封装好的方法、组件需要复用,不要重复造轮子
|
||||
4. 小程序端的抽屉全部需要用page-container来防止用户意外退出页面(记得使用v-if而不是v-show)
|
||||
5. 数据库的(created_at、updated_at、deleted_at)统一使用时间戳,不要使用字符串,并且我在查询器中一级格式化成字符串了,无需再次格式化
|
||||
6. 微信小程序 `.vue` 模板(会编译成 WXML)禁止使用 `??`、`?.` 等现代运算符,否则会报 `unexpected token '?'`;模板里用 `||` / 显式判断,脚本里可用 `??`/`?.`
|
||||
7. 微信小程序模板里 `:class` / `:style` 禁止写 `fn(arg)` 方法调用(如 `:class="sexClass(p)"` 会编译失败);用对象/数组字面量(如 `:class="{ male: p.sex == 1 }"`),或把结果先算进 data/computed 再绑定
|
||||
|
||||
22
pages.json
22
pages.json
@@ -7,17 +7,23 @@
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
|
||||
// 消息通知组件
|
||||
"^MessageNotification": "@/components/MessageNotification/MessageNotification.vue",
|
||||
"^FollowUpDrugDrawer$": "@/subPackages/doctor/components/FollowUpDrugDrawer.vue"
|
||||
"^FollowUpDrugDrawer$": "@/subPackages/doctor/components/FollowUpDrugDrawer.vue",
|
||||
// 列表骨架屏(分包组件,主包页需配合 componentPlaceholder)
|
||||
"^ListSkeleton$": "@/subPackages/common/components/ListSkeleton.vue"
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/home/home",
|
||||
"style": {
|
||||
// "navigationBarTitleText": "custom",
|
||||
"navigationStyle": "custom"
|
||||
"navigationStyle": "custom",
|
||||
// "navigationStyle": "default",
|
||||
// "navigationBarBackgroundColor": "#298DFF",
|
||||
// "navigationBarTextStyle": "white"
|
||||
// 主包异步引用分包 ListSkeleton
|
||||
"componentPlaceholder": {
|
||||
"list-skeleton": "view"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -53,7 +59,11 @@
|
||||
{
|
||||
"path": "pages/cate/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康资讯"
|
||||
"navigationBarTitleText": "健康资讯",
|
||||
// 主包异步引用分包 ListSkeleton
|
||||
"componentPlaceholder": {
|
||||
"list-skeleton": "view"
|
||||
}
|
||||
}
|
||||
// "needLogin": true
|
||||
},
|
||||
@@ -67,7 +77,11 @@
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息"
|
||||
"navigationBarTitleText": "消息",
|
||||
// 主包异步引用分包 ListSkeleton
|
||||
"componentPlaceholder": {
|
||||
"list-skeleton": "view"
|
||||
}
|
||||
}
|
||||
// "needLogin": true
|
||||
},
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
<!-- //药品分类左 -->
|
||||
<view class="goods">
|
||||
<view class="goods_left" @touchmove.stop>
|
||||
<scroll-view scroll-y scroll-with-animation class="u-menu-scroll-view" :scroll-top="scrollTop"
|
||||
<!-- 首次加载分类骨架 -->
|
||||
<ListSkeleton v-if="categoryInitialLoading" type="category" :rows="8" />
|
||||
<scroll-view v-else scroll-y scroll-with-animation class="u-menu-scroll-view" :scroll-top="scrollTop"
|
||||
:scroll-into-view="itemId">
|
||||
<view v-for="(item,index) in categoryLists" :key="item.id" class="u-tab-item"
|
||||
:class="[num == item.id ? 'u-item-active' : '']" @tap.stop="changeStyle(item.id)"
|
||||
@@ -26,7 +28,9 @@
|
||||
<view class="goods_right">
|
||||
<!-- 药品 -->
|
||||
<view class="second">
|
||||
<!-- 商品列表 -->
|
||||
<!-- 首次或切分类且当前无文章时展示骨架,有旧文章则保留至新结果 -->
|
||||
<ListSkeleton v-if="showArticleSkeleton" type="article" :rows="4" />
|
||||
<template v-else>
|
||||
<view class="list" v-for="(item,index) in infoList" @click="toDetail(item.id)" :key="item.id">
|
||||
<view class="list_">
|
||||
<image :src="item.cover||'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/xx/cp.png'" mode=""></image>
|
||||
@@ -35,6 +39,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -65,7 +70,18 @@
|
||||
selectIndex: 0,
|
||||
arr: [], // 储存距离顶部高度的数组
|
||||
scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
|
||||
show: false
|
||||
show: false,
|
||||
// 首次加载骨架
|
||||
categoryInitialLoading: true,
|
||||
articleInitialLoading: true,
|
||||
// 切分类且当前列表为空时拉文章期间展示骨架
|
||||
articleFetchingEmpty: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 是否展示右侧文章骨架:首次加载,或请求中且当前无文章可保留
|
||||
showArticleSkeleton() {
|
||||
return this.articleInitialLoading || this.articleFetchingEmpty
|
||||
}
|
||||
},
|
||||
onLoad(op) {
|
||||
@@ -86,14 +102,14 @@
|
||||
url: '/pages/cate/info-detail?id=' + e
|
||||
})
|
||||
},
|
||||
//点击药品一级分类e
|
||||
//点击药品一级分类e:不清空 infoList,有旧数据则保留到新结果返回
|
||||
handleCategory1(e, index) {
|
||||
this.num = e
|
||||
this.cid = e
|
||||
this.getArticleList()
|
||||
},
|
||||
|
||||
//获取药品分类
|
||||
//获取药品分类:成功后再覆盖,失败保留旧分类
|
||||
getList() {
|
||||
categoriesList({
|
||||
method: "post",
|
||||
@@ -101,12 +117,13 @@
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'list');
|
||||
if (res.data.code == 0) {
|
||||
const list = (res.data.result && res.data.result.list) || []
|
||||
this.categoryLists = list
|
||||
if (!list.length) {
|
||||
this.infoList = []
|
||||
this.articleInitialLoading = false
|
||||
this.articleFetchingEmpty = false
|
||||
return
|
||||
}
|
||||
const firstId = list[0].id
|
||||
@@ -114,10 +131,15 @@
|
||||
this.cid = firstId
|
||||
this.getArticleList()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.categoryInitialLoading = false
|
||||
})
|
||||
},
|
||||
// 文章列表
|
||||
// 文章列表:请求前不清空;仅当当前无文章可展示时打骨架标记
|
||||
getArticleList() {
|
||||
if (!this.infoList || this.infoList.length === 0) {
|
||||
this.articleFetchingEmpty = true
|
||||
}
|
||||
articleList({
|
||||
method: "get",
|
||||
data: {
|
||||
@@ -125,12 +147,12 @@
|
||||
cid: this.cid
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'list');
|
||||
if (res.data.code == 0) {
|
||||
this.infoList = (res.data.result && res.data.result.list) || []
|
||||
// console.log(res, 'list')
|
||||
}
|
||||
|
||||
}).finally(() => {
|
||||
this.articleInitialLoading = false
|
||||
this.articleFetchingEmpty = false
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -138,6 +160,7 @@
|
||||
// this.getList();
|
||||
},
|
||||
onShow() {
|
||||
// 不清空 categoryLists / infoList,成功后再替换
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,10 @@
|
||||
</view>
|
||||
|
||||
<!-- 2.5 金刚区 (Zone) - 支持滑动/换行切换 -->
|
||||
<view v-if="homeZones.length > 0" class="zone-wrapper" :class="zoneLayoutMode === 'scroll' ? 'zone-scroll-mode' : 'zone-wrap-mode'">
|
||||
<view v-if="homeZonesInitialLoading" class="zone-wrapper">
|
||||
<ListSkeleton type="zone" :rows="5" />
|
||||
</view>
|
||||
<view v-else-if="homeZones.length > 0" class="zone-wrapper" :class="zoneLayoutMode === 'scroll' ? 'zone-scroll-mode' : 'zone-wrap-mode'">
|
||||
<view v-for="(item, index) in homeZones" :key="index" class="zone-item" @click="goZoneList(item)">
|
||||
<view class="zone-icon-box">
|
||||
<image
|
||||
@@ -197,6 +200,9 @@
|
||||
<view class="section-more" @click="goYard(0)">更多 <text class="iconfont icon-jiantou1" style="font-size: 20rpx;"></text></view>
|
||||
</view>
|
||||
|
||||
<!-- 首次加载展示骨架,刷新时保留旧列表避免闪空 -->
|
||||
<ListSkeleton v-if="doctorListInitialLoading" type="doctor" :rows="3" />
|
||||
<template v-else>
|
||||
<view class="doctor-card" @click="goLookDoctor(item.id)" v-for="(item,index) in doctorList" :key="item.id">
|
||||
<view class="doc-main">
|
||||
<view class="doc-avatar-box">
|
||||
@@ -232,6 +238,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<!-- 5. 药店模式内容:热销好药 -->
|
||||
@@ -243,6 +250,8 @@
|
||||
|
||||
<!-- 优化后的药品列表:使用计算属性 displayProductList 解决循环报错 -->
|
||||
<view class="product-list-container">
|
||||
<ListSkeleton v-if="productListInitialLoading" type="product" :rows="3" />
|
||||
<template v-else>
|
||||
<view class="product-card" @click="goProductDetail(item)" v-for="(item, index) in displayProductList" :key="index">
|
||||
<view class="prod-img-box">
|
||||
<image :src="(item.drug && item.drug.image) ? item.drug.image : 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/mine/avatar_1.png'" mode="aspectFill" class="prod-img" :class="{ 'prescription-blur': item.drug && item.drug.type == 2 && (item.drug.is_otc === 0 || item.drug.is_otc === '0') }"></image>
|
||||
@@ -269,6 +278,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<!-- 6. 资质证明 -->
|
||||
@@ -332,6 +342,10 @@ export default {
|
||||
doctorList: [],
|
||||
productList: [],
|
||||
homeZones: [],
|
||||
// 首次加载骨架标记:仅第一次请求结束前为 true,刷新时保留旧数据不闪空
|
||||
doctorListInitialLoading: true,
|
||||
productListInitialLoading: true,
|
||||
homeZonesInitialLoading: true,
|
||||
topProductsTitle: '热销商品',
|
||||
topProductsList: [],
|
||||
qualifications: [],
|
||||
@@ -683,7 +697,7 @@ export default {
|
||||
})
|
||||
},
|
||||
getList() {
|
||||
this.doctorList = [];
|
||||
// 不再请求前清空 doctorList,避免 onShow 刷新时出现「先空后满」
|
||||
doctorList({
|
||||
method: "post",
|
||||
data: { store_id: uni.getStorageSync('store_id') || '11001' }
|
||||
@@ -699,6 +713,8 @@ export default {
|
||||
const responseData = isGuest && res.data.result ? res.data.result : res.data.data;
|
||||
this.doctorList = (responseData.list || []).slice(0, 5)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.doctorListInitialLoading = false
|
||||
})
|
||||
},
|
||||
toChang(e) {
|
||||
@@ -750,6 +766,9 @@ export default {
|
||||
if (res.data.code == 0) {
|
||||
this.productList = res.data.result.records;
|
||||
}
|
||||
}).finally(() => {
|
||||
// top 与 product 任一返回即可结束首次骨架(见 getHomeTopProducts)
|
||||
this._markProductInitialLoaded()
|
||||
})
|
||||
},
|
||||
getHomeTopProducts() {
|
||||
@@ -761,8 +780,17 @@ export default {
|
||||
this.topProductsTitle = result.title || '热销商品';
|
||||
this.topProductsList = result.list || [];
|
||||
}
|
||||
}).finally(() => {
|
||||
this._markProductInitialLoaded()
|
||||
})
|
||||
},
|
||||
// 商品区依赖 topProducts 或 productList,两者都结束首次请求后再关骨架
|
||||
_markProductInitialLoaded() {
|
||||
this._productFetchDone = (this._productFetchDone || 0) + 1
|
||||
if (this._productFetchDone >= 2) {
|
||||
this.productListInitialLoading = false
|
||||
}
|
||||
},
|
||||
getHomeZones() {
|
||||
getHomeZonesApi({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
@@ -770,7 +798,14 @@ export default {
|
||||
if (res.data.code == 0) {
|
||||
this.homeZones = res.data.result || res.data.data || [];
|
||||
}
|
||||
}).catch(() => { this.homeZones = []; })
|
||||
}).catch(() => {
|
||||
// 仅尚无数据时清空,避免刷新失败抹掉已有专区
|
||||
if (!this.homeZones || this.homeZones.length === 0) {
|
||||
this.homeZones = [];
|
||||
}
|
||||
}).finally(() => {
|
||||
this.homeZonesInitialLoading = false
|
||||
})
|
||||
},
|
||||
getPlatformQualifications() {
|
||||
getPlatformQualificationsApi({
|
||||
@@ -965,12 +1000,12 @@ $card-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.04);
|
||||
&:active { transform: scale(0.95); }
|
||||
.zone-icon-box {
|
||||
width: 100rpx; height: 100rpx;
|
||||
background: linear-gradient(180deg, #FFFFFF 0%, #F5F9FF 100%);
|
||||
//background: linear-gradient(180deg, #FFFFFF 0%, #F5F9FF 100%);
|
||||
border-radius: 36rpx;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(65, 117, 238, 0.08);
|
||||
//box-shadow: 0 8rpx 24rpx rgba(65, 117, 238, 0.08);
|
||||
margin-bottom: 12rpx;
|
||||
.zone-img { width: 56rpx; height: 56rpx; }
|
||||
.zone-img { width: 100rpx; height: 100rpx; }
|
||||
}
|
||||
.zone-text { font-size: 24rpx; color: #555; font-weight: 500; }
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 首次加载:四条固定入口用骨架,避免 num 未定义时闪「暂无新消息」 -->
|
||||
<ListSkeleton v-if="noticeInitialLoading" type="message" :rows="4" />
|
||||
<template v-else>
|
||||
<!-- 消息列表 -->
|
||||
<view class="list" @click="goSystem">
|
||||
<!-- 头像 -->
|
||||
@@ -91,7 +94,6 @@
|
||||
<view class="avator">
|
||||
<view class="img">
|
||||
<image src="https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/xx/ysxx.png" mode=""></image>
|
||||
<!-- <image src="https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/xx/zhuanzhen.png" mode=""></image>-->
|
||||
</view>
|
||||
<u-badge size="default" v-if="transfer.num>=0" :count="transfer.num" :is-dot="transfer.num==0?true:false"
|
||||
type="error" :offset="transfer.num>0?[-4,-8]:[0,0]"></u-badge>
|
||||
@@ -110,13 +112,18 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 模拟<u-divider>在线问诊</u-divider>效果-->
|
||||
</template>
|
||||
|
||||
<!-- 标题 - 在线咨询 -->
|
||||
<view v-if="checkDev('open-im') && onlineConsultationList.length > 0" class="title">
|
||||
<text>在线咨询</text>
|
||||
</view>
|
||||
<!-- IM 会话首次骨架:有旧数据时直接展示旧列表直至替换 -->
|
||||
<ListSkeleton
|
||||
v-if="checkDev('open-im') && chatInitialLoading && onlineConsultationList.length === 0 && onlineReconsultationList.length === 0"
|
||||
type="message"
|
||||
:rows="3"
|
||||
/>
|
||||
<!-- 在线咨询 - 用户 (type=1) -->
|
||||
<view v-if="checkDev('open-im')" v-for="(item, index) in onlineConsultationList" :key="item.id" class="list" @click="goChat(item, index)">
|
||||
<!-- 头像 -->
|
||||
@@ -136,7 +143,6 @@
|
||||
</view>
|
||||
<view class="preview">
|
||||
<p>{{ item.last_message }}</p>
|
||||
<!-- <p v-if="item.un_read_count>0">您有{{item.un_read_count}}条新的消息</p>-->
|
||||
</view>
|
||||
<view class="preview" v-if="item.last_message===''">
|
||||
暂无新消息
|
||||
@@ -167,7 +173,6 @@
|
||||
</view>
|
||||
<view class="preview">
|
||||
<p>{{ item.last_message }}</p>
|
||||
<!-- <p v-if="item.un_read_count>0">您有{{item.un_read_count}}条新的消息</p>-->
|
||||
</view>
|
||||
<view class="preview" v-if="item.last_message===''">
|
||||
暂无新消息
|
||||
@@ -203,7 +208,10 @@ export default {
|
||||
imChat: [],
|
||||
onlineConsultationList: [], // 在线咨询列表 (type=1)
|
||||
onlineReconsultationList: [], // 在线复诊列表 (type=3)
|
||||
type: ""
|
||||
type: "",
|
||||
// 首次加载骨架:刷新时不再清空数据,故仅首次为 true
|
||||
noticeInitialLoading: true,
|
||||
chatInitialLoading: true
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
@@ -235,7 +243,6 @@ export default {
|
||||
type: "all"
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'res');
|
||||
uni.showToast({
|
||||
title: '清除成功',
|
||||
duration: 2000,
|
||||
@@ -257,7 +264,6 @@ export default {
|
||||
type: "system"
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'res');
|
||||
})
|
||||
},
|
||||
// 详情
|
||||
@@ -272,7 +278,6 @@ export default {
|
||||
type: "order"
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'res');
|
||||
})
|
||||
},
|
||||
goDoctor() {
|
||||
@@ -286,7 +291,6 @@ export default {
|
||||
type: "doctor_news"
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'res');
|
||||
})
|
||||
},
|
||||
// 转诊消息
|
||||
@@ -299,17 +303,8 @@ export default {
|
||||
uni.navigateTo({
|
||||
url: `/subPackages/chat/chat?room_id=${item.room_id}&nick_name=${item.nick_name}&user_id=${item.id}&avatar=${encodeURIComponent(item.avatar || '')}&room_status=${item.room_status || 0}`
|
||||
})
|
||||
// getseesionRead({
|
||||
// method: "post",
|
||||
// data: {
|
||||
// store_id: uni.getStorageSync('store_id') || 11001,
|
||||
// type: "doctor_news"
|
||||
// }
|
||||
// }).then((res) => {
|
||||
// // console.log(res, 'res');
|
||||
// })
|
||||
},
|
||||
//
|
||||
// 获取系统/订单/医生消息概览;成功才覆盖,失败保留旧数据
|
||||
async getInfo() {
|
||||
try {
|
||||
const res = await getSystemNoticeIndexApi({
|
||||
@@ -322,8 +317,11 @@ export default {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取消息概览失败:', error)
|
||||
} finally {
|
||||
this.noticeInitialLoading = false
|
||||
}
|
||||
},
|
||||
// 拉取 IM 好友会话列表,成功后整份替换,失败不写空
|
||||
getMyChatFriendsList() {
|
||||
getChatFriendsListApi().then((res) => {
|
||||
const allChatList = res.data.result || []
|
||||
@@ -332,9 +330,13 @@ export default {
|
||||
this.onlineReconsultationList = allChatList.filter(item => (item.type === 3 || item.type === 2)) // type=3的为在线复诊
|
||||
// 保持imChat兼容性(包含所有)
|
||||
this.imChat = allChatList
|
||||
}).catch((error) => {
|
||||
console.error('获取聊天列表失败:', error)
|
||||
}).finally(() => {
|
||||
this.chatInitialLoading = false
|
||||
})
|
||||
},
|
||||
// 获取转诊消息列表
|
||||
// 获取转诊消息列表;失败不重置 transfer,避免闪空
|
||||
getTransferList() {
|
||||
getTransferPrescriptionListApi().then((res) => {
|
||||
if (res.data && res.data.code == 0) {
|
||||
@@ -362,15 +364,7 @@ export default {
|
||||
this.getInfo()
|
||||
},
|
||||
onShow() {
|
||||
this.order = []
|
||||
this.system = []
|
||||
this.doctor = []
|
||||
this.transfer = {
|
||||
num: 0,
|
||||
time: ''
|
||||
}
|
||||
this.onlineConsultationList = []
|
||||
this.onlineReconsultationList = []
|
||||
// 不再清空列表:保留旧 UI,接口成功后再覆盖
|
||||
this.getInfo()
|
||||
this.getMyChatFriendsList()
|
||||
this.getTransferList()
|
||||
|
||||
@@ -515,10 +515,10 @@ export async function postRefundBased(params) {
|
||||
// return data
|
||||
|
||||
// }
|
||||
/** 物流详情 → xk-api mobile(含多包裹 packages) */
|
||||
export async function getLogistics(params) {
|
||||
let data = await http('/oldApi/v1/product-order/express', params)
|
||||
return data
|
||||
|
||||
let data = await http('/xkApi/product-order/express', params)
|
||||
return normalizeXkApiResponse(data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -80,17 +80,21 @@ 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",
|
||||
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: "https://test.xk.app.nailaoyun.cn/member",
|
||||
xkApi: "https://test.xk.api.nailaoyun.cn/api/mobile",
|
||||
shop: "https://test.xk.shop.nailaoyun.cn/member",
|
||||
im: "https://api.ws.g.nailaoyun.cn/api"
|
||||
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: {
|
||||
|
||||
@@ -59,15 +59,17 @@
|
||||
>
|
||||
<view class="message-list-container" id="msglist" :style="{ paddingBottom: (keyboardHeight > 0 ? keyboardHeight + 10 : 0) + 'px' }">
|
||||
|
||||
<!-- 协议提示信息 -->
|
||||
<!-- 协议提示信息:协议名单独节点绑定点击,避免嵌套 text 吞事件 -->
|
||||
<view class="notice-box" v-if="showNotice">
|
||||
<view class="notice-text">
|
||||
<text v-for="(part, index) in parsedNoticeParts" :key="index">
|
||||
<block v-for="(part, index) in parsedNoticeParts" :key="index">
|
||||
<text v-if="part.type === 'text'">{{ part.text }}</text>
|
||||
<text v-else-if="part.type === 'agreement'" class="notice-link" @click="viewAgreement(part.agreementId)">
|
||||
《{{ part.text }}》
|
||||
</text>
|
||||
</text>
|
||||
<text
|
||||
v-else-if="part.type === 'agreement'"
|
||||
class="notice-link"
|
||||
@click.stop="viewAgreement(part.agreementId)"
|
||||
>《{{ part.text }}》</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -103,6 +105,7 @@
|
||||
@goToOrderMedicine="goToOrderMedicine"
|
||||
@viewOrder="viewOrder"
|
||||
@followUpDrugAnswered="onFollowUpDrugAnswered"
|
||||
@avatarClick="goDoctorDetail(msg)"
|
||||
/>
|
||||
|
||||
</view>
|
||||
@@ -115,9 +118,10 @@
|
||||
<view style="height: 180rpx;"></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 协议抽屉 -->
|
||||
<!-- 协议抽屉:v-if 控制挂载,:show 控制显隐(微信 page-container 要求) -->
|
||||
<page-container
|
||||
:if="showAgreement"
|
||||
v-if="showAgreement"
|
||||
:show="showAgreement"
|
||||
position="bottom"
|
||||
round
|
||||
overlay
|
||||
@@ -295,6 +299,8 @@ export default {
|
||||
this.doctorUserInfo = option;
|
||||
if (option.avatar) this.doctorAvatar = option.avatar;
|
||||
this.currentUserId = 'user-' + uni.getStorageSync('user_id') || 'user-2512';
|
||||
// 从登录缓存读取己方微信/用户头像,避免一直用硬编码占位图
|
||||
this.syncUserAvatar();
|
||||
|
||||
let doctorId = option.user_id || '';
|
||||
if (doctorId.includes('-type-')) doctorId = doctorId.split('-type-')[0];
|
||||
@@ -352,6 +358,8 @@ export default {
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 从资料页返回时再同步一次,避免改过头像后聊天仍显示旧图
|
||||
this.syncUserAvatar();
|
||||
// 确保房间ID已设置(从ChatManager获取,作为备用)
|
||||
if (!this.doctorUserInfo.room_id && typeof ChatManager !== 'undefined') {
|
||||
const currentRoomId = ChatManager.getCurrentRoomId();
|
||||
@@ -391,6 +399,16 @@ export default {
|
||||
|
||||
methods: {
|
||||
// === 新增辅助方法 ===
|
||||
/**
|
||||
* 从本地 userinfo 同步己方头像(字段为 avatarurl,与登录/我的页一致)
|
||||
* 无头像时回退到与我的页相同的默认图
|
||||
*/
|
||||
syncUserAvatar() {
|
||||
const userinfo = uni.getStorageSync('userinfo') || {};
|
||||
this.userAvatar = userinfo.avatarurl
|
||||
|| 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/mine/mr_tx.png';
|
||||
},
|
||||
|
||||
isMsgMine(msg) {
|
||||
return this.getSenderIdWithoutPrefix(msg.sender_user_id) === this.getCurrentUserIdWithoutPrefix();
|
||||
},
|
||||
@@ -495,22 +513,20 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// 查找匹配的协议
|
||||
// 查找匹配的协议:名称/描述双向 includes,仍无匹配则用列表第一条保证可点
|
||||
const agreementName = match[1];
|
||||
const agreement = this.agreements.find(ag => ag.name === agreementName || ag.name.includes(agreementName));
|
||||
const agreement = this.findAgreementByName(agreementName);
|
||||
|
||||
if (agreement) {
|
||||
// 找到匹配的协议,添加为可点击的链接
|
||||
parts.push({
|
||||
type: 'agreement',
|
||||
text: agreementName,
|
||||
agreementId: agreement.id
|
||||
});
|
||||
} else {
|
||||
// 没找到匹配的协议,作为普通文本显示
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: match[0] // 《协议名称》
|
||||
text: match[0]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -527,6 +543,24 @@ export default {
|
||||
|
||||
this.parsedNoticeParts = parts;
|
||||
},
|
||||
/**
|
||||
* 按文案中的协议名匹配协议列表(放宽 name/desc 双向包含)
|
||||
* 匹配不到但列表非空时回退第一条,避免《》无法点击
|
||||
*/
|
||||
findAgreementByName(agreementName) {
|
||||
const list = this.agreements || [];
|
||||
if (!list.length) return null;
|
||||
const name = String(agreementName || '');
|
||||
const hit = list.find((ag) => {
|
||||
const n = String(ag.name || '');
|
||||
const d = String(ag.desc || '');
|
||||
return n === name
|
||||
|| n.includes(name)
|
||||
|| name.includes(n)
|
||||
|| (d && (d === name || d.includes(name) || name.includes(d)));
|
||||
});
|
||||
return hit || list[0];
|
||||
},
|
||||
// 查看协议
|
||||
async viewAgreement(agreementId) {
|
||||
if (!agreementId) {
|
||||
@@ -541,6 +575,7 @@ export default {
|
||||
const agreement = this.agreements.find(ag => ag.id === agreementId);
|
||||
this.currentAgreementId = agreementId;
|
||||
this.currentAgreementName = agreement ? agreement.name : '协议详情';
|
||||
this.agreementContent = '';
|
||||
this.showAgreement = true;
|
||||
|
||||
try {
|
||||
@@ -569,6 +604,26 @@ export default {
|
||||
this.showAgreement = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击气泡医生头像进入医生详情(只读,不展示挂号)
|
||||
* 己方/助理头像不跳转
|
||||
*/
|
||||
goDoctorDetail(msg) {
|
||||
if (!msg || this.isMsgMine(msg)) return;
|
||||
const senderId = msg.sender_user_id || msg.senderId || '';
|
||||
if (senderId === 'doctor_assistant') return;
|
||||
const cleanId = String(this.doctorId || '')
|
||||
.replace(/^doctor-/, '')
|
||||
.replace(/-type-.*$/, '');
|
||||
if (!cleanId) {
|
||||
uni.showToast({ title: '医生信息缺失', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/subPackages/doctor/doctor-detail?id=${cleanId}&readonly=1`
|
||||
});
|
||||
},
|
||||
|
||||
// === 音频播放逻辑 ===
|
||||
playAudio(msg) {
|
||||
const audioUrl = getParsedContent(msg.message_type, msg.message_content);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="bubble-container" :class="{ 'mine': isMine, 'other': !isMine }">
|
||||
<!-- 头像 -->
|
||||
<image class="avatar" :src="avatar" mode="aspectFill"></image>
|
||||
<!-- 头像:非己方可点进医生详情 -->
|
||||
<image class="avatar" :src="avatar" mode="aspectFill" @click.stop="onAvatarClick"></image>
|
||||
|
||||
<!-- 消息内容包裹 -->
|
||||
<view class="content-wrapper">
|
||||
@@ -146,13 +146,22 @@
|
||||
<text class="block-label">主诉</text>
|
||||
<text class="block-content">{{ parsedContent.chief_complaint }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="registerCardDrugNamesLine">
|
||||
<text class="label">所选药品</text>
|
||||
<text class="value">{{ registerCardDrugNamesLine }}</text>
|
||||
<view v-if="registerCardDrugRows.length" class="drug-list-block">
|
||||
<text class="block-label">所选药品</text>
|
||||
<view v-for="row in registerCardDrugRows" :key="row._wxKey" class="info-row drug-spec-row">
|
||||
<image
|
||||
v-if="row.image"
|
||||
class="drug-thumb"
|
||||
:src="row.image"
|
||||
mode="aspectFill"
|
||||
@click.stop="$emit('previewImage', row.image)"
|
||||
/>
|
||||
<view class="drug-name-wrap">
|
||||
<text class="label">{{ row.name || '药品' }}</text>
|
||||
<text v-if="row.specification" class="spec-text">{{ row.specification }}</text>
|
||||
</view>
|
||||
<text class="value">×{{ row.quantity }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="parsedContent.number != null && parsedContent.number !== ''">
|
||||
<text class="label">数量</text>
|
||||
<text class="value">各 {{ parsedContent.number }} 盒</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer"><button class="action-btn" @click="$emit('viewRegister', parsedContent.id)">查看详情</button></view>
|
||||
@@ -314,17 +323,38 @@ export default {
|
||||
}
|
||||
return message_content;
|
||||
},
|
||||
/** 挂号卡片:多选西药名称串联,无则单药 drug.name */
|
||||
registerCardDrugNamesLine() {
|
||||
if (this.msg.message_type !== 10) return '';
|
||||
/**
|
||||
* 预约挂号卡片药品行:药名 + 规格 + 数量(与医生端一致,去掉底部「各 X 盒」)
|
||||
*/
|
||||
registerCardDrugRows() {
|
||||
if (this.msg.message_type !== 10) return [];
|
||||
const pc = this.parsedContent;
|
||||
if (!pc || typeof pc !== 'object') return '';
|
||||
if (!pc || typeof pc !== 'object') return [];
|
||||
const fallbackQty = pc.number != null && pc.number !== '' ? Number(pc.number) : 1;
|
||||
const arr = pc.selected_western_drugs;
|
||||
if (Array.isArray(arr) && arr.length) {
|
||||
return arr.map((d) => d && d.name).filter(Boolean).join('、');
|
||||
return arr.map((d, idx) => {
|
||||
const q = d && d.quantity != null ? Number(d.quantity) : fallbackQty;
|
||||
const id = d && (d.drug_id || d.id);
|
||||
return {
|
||||
_wxKey: 'rd-' + (id != null ? id : idx),
|
||||
name: (d && d.name) || '',
|
||||
specification: (d && (d.specification || d.spec || d.drug_spec)) || '',
|
||||
image: (d && (d.image || d.drug_image)) || '',
|
||||
quantity: q >= 1 ? q : 1,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (pc.drug && pc.drug.name) return pc.drug.name;
|
||||
return '';
|
||||
if (pc.drug && pc.drug.name) {
|
||||
return [{
|
||||
_wxKey: 'rd-' + (pc.drug.drug_id || pc.drug.id || 0),
|
||||
name: pc.drug.name,
|
||||
specification: pc.drug.specification || pc.drug.spec || '',
|
||||
image: pc.drug.image || pc.drug.drug_image || '',
|
||||
quantity: fallbackQty >= 1 ? fallbackQty : 1,
|
||||
}];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
followUpAnsweredLabel() {
|
||||
const pc = this.parsedContent;
|
||||
@@ -336,6 +366,13 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 非己方头像点击:通知父页跳转医生详情;己方头像不响应
|
||||
*/
|
||||
onAvatarClick() {
|
||||
if (this.isMine) return;
|
||||
this.$emit('avatarClick');
|
||||
},
|
||||
// 计算语音条宽度 (Min: 100rpx, Max: 350rpx, Unit: 10rpx/sec)
|
||||
getAudioWidth(duration) {
|
||||
const min = 120;
|
||||
@@ -609,6 +646,40 @@ $success-color: #059669;
|
||||
.price { color: #ef4444; font-size: 28rpx; font-weight: bold; }
|
||||
.small { font-size: 22rpx; color: #999; }
|
||||
}
|
||||
.drug-spec-row {
|
||||
align-items: flex-start;
|
||||
.drug-thumb {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #f3f4f6;
|
||||
flex-shrink: 0;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
.drug-name-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.spec-text {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #9ca3af;
|
||||
font-weight: 400;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
.drug-list-block {
|
||||
.block-label {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #888;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
}
|
||||
.desc-text { font-size: 26rpx; color: #333; }
|
||||
.text-block {
|
||||
background: #f5f5f5; padding: 16rpx; border-radius: 8rpx;
|
||||
|
||||
275
subPackages/common/components/ListSkeleton.vue
Normal file
275
subPackages/common/components/ListSkeleton.vue
Normal file
@@ -0,0 +1,275 @@
|
||||
<template>
|
||||
<!--
|
||||
列表骨架屏:按 type 模拟医生卡/消息行/商品卡/资讯卡/分类侧栏,
|
||||
放在分包以控制主包体积,主包页通过 componentPlaceholder 异步引用。
|
||||
-->
|
||||
<view class="list-skeleton" :class="'list-skeleton--' + type">
|
||||
<view
|
||||
v-for="i in rowCount"
|
||||
:key="i"
|
||||
class="sk-row"
|
||||
:class="'sk-row--' + type"
|
||||
>
|
||||
<!-- 医生推荐卡片 -->
|
||||
<template v-if="type === 'doctor'">
|
||||
<view class="sk-avatar sk-shimmer"></view>
|
||||
<view class="sk-body">
|
||||
<view class="sk-line sk-line--lg sk-shimmer"></view>
|
||||
<view class="sk-line sk-line--md sk-shimmer"></view>
|
||||
<view class="sk-line sk-line--sm sk-shimmer"></view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 消息列表行 -->
|
||||
<template v-else-if="type === 'message'">
|
||||
<view class="sk-avatar sk-avatar--round sk-shimmer"></view>
|
||||
<view class="sk-body">
|
||||
<view class="sk-line-row">
|
||||
<view class="sk-line sk-line--md sk-shimmer"></view>
|
||||
<view class="sk-line sk-line--xs sk-shimmer"></view>
|
||||
</view>
|
||||
<view class="sk-line sk-line--sm sk-shimmer"></view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 商品卡片 -->
|
||||
<template v-else-if="type === 'product'">
|
||||
<view class="sk-prod-img sk-shimmer"></view>
|
||||
<view class="sk-body">
|
||||
<view class="sk-line sk-line--lg sk-shimmer"></view>
|
||||
<view class="sk-line sk-line--sm sk-shimmer"></view>
|
||||
<view class="sk-line sk-line--md sk-shimmer"></view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 资讯文章卡片 -->
|
||||
<template v-else-if="type === 'article'">
|
||||
<view class="sk-cover sk-shimmer"></view>
|
||||
<view class="sk-cover-title sk-shimmer"></view>
|
||||
</template>
|
||||
<!-- 资讯左侧分类 -->
|
||||
<template v-else-if="type === 'category'">
|
||||
<view class="sk-cate-item sk-shimmer"></view>
|
||||
</template>
|
||||
<!-- 金刚区横滑块 -->
|
||||
<template v-else-if="type === 'zone'">
|
||||
<view class="sk-zone-icon sk-shimmer"></view>
|
||||
<view class="sk-line sk-line--xs sk-shimmer"></view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ListSkeleton',
|
||||
props: {
|
||||
// 骨架样式类型
|
||||
type: {
|
||||
type: String,
|
||||
default: 'message',
|
||||
validator(v) {
|
||||
return ['doctor', 'message', 'product', 'article', 'category', 'zone'].indexOf(v) !== -1
|
||||
}
|
||||
},
|
||||
// 行数
|
||||
rows: {
|
||||
type: [Number, String],
|
||||
default: 3
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rowCount() {
|
||||
const n = Number(this.rows)
|
||||
return n > 0 ? n : 3
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-skeleton {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sk-shimmer {
|
||||
background: linear-gradient(90deg, #ebebeb 25%, #f5f5f5 50%, #ebebeb 75%);
|
||||
background-size: 400% 100%;
|
||||
animation: sk-shimmer 1.4s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes sk-shimmer {
|
||||
0% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-row--doctor {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin: 0 24rpx 20rpx;
|
||||
padding: 28rpx;
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
|
||||
.sk-avatar {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.sk-body {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-row--message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 32rpx 38rpx;
|
||||
background: #fff;
|
||||
|
||||
.sk-avatar {
|
||||
width: 84rpx;
|
||||
height: 84rpx;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.sk-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sk-line-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-row--product {
|
||||
display: flex;
|
||||
margin: 0 24rpx 20rpx;
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
|
||||
.sk-prod-img {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
flex-shrink: 0;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.sk-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-row--article {
|
||||
position: relative;
|
||||
width: 500rpx;
|
||||
height: 246rpx;
|
||||
margin: 10rpx auto;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.sk-cover {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.sk-cover-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 92rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-row--category {
|
||||
width: 184rpx;
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #fff;
|
||||
|
||||
.sk-cate-item {
|
||||
width: 100rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.list-skeleton--zone {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding: 16rpx 24rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sk-row--zone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 140rpx;
|
||||
flex-shrink: 0;
|
||||
margin-right: 16rpx;
|
||||
|
||||
.sk-zone-icon {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.sk-line--xs {
|
||||
width: 72rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-line {
|
||||
height: 24rpx;
|
||||
border-radius: 6rpx;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sk-line--lg {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.sk-line--md {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.sk-line--sm {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.sk-line--xs {
|
||||
width: 80rpx;
|
||||
height: 20rpx;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sk-line-row .sk-line--md {
|
||||
width: 40%;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because one or more lines are too long
@@ -36,8 +36,8 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 到店医生 预约挂号 -->
|
||||
<view class="appoin">
|
||||
<!-- 到店医生 预约挂号:聊天室只读进入时不展示挂号入口 -->
|
||||
<view class="appoin" v-if="!readonly">
|
||||
<view class="title">预约挂号</view>
|
||||
<view class="list">
|
||||
<view class="yard">
|
||||
@@ -121,10 +121,13 @@
|
||||
registList: [],
|
||||
peopleList: [],
|
||||
rType: '0', // 挂号类型
|
||||
// 聊天室等场景只读查看:隐藏挂号按钮区
|
||||
readonly: false,
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
console.log(e, 'e');
|
||||
this.readonly = e.readonly === '1' || e.readonly === 1;
|
||||
// 允许未登录访问,移除登录跳转
|
||||
// 如果是guest模式,强制设置store_id为11001
|
||||
if (isGuestMode()) {
|
||||
@@ -148,7 +151,10 @@
|
||||
this.doctorID = uni.getStorageSync('doctors_id')
|
||||
this.getDocdetail();
|
||||
this.getUser();
|
||||
// 只读模式不拉号源,避免无用请求
|
||||
if (!this.readonly) {
|
||||
this.getRegist();
|
||||
}
|
||||
console.log(this.doctorID, '6666');
|
||||
|
||||
} else {
|
||||
@@ -159,7 +165,9 @@
|
||||
if (isGuestMode()) {
|
||||
uni.setStorageSync('store_id', '11001');
|
||||
this.getDocdetail();
|
||||
if (!this.readonly) {
|
||||
this.getRegist();
|
||||
}
|
||||
} else {
|
||||
const id = e.sts_id || uni.getStorageSync('store_id')
|
||||
if (id!='undefined' && id) {
|
||||
@@ -179,6 +187,8 @@
|
||||
},
|
||||
// 挂号
|
||||
goAdd() {
|
||||
// 只读模式不允许挂号
|
||||
if (this.readonly) return;
|
||||
// 如果未登录,保存跳转信息并跳转到登录页
|
||||
if (!isLoggedIn()) {
|
||||
const storeId = uni.getStorageSync('store_id') || '11001';
|
||||
@@ -345,8 +355,11 @@
|
||||
mounted() {
|
||||
this.getDocdetail();
|
||||
this.getUser();
|
||||
// 只读模式不拉号源/就诊人相关挂号数据
|
||||
if (!this.readonly) {
|
||||
this.getRegist();
|
||||
this.getPeople();
|
||||
}
|
||||
|
||||
if (!this.doctorList && doctorID) {
|
||||
this.getDocdetail();
|
||||
|
||||
@@ -132,6 +132,10 @@
|
||||
|
||||
<!-- 按钮区完全保留你原有的判断逻辑 -->
|
||||
<view class="choose_btn">
|
||||
<view class="order_info active" v-if="item.is_pay==0 && item.status==0 && item.cancel_status==0"
|
||||
@tap.stop="goCancel(item.id)">
|
||||
取消
|
||||
</view>
|
||||
<view class="order_info active" v-if="item.status==1 && item.is_pay==1 && item.forbiddenRefund==0"
|
||||
@tap.stop="toCancel(item.id,item.status,refundType)">
|
||||
退款
|
||||
@@ -164,10 +168,6 @@
|
||||
查看物流
|
||||
</view>
|
||||
|
||||
<view class="order_info active" v-if="item.is_pay==0 && item.status==0 && item.cancel_status==0"
|
||||
@tap.stop="goCancel(item.id)">
|
||||
取消
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-loadmore :status="loadMoreStatus" v-if="orderList.length!=0" margin-top="30" margin-bottom="30" />
|
||||
|
||||
@@ -91,10 +91,26 @@
|
||||
this.mobile = res.data.data.user.mobile
|
||||
this.idCard = res.data.data.user.idcard
|
||||
this._securityBaseline = { name: this.name }
|
||||
// 写回本地 userinfo,保证聊天室等页面能读到最新头像
|
||||
this.syncUserinfoStorage(res.data.data.user)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 将最新用户资料合并进本地 userinfo(尤其是 avatarurl)
|
||||
* 登录时存的是整份 user,此处只覆盖接口返回的字段,避免丢掉其它缓存键
|
||||
*/
|
||||
syncUserinfoStorage(user) {
|
||||
if (!user) return
|
||||
const cached = uni.getStorageSync('userinfo') || {}
|
||||
uni.setStorageSync('userinfo', {
|
||||
...cached,
|
||||
...user,
|
||||
avatarurl: user.avatarurl || cached.avatarurl || ''
|
||||
})
|
||||
},
|
||||
|
||||
// 点击头像触发click事件 changeUserPhoto
|
||||
async changeUserPhoto() {
|
||||
console.log('进入更新头像的功能')
|
||||
@@ -198,6 +214,13 @@
|
||||
icon: "success",
|
||||
title: '保存成功'
|
||||
})
|
||||
// 先写回 storage,再拉详情,避免聊天页 onShow 读到旧头像
|
||||
const cached = uni.getStorageSync('userinfo') || {}
|
||||
uni.setStorageSync('userinfo', {
|
||||
...cached,
|
||||
avatarurl: req.data.url
|
||||
})
|
||||
this.avatar = req.data.url
|
||||
this.getInfo()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<image :src="data.store['offical_seal'] ||''" mode=""></image>
|
||||
<view class="record_yard">
|
||||
<view class="yard">
|
||||
{{data.store.name}}
|
||||
{{ storeDisplayName }}
|
||||
</view>
|
||||
<view class="state">
|
||||
处方笺
|
||||
@@ -359,8 +359,16 @@
|
||||
getUseWay
|
||||
} from '../../request/api/api'
|
||||
import { checkImageUrl } from '../../utils/utils'
|
||||
import { formatStoreNameWithHu } from '../../utils/formatStoreNameWithHu.js'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
/** 在线处方诊所名加(互) */
|
||||
storeDisplayName() {
|
||||
const store = this.data && this.data.store ? this.data.store : {}
|
||||
return formatStoreNameWithHu(store.name, this.data && this.data.is_online)
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusName: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view class="container safe-area-inset-bottom">
|
||||
<MessageNotification />
|
||||
<!-- 收货地址 -->
|
||||
<view class="head" v-if="logisticsList.express_name!=''">
|
||||
<view class="head" v-if="logisticsList.express_name">
|
||||
<image src="https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/mine/mr_tx.png" mode=""></image>
|
||||
<view class="head_info">
|
||||
<view class="name">{{logisticsList.express_name}} {{logisticsList.express_mobile_tm || logisticsList.express_mobile}}</view>
|
||||
@@ -10,73 +10,140 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="infos" v-if="express!=''">
|
||||
<!-- 多包裹 Tab:无 warehouse_name 时只显示包裹序号 -->
|
||||
<scroll-view v-if="packages.length > 1" class="pkg-tabs" scroll-x>
|
||||
<view
|
||||
v-for="(pkg, idx) in packages"
|
||||
:key="idx"
|
||||
class="pkg-tab"
|
||||
:class="{ active: activePkg === idx }"
|
||||
@click="switchPkg(idx)"
|
||||
>
|
||||
包裹{{ pkg.package_no || idx + 1 }}
|
||||
<text v-if="pkg.warehouse_name" class="pkg-sub">{{ pkg.warehouse_name }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 多包裹:左右滑动切换;单包直接展示 -->
|
||||
<swiper
|
||||
v-if="packages.length > 1"
|
||||
class="pkg-swiper"
|
||||
:current="activePkg"
|
||||
:style="{ height: swiperHeight + 'px' }"
|
||||
@change="onSwiperChange"
|
||||
>
|
||||
<swiper-item v-for="(pkg, idx) in packages" :key="idx">
|
||||
<view class="pkg-panel" :id="'pkg-panel-' + idx">
|
||||
<view class="infos" v-if="pkgExpress(pkg).express_no">
|
||||
<view class="_info">
|
||||
<text>快递单号</text>
|
||||
<text class="info">{{express.express_no}}</text>
|
||||
<text class="copy" @click="copy(express.express_no)">复制</text>
|
||||
<text class="info">{{ pkgExpress(pkg).express_no }}</text>
|
||||
<text class="copy" @click="copy(pkgExpress(pkg).express_no)">复制</text>
|
||||
</view>
|
||||
<view class="_info">
|
||||
<text>配送方式</text>
|
||||
<text class="info">{{express.express_company_name}}</text>
|
||||
<text class="info">{{ pkgExpress(pkg).express_company_name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="infos" v-else>
|
||||
<view class="_info">
|
||||
<text>发货状态</text>
|
||||
<text class="info">{{ Number(pkg.is_send) === 1 ? '已发货' : '待发货' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 物流追踪 -->
|
||||
<view class="card">
|
||||
<view class="title">
|
||||
物流追踪
|
||||
</view>
|
||||
<!-- <view class="empty" v-if="newArr.length==0">
|
||||
<image src="https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/empty/orders.png" mode="aspectFit"></image>
|
||||
<text>药房正在备药中,暂时还没有物流信息哦~</text>
|
||||
</view> -->
|
||||
|
||||
<view class="line" v-if="newArr.length>0">
|
||||
<u-time-line v-for="(item,index) in newArr" :key="index">
|
||||
<u-time-line-item nodeTop="2">
|
||||
<view class="title">物流追踪</view>
|
||||
<view class="line" v-if="pkgTracks(pkg).length > 0">
|
||||
<u-time-line>
|
||||
<u-time-line-item
|
||||
v-for="(item, index) in pkgTracks(pkg)"
|
||||
:key="index"
|
||||
nodeTop="2"
|
||||
>
|
||||
<template v-slot:node>
|
||||
<view class="track-node" :class="{ 'is-active': index === 0 }" />
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<view>
|
||||
<view class="u-order-title">{{item.status}}</view>
|
||||
<view class="u-order-desc">
|
||||
{{item.detail}}
|
||||
<view class="track-content" :class="{ 'is-active': index === 0 }">
|
||||
<view class="u-order-title">
|
||||
{{ item.status }}
|
||||
<text v-if="showOngoing(item, index)" class="ongoing">进行中</text>
|
||||
</view>
|
||||
<view class="u-order-time">{{item.detail_at}}</view>
|
||||
<view class="u-order-desc">{{ item.detail }}</view>
|
||||
<view class="u-order-time">{{ item.detail_at }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-time-line-item>
|
||||
</u-time-line>
|
||||
</view>
|
||||
<view v-else class="empty-tip">暂无物流轨迹</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
<template v-else>
|
||||
<view class="infos" v-if="currentExpress && currentExpress.express_no">
|
||||
<view class="_info">
|
||||
<text>快递单号</text>
|
||||
<text class="info">{{ currentExpress.express_no }}</text>
|
||||
<text class="copy" @click="copy(currentExpress.express_no)">复制</text>
|
||||
</view>
|
||||
<view class="_info">
|
||||
<text>配送方式</text>
|
||||
<text class="info">{{ currentExpress.express_company_name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="infos" v-else-if="packages.length">
|
||||
<view class="_info">
|
||||
<text>发货状态</text>
|
||||
<text class="info">{{ currentPkg && Number(currentPkg.is_send) === 1 ? '已发货' : '待发货' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card">
|
||||
<view class="title">物流追踪</view>
|
||||
<view class="line" v-if="newArr.length > 0">
|
||||
<u-time-line>
|
||||
<u-time-line-item
|
||||
v-for="(item, index) in newArr"
|
||||
:key="index"
|
||||
nodeTop="2"
|
||||
>
|
||||
<template v-slot:node>
|
||||
<view class="track-node" :class="{ 'is-active': index === 0 }" />
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<view class="track-content" :class="{ 'is-active': index === 0 }">
|
||||
<view class="u-order-title">
|
||||
{{ item.status }}
|
||||
<text v-if="showOngoing(item, index)" class="ongoing">进行中</text>
|
||||
</view>
|
||||
<view class="u-order-desc">{{ item.detail }}</view>
|
||||
<view class="u-order-time">{{ item.detail_at }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-time-line-item>
|
||||
</u-time-line>
|
||||
</view>
|
||||
<view v-else class="empty-tip">暂无物流轨迹</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 底部 确认收货 -->
|
||||
<view class="footer" v-if="newArr.length>0">
|
||||
<!-- 底部确认收货 -->
|
||||
<view class="footer" v-if="canConfirm">
|
||||
<view class="to_pay" @click="toaffirm">确认收货</view>
|
||||
</view>
|
||||
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// getLogistics
|
||||
import {
|
||||
getLogistics,
|
||||
confirmAccept
|
||||
} from '../../request/api/api';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isshow: true,
|
||||
show: false,
|
||||
content: '是否确认退款',
|
||||
logisticsList: {},
|
||||
order_no: '',
|
||||
express: [],
|
||||
order_id: '',
|
||||
newArr: [{
|
||||
|
||||
const FALLBACK_TRACKS = [{
|
||||
detail: "药品已打包,等待快递揽件",
|
||||
detail_at: "",
|
||||
status: "已发货",
|
||||
@@ -86,34 +153,107 @@
|
||||
detail_at: "",
|
||||
status: "备药",
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
logisticsList: {},
|
||||
express: {},
|
||||
packages: [],
|
||||
activePkg: 0,
|
||||
order_id: '',
|
||||
newArr: [],
|
||||
canConfirm: false,
|
||||
swiperHeight: 480,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentPkg() {
|
||||
return this.packages[this.activePkg] || null
|
||||
},
|
||||
currentExpress() {
|
||||
const pkg = this.currentPkg
|
||||
if (pkg && pkg.express) return pkg.express
|
||||
return this.express
|
||||
}
|
||||
},
|
||||
onLoad(op) {
|
||||
this.order_id = op.id || '45'
|
||||
this.order_id = op.id || ''
|
||||
this.getLogisticsList()
|
||||
},
|
||||
methods: {
|
||||
// 支付
|
||||
/** 最新一条非签收时才显示「进行中」 */
|
||||
showOngoing(item, index) {
|
||||
if (index !== 0) return false
|
||||
const status = String((item && item.status) || '')
|
||||
return status !== '签收'
|
||||
},
|
||||
pkgExpress(pkg) {
|
||||
return (pkg && pkg.express) || {}
|
||||
},
|
||||
/** 按包裹组装轨迹(读 packages[i].express.detail) */
|
||||
pkgTracks(pkg) {
|
||||
const express = this.pkgExpress(pkg)
|
||||
const detail = Array.isArray(express.detail) ? express.detail : []
|
||||
if (detail.length) return detail
|
||||
if (pkg && Number(pkg.is_send) === 1) return FALLBACK_TRACKS
|
||||
return [{
|
||||
detail: '药房正在备药中',
|
||||
detail_at: '',
|
||||
status: '备药',
|
||||
}]
|
||||
},
|
||||
/** Tab 切换包裹,驱动 swiper */
|
||||
switchPkg(idx) {
|
||||
this.activePkg = idx
|
||||
this.applyTracksFromPkg()
|
||||
this.$nextTick(() => this.updateSwiperHeight())
|
||||
},
|
||||
/** swiper 左右滑同步 activePkg */
|
||||
onSwiperChange(e) {
|
||||
const idx = Number(e.detail.current || 0)
|
||||
if (idx === this.activePkg) return
|
||||
this.activePkg = idx
|
||||
this.applyTracksFromPkg()
|
||||
this.$nextTick(() => this.updateSwiperHeight())
|
||||
},
|
||||
/** 测量当前面板高度,避免 swiper 裁切时间轴 */
|
||||
updateSwiperHeight() {
|
||||
if (this.packages.length <= 1) return
|
||||
const q = uni.createSelectorQuery().in(this)
|
||||
q.select('#pkg-panel-' + this.activePkg).boundingClientRect((rect) => {
|
||||
if (rect && rect.height) {
|
||||
this.swiperHeight = Math.ceil(rect.height)
|
||||
}
|
||||
}).exec()
|
||||
},
|
||||
/**
|
||||
* 根据当前包裹组装时间轴(单包模式用)
|
||||
* 接口 detail 按时间倒序,第 0 条即最新
|
||||
*/
|
||||
applyTracksFromPkg() {
|
||||
const pkg = this.currentPkg
|
||||
this.newArr = this.pkgTracks(pkg)
|
||||
const express = this.currentExpress
|
||||
const hasTrack = Array.isArray(express.detail) && express.detail.length > 0
|
||||
this.canConfirm = hasTrack || (pkg && Number(pkg.is_send) === 1)
|
||||
},
|
||||
toaffirm() {
|
||||
this.postConfirm()
|
||||
uni.switchTab({
|
||||
url: '/pages/mine/mine'
|
||||
})
|
||||
},
|
||||
|
||||
// 点击复制
|
||||
copy(value) {
|
||||
//提示模板
|
||||
uni.showModal({
|
||||
content: value, //模板中提示的内容
|
||||
content: value,
|
||||
confirmText: '复制内容',
|
||||
success: () => {
|
||||
|
||||
uni.setClipboardData({
|
||||
data: value, //要被复制的内容
|
||||
success: () => { //复制成功的回调函数
|
||||
uni.showToast({ //提示
|
||||
data: value,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '复制成功',
|
||||
icon: 'success'
|
||||
})
|
||||
@@ -122,28 +262,31 @@
|
||||
}
|
||||
});
|
||||
},
|
||||
//物流详情请求
|
||||
getLogisticsList() {
|
||||
getLogistics({
|
||||
method: "get",
|
||||
method: "post",
|
||||
data: {
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
order_id: this.order_id,
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'list');
|
||||
if (res.data.errcode == 0) {
|
||||
console.log(res.data.data);
|
||||
this.logisticsList = res.data.data.address
|
||||
this.express = res.data.data.express
|
||||
|
||||
let arr = this.express.detail.filter((item, index) => {
|
||||
return index != 0
|
||||
})
|
||||
|
||||
this.newArr = [...arr,...this.newArr ]
|
||||
const data = res.data.data || {}
|
||||
this.logisticsList = data.address || {}
|
||||
this.express = data.express || {}
|
||||
this.packages = Array.isArray(data.packages) ? data.packages : []
|
||||
if (!this.packages.length && this.express && this.express.express_no) {
|
||||
this.packages = [{
|
||||
package_no: 1,
|
||||
warehouse_name: '',
|
||||
is_send: 1,
|
||||
express: this.express,
|
||||
}]
|
||||
}
|
||||
this.activePkg = 0
|
||||
this.applyTracksFromPkg()
|
||||
this.$nextTick(() => this.updateSwiperHeight())
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
postConfirm() {
|
||||
@@ -154,11 +297,9 @@
|
||||
order_id: this.order_id,
|
||||
}
|
||||
}).then((res) => {
|
||||
// console.log(res, 'list');
|
||||
if (res.data.errcode == 0) {
|
||||
console.log(res.data.data);
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -166,25 +307,63 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$primary: #4175EE;
|
||||
$primary-soft: rgba(65, 117, 238, 0.12);
|
||||
$primary-glow: rgba(65, 117, 238, 0.25);
|
||||
|
||||
.container {
|
||||
width: 750rpx;
|
||||
max-height: 100%;
|
||||
min-height: 100vh;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
|
||||
background: #F5F5F5;
|
||||
|
||||
.empty {
|
||||
width: 440rpx;
|
||||
height: 393rpx;
|
||||
margin: 200rpx auto;
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
margin-bottom: 10rpx;
|
||||
color: #999;
|
||||
padding: 40rpx 0;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.pkg-tabs {
|
||||
white-space: nowrap;
|
||||
width: 710rpx;
|
||||
margin: 0 auto 16rpx;
|
||||
background: #fff;
|
||||
padding: 16rpx 20rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pkg-tab {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 12rpx 28rpx;
|
||||
margin-right: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #f5f5f5;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
|
||||
&.active {
|
||||
background: $primary-soft;
|
||||
color: $primary;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pkg-sub {
|
||||
font-size: 20rpx;
|
||||
margin-top: 4rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.pkg-swiper {
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.pkg-panel {
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.head {
|
||||
@@ -217,157 +396,133 @@
|
||||
.choose_area {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #232323;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 710rpx;
|
||||
border-radius: 16rpx;
|
||||
margin: 10rpx auto 180rpx;
|
||||
padding: 30rpx;
|
||||
background: #FFFFFF;
|
||||
|
||||
.title {
|
||||
width: 640rpx;
|
||||
padding-bottom: 22rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Bold, PingFang SC;
|
||||
font-weight: bold;
|
||||
color: #232323;
|
||||
border-bottom: 2rpx solid #DDDDDD;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 18rpx;
|
||||
|
||||
.u-time-line-item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.u-node {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 100rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.u-order-title {
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.u-order-desc {
|
||||
color: rgb(150, 150, 150);
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.u-order-time {
|
||||
color: rgb(200, 200, 200);
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.infos {
|
||||
width: 710rpx;
|
||||
margin: 20rpx auto 20rpx;
|
||||
padding: 20rpx 32rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 0 auto 20rpx;
|
||||
background: #fff;
|
||||
padding: 10rpx 30rpx;
|
||||
|
||||
._info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20rpx 0;
|
||||
|
||||
text {
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
}
|
||||
color: #666;
|
||||
|
||||
.info {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
flex: 1;
|
||||
margin-left: 30rpx;
|
||||
color: #232323;
|
||||
margin-left: 60rpx;
|
||||
}
|
||||
|
||||
.copy {
|
||||
display: inline-block;
|
||||
border: 2rpx solid #1777FF;
|
||||
width: 88rpx;
|
||||
height: 48rpx;
|
||||
color: $primary;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 710rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #232323;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
.track-node {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: #d9d9d9;
|
||||
margin-left: 6rpx;
|
||||
|
||||
&.is-active {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
margin-left: 4rpx;
|
||||
background: $primary;
|
||||
box-shadow: 0 0 0 6rpx $primary-glow;
|
||||
}
|
||||
}
|
||||
|
||||
.track-content {
|
||||
.u-order-title {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #1777FF;
|
||||
line-height: 44rpx;
|
||||
text-align: center;
|
||||
margin-left: 60rpx;
|
||||
font-weight: 500;
|
||||
color: #999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.u-order-desc {
|
||||
font-size: 26rpx;
|
||||
color: #bbb;
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
.u-order-time {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
.u-order-title {
|
||||
font-weight: 700;
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.u-order-desc {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.u-order-time {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ongoing {
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background: $primary;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 750rpx;
|
||||
height: 100rpx;
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
bottom: env(safe-area-inset-bottom);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
|
||||
|
||||
.to_cancle {
|
||||
width: 196rpx;
|
||||
height: 64rpx;
|
||||
text-align: center;
|
||||
line-height: 64rpx;
|
||||
color: #1777FF;
|
||||
background: #E7F1FF;
|
||||
border-radius: 50rpx 50rpx 50rpx 50rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
background: #fff;
|
||||
padding: 20rpx 40rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
|
||||
.to_pay {
|
||||
width: 196rpx;
|
||||
height: 64rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
line-height: 64rpx;
|
||||
background: $primary;
|
||||
color: #fff;
|
||||
background: #1777FF;
|
||||
border-radius: 50rpx 50rpx 50rpx 50rpx;
|
||||
}
|
||||
|
||||
.to_agin {
|
||||
width: 196rpx;
|
||||
height: 64rpx;
|
||||
text-align: center;
|
||||
line-height: 64rpx;
|
||||
border-radius: 50rpx 50rpx 50rpx 50rpx;
|
||||
border: 2rpx solid #999999;
|
||||
color: #999999;
|
||||
margin-left: 20rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -84,13 +84,11 @@ export function handleSecurityError(err) {
|
||||
|
||||
function assertCheckOk(res) {
|
||||
|
||||
if (res && res.code === 0) {
|
||||
|
||||
if (res && res.data.code === 0) {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
throw { msg: (res && res.message) || '内容含有违规信息,请修改后重试' };
|
||||
throw { msg: (res && res.data.message) || '内容含有违规信息,请修改后重试' };
|
||||
|
||||
}
|
||||
|
||||
|
||||
12
utils/formatStoreNameWithHu.js
Normal file
12
utils/formatStoreNameWithHu.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 在线处方诊所名追加「(互)」:is_online 为 1/2/3,线下 0 不加
|
||||
*/
|
||||
export function formatStoreNameWithHu(storeName, isOnline) {
|
||||
const name = String(storeName || '').trim()
|
||||
if (!name) return ''
|
||||
const online = Number(isOnline)
|
||||
if (online === 1 || online === 2 || online === 3) {
|
||||
return name.endsWith('(互)') ? name : `${name}(互)`
|
||||
}
|
||||
return name
|
||||
}
|
||||
@@ -6,8 +6,8 @@ export function checkDev(key = '') {
|
||||
// 判断某些模块是否开启
|
||||
switch (key) {
|
||||
case 'dev':
|
||||
// return false;
|
||||
return true;
|
||||
return false;
|
||||
// return true;
|
||||
case 'open-im':
|
||||
// return false;
|
||||
return true;
|
||||
|
||||
@@ -331,5 +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://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);
|
||||
Reference in New Issue
Block a user