1. 优化了一些交互,中药药品编辑交互

2. dev和生产环境统一鉴别
This commit is contained in:
李琦
2026-05-30 13:52:44 +08:00
parent ad370375a7
commit 6d93314222
15 changed files with 496 additions and 326 deletions

View File

@@ -41,8 +41,16 @@ const reqInterceptor = async (options) => {
...options.header
}
const isToken = (options.header || {}).isToken === false
if (uni.getStorageSync('token') && !isToken) {
options.header['authorization'] = `Bearer ${uni.getStorageSync('token')}`// 让每个请求携带自定义token 请根据实际情况自行修改
const isClinicAdminReq = (options.header || {})._clinicAdmin === '1'
|| (options.url && String(options.url).indexOf('clinic-admin') !== -1)
const clinicToken = uni.getStorageSync('clinic_admin_token')
const doctorToken = uni.getStorageSync('token')
if (!isToken) {
if (isClinicAdminReq && clinicToken) {
options.header['authorization'] = `Bearer ${clinicToken}`
} else if (doctorToken) {
options.header['authorization'] = `Bearer ${doctorToken}`
}
}
return options;
}
@@ -86,14 +94,21 @@ const resInterceptor = (response, conf = {}) => {
} else if (statusCode === 401) {
uni.showToast({
icon: 'error',
title: response['msg'] || errorCode[statusCode]
title: response['msg'] || response['message'] || errorCode[statusCode]
})
uni.removeStorageSync()
setTimeout(()=>{
uni.navigateTo({
url:'/pages/login/index'
})
},1000)
const isClinic = uni.getStorageSync('loginMode') === 'clinic_admin'
if (isClinic) {
uni.removeStorageSync('clinic_admin_token')
uni.removeStorageSync('clinic_admin_user')
uni.removeStorageSync('loginMode')
} else {
uni.removeStorageSync('token')
uni.removeStorageSync('loginInfo')
uni.removeStorageSync('identity')
}
setTimeout(() => {
uni.reLaunch({ url: '/pages/login/index' })
}, 1000)
_responseLog(response, conf, "response 401")
// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
return {

View File

@@ -71,6 +71,8 @@
* @event {Function} on-choose-complete 每次选择图片后触发,只是让外部可以得知每次选择后,内部的文件列表
* @example <u-upload :action="action" :file-list="fileList" ></u-upload>
*/
import { prepareImagePath } from '@/common/js/image-compress.js';
export default {
name: 'd-upload',
props: {
@@ -296,51 +298,56 @@
const {
name = '', maxCount, multiple, maxSize, sizeType, lists, camera, compressed, maxDuration, sourceType
} = this;
let chooseFile = null;
const newMaxCount = maxCount - lists.length;
// 设置为只选择图片的时候使用 chooseImage 来实现
chooseFile = new Promise((resolve, reject) => {
uni.chooseImage({
count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
sourceType: sourceType,
sizeType,
success: resolve,
fail: reject
});
});
chooseFile
.then(res => {
let file = null;
let listOldLength = this.lists.length;
res.tempFiles.map((val, index) => {
// 检查文件后缀是否允许如果不在this.limitType内就会返回false
if (!this.checkFileExt(val)) return;
// 如果是非多选index大于等于1或者超出最大限制数量时不处理
if (!multiple && index >= 1) return;
success: async (res) => {
const listOldLength = this.lists.length;
for (let index = 0; index < res.tempFiles.length; index++) {
const val = res.tempFiles[index];
if (!this.checkFileExt(val)) continue;
if (!multiple && index >= 1) continue;
if (val.size > maxSize) {
this.$emit('on-oversize', val, this.lists, this.index);
this.showToast('超出允许的文件大小');
} else {
continue;
}
if (maxCount <= lists.length) {
this.$emit('on-exceed', val, this.lists, this.index);
this.showToast('超出最大允许的文件个数');
return;
break;
}
try {
const prepared = await prepareImagePath({
path: val.path,
size: val.size,
});
if (!prepared) continue;
lists.push({
url: val.path,
url: prepared.path,
progress: 0,
error: false,
file: val
file: {
...val,
path: prepared.path,
size: prepared.size,
},
});
} catch (error) {
this.$emit('on-choose-fail', error);
this.showToast('图片处理失败');
}
}
});
// 每次图片选择完,抛出一个事件,并将当前内部选择的图片数组抛出去
this.$emit('on-choose-complete', this.lists, this.index);
if (this.autoUpload) this.uploadFile(listOldLength);
})
.catch(error => {
},
fail: (error) => {
this.$emit('on-choose-fail', error);
}
});
},
// 提示用户消息

View File

@@ -391,6 +391,61 @@
}
]
}, {
"root": "subPackages/sub_clinic_admin",
"pages": [{
"path": "home/index",
"style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom" }
},
{
"path": "my/index",
"style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" }
},
{
"path": "withdrawal/index",
"style": { "navigationBarTitleText": "提现管理", "navigationStyle": "custom" }
},
{
"path": "withdrawal/settlement/index",
"style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom" }
},
{
"path": "withdrawal/settlement/detail",
"style": { "navigationBarTitleText": "结算明细", "navigationStyle": "custom" }
},
{
"path": "withdrawal/apply",
"style": { "navigationBarTitleText": "申请提现", "navigationStyle": "custom" }
},
{
"path": "withdrawal/card-edit",
"style": { "navigationBarTitleText": "编辑账户", "navigationStyle": "custom" }
},
{
"path": "withdrawal/record-detail",
"style": { "navigationBarTitleText": "提现详情", "navigationStyle": "custom" }
},
{
"path": "reconciliation/index",
"style": { "navigationBarTitleText": "对账单", "navigationStyle": "custom" }
},
{
"path": "order/index",
"style": { "navigationBarTitleText": "商品订单", "navigationStyle": "custom" }
},
{
"path": "order/detail",
"style": { "navigationBarTitleText": "订单详情", "navigationStyle": "custom" }
},
{
"path": "warehouse/index",
"style": { "navigationBarTitleText": "仓库管理", "navigationStyle": "custom" }
},
{
"path": "warehouse/detail",
"style": { "navigationBarTitleText": "药品详情", "navigationStyle": "custom" }
}
]
}, {
"root": "subPackages/sub_agreement",
"pages": [{
@@ -423,10 +478,10 @@
}
],
"tabBar": {
"color": "#fff",
"selectedColor": "#fff",
"backgroundColor": "#fff",
"borderStyle": "white",
"color": "#666666",
"selectedColor": "#1575FC",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [{
"pagePath": "pages/workbench/index",
"text": "工作台"

View File

@@ -10,10 +10,16 @@
<view class="pwd">
<d-input :maxlength="11" height="96" v-model="form['mobile']"
:prefixIcon="require('../../static/image/act.png')" borderRadius="96rpx" prefixIconSize="40rpx"
placeholder="请输入手机号" @input="is_d=false" :placeholder-style="{fontSize:'32rpx'}"
:placeholder="loginMode === 'clinic_admin' ? '请输入手机号' : '请输入手机号'" @input="is_d=false" :placeholder-style="{fontSize:'32rpx'}"
:custom-style="{fontSize:'32rpx',paddingLeft:'60rpx'}" />
</view>
<view class="pwd" v-if="loginMode === 'clinic_admin'">
<d-input height="96" v-model="clinicPassword" type="password" password
borderRadius="96rpx" placeholder="请输入后台登录密码" :placeholder-style="{fontSize:'32rpx'}"
:custom-style="{fontSize:'32rpx',paddingLeft:'32rpx'}" />
</view>
<view class="pwd">
<u-field v-model="smsCode" placeholder="请填写验证码" :placeholder-style="{fontSize:'32rpx'}">
<u-button size="mini" slot="right" @click="getCode">{{codeText}}</u-button>
@@ -40,10 +46,13 @@
登录</u-button>
</view>
<!-- <view class="register">-->
<!-- <text @click="$go('../../subPackages/sub_workbench/workbench_identity')">手机号注册</text>-->
<!-- </view>-->
<view class="register">
<text @click="switchClinicAdmin">{{ loginMode === 'clinic_admin' ? '返回医生/药师登录' : '我是诊所管理员' }}</text>
</view>
<!-- <view class="register">-->
<!-- <text @click="$go('../../subPackages/sub_workbench/workbench_identity')">手机号注册</text>-->
<!-- </view>-->
</view>
</view>
@@ -60,9 +69,15 @@
getUserInfo,
loginOrRe
} from '../../api/all';
import {
sendClinicAdminCode,
clinicAdminLogin,
getClinicAdminMyInfo,
} from '../../api/clinicAdmin';
export default {
data() {
return {
loginMode: 'service_user',
loading: false,
form: {
check: false
@@ -74,6 +89,7 @@
mobile: '',
codeText: '',
smsCode: '',
clinicPassword: '',
code: ''
};
},
@@ -83,6 +99,13 @@
// console.log('appid', accountInfo.miniProgram.appId); // 小程序 appId
},
mounted() {
const clinicToken = uni.getStorageSync('clinic_admin_token')
if (clinicToken && uni.getStorageSync('loginMode') === 'clinic_admin') {
setTimeout(() => {
uni.reLaunch({ url: '/subPackages/sub_clinic_admin/home/index' })
}, 200)
return
}
const token = uni.getStorageSync('token')
const info = uni.getStorageSync('loginInfo')
if (token&&info) {
@@ -105,6 +128,11 @@
}
},
methods: {
switchClinicAdmin() {
this.loginMode = this.loginMode === 'clinic_admin' ? 'service_user' : 'clinic_admin'
this.clinicPassword = ''
this.smsCode = ''
},
toLogin() {
uni.login({
provider: 'weixin',
@@ -115,7 +143,6 @@
},
//登录或者注册接口
register() {
//修改1
if (!uni.$u.test.mobile(this.form['mobile'])) {
this.$toast('请输入正确的手机号')
return
@@ -130,6 +157,15 @@
return
}
if (this.loginMode === 'clinic_admin') {
if (!this.clinicPassword) {
this.$toast('请输入后台登录密码')
return
}
this.clinicAdminLoginFlow()
return
}
const data = {
store_id: '11001',
mobile: this.form['mobile'],
@@ -257,16 +293,44 @@
codeChange(text) {
this.codeText = text;
},
clinicAdminLoginFlow() {
this.loading = true
clinicAdminLogin(this.form['mobile'], this.clinicPassword, this.smsCode).then(res => {
if (res.code !== 0 || !res.result || !res.result.token) {
this.$toast(res.message || res.msg || '登录失败')
return Promise.reject()
}
uni.setStorageSync('loginMode', 'clinic_admin')
uni.setStorageSync('clinic_admin_token', res.result.token)
return getClinicAdminMyInfo()
}).then((wrap) => {
if (!wrap || !wrap.ok) return
uni.setStorageSync('clinic_admin_user', wrap.data)
this.$toast('登录成功')
setTimeout(() => {
uni.reLaunch({ url: '/subPackages/sub_clinic_admin/home/index' })
}, 400)
}).catch(() => {}).finally(() => {
this.loading = false
})
},
getCode() {
if (this.$refs.uCode.canGetCode) {
// 模拟向后端请求验证码
uni.showLoading({
title: '正在获取验证码'
})
uni.showLoading({ title: '正在获取验证码' })
setTimeout(() => {
uni.hideLoading();
// 通知验证码组件内部开始倒计时
//发送验证码接口
if (this.loginMode === 'clinic_admin') {
if (!this.clinicPassword) {
this.$toast('请先输入后台登录密码')
return
}
sendClinicAdminCode(this.form['mobile']).then(res => {
if (res.code === 0 || res.errcode != -1) {
this.$refs.uCode.start();
}
})
return
}
const data = {
store_id: '11001',
mobile: this.form['mobile']

View File

@@ -135,13 +135,15 @@
</block>
<block v-if="lists.prescription_type==2">
<view class="item" v-for="(it,index) in infoList.repice" :key="item.id">
<block v-if="lists.prescription_type==2||lists.prescription_type==5||lists.prescription_type==7">
<view class="item" v-for="(it,index) in infoList.repice" :key="it.id || index">
<!-- v-for="(it,index) in item.content" :key="it.id" -->
<view class="name" style="justify-content: space-between;">
<view class="yp_name">
<text>{{ it.content.drug_name}} </text>
<text style="font-size: 24rpx;margin-left: 10rpx;">{{ it.content.specification }}</text>
<text>{{ (it.content && it.content.drug_name) || '' }} </text>
<text
v-if="it.content && it.content.specification"
class="drug-spec">{{ it.content.specification }}</text>
</view>
<text>x{{ it.number}}</text>
</view>
@@ -293,6 +295,25 @@
})
return num
},
normalizeRepice(list) {
return (list || []).map((it) => {
let content = it.content
if (typeof content === 'string') {
try {
content = JSON.parse(content || '{}')
} catch (e) {
content = {}
}
}
if (!content || typeof content !== 'object' || Array.isArray(content)) {
content = Array.isArray(content) ? content : {}
}
return {
...it,
content,
}
})
},
getInfo() {
prescripDetail({
store_id: uni.getStorageSync('store_id') || '11001',
@@ -300,7 +321,9 @@
}).then((res) => {
// console.log(res, 'deta');
if (res.errcode == 0) {
this.infoList = res.data.content
const content = res.data.content
content.repice = this.normalizeRepice(content.repice)
this.infoList = content
this.rpList = res.data.pharmacistInfo
this.lists = res.data
this.status = res.data.status
@@ -534,6 +557,12 @@
// justify-content: space-between;
flex-wrap: wrap;
.drug-spec {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
._name {
display: flex;
justify-content: space-between;

View File

@@ -132,13 +132,15 @@
</block>
<block v-if="lists.prescription_type==2">
<view class="item" v-for="(it,index) in infoList.repice" :key="item.id">
<block v-if="lists.prescription_type==2||lists.prescription_type==5||lists.prescription_type==7">
<view class="item" v-for="(it,index) in infoList.repice" :key="it.id || index">
<!-- v-for="(it,index) in item.content" :key="it.id" -->
<view class="name" style="justify-content: space-between;">
<view class="yp_name">
<text>{{ it.content.drug_name}} </text>
<text style="font-size: 24rpx;margin-left: 10rpx;">{{ it.content.specification }}</text>
<text>{{ (it.content && it.content.drug_name) || '' }} </text>
<text
v-if="it.content && it.content.specification"
class="drug-spec">{{ it.content.specification }}</text>
</view>
<text>x{{ it.number}}</text>
</view>
@@ -273,6 +275,25 @@
})
return num
},
normalizeRepice(list) {
return (list || []).map((it) => {
let content = it.content
if (typeof content === 'string') {
try {
content = JSON.parse(content || '{}')
} catch (e) {
content = {}
}
}
if (!content || typeof content !== 'object' || Array.isArray(content)) {
content = Array.isArray(content) ? content : {}
}
return {
...it,
content,
}
})
},
getInfo() {
prescripDetail({
store_id: uni.getStorageSync('store_id') || '11001',
@@ -280,7 +301,9 @@
}).then((res) => {
// console.log(res, 'deta');
if (res.errcode == 0) {
this.infoList = res.data.content
const content = res.data.content
content.repice = this.normalizeRepice(content.repice)
this.infoList = content
this.rpList = res.data.pharmacistInfo
this.lists = res.data
this.status = res.data.status
@@ -514,6 +537,12 @@
// justify-content: space-between;
flex-wrap: wrap;
.drug-spec {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
._name {
display: flex;
justify-content: space-between;

View File

@@ -101,10 +101,10 @@
}
],
"tabBar": {
"color": "#fff",
"selectedColor": "#fff",
"backgroundColor": "#fff",
"borderStyle": "white",
"color": "#666666",
"selectedColor": "#1575FC",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [{
"pagePath": "pages/workbench/index",
"text": "工作台"

View File

@@ -49,6 +49,7 @@
logout,
toUpload,
} from '@/api/all.js'
import { chooseAvatarImage } from '@/common/js/select-avatar-image.js';
export default {
data() {
return {
@@ -85,56 +86,24 @@
}
},
selectAct() {
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'],
success: (res) => {
uni.showLoading({
title: '请稍后...'
})
const tempFiles = res.tempFiles;
let resSize = tempFiles[0].size;
// 1M=1024KB=1048576B
console.log(resSize)
if (resSize > 1048576) {
uni.showToast({
title: "上传图片大小不能超过1MB",
icon: 'error'
});
return
}
uni.uploadFile({
url: 'https://api.xiaokang88.com/open-api/upload/old-admin-img',
filePath: res.tempFiles[0]['path'],
name: 'file',
header: {
authorization: `Bearer ${uni.getStorageSync('token')}`
},
chooseAvatarImage({
formData: {
store_id: uni.getStorageSync('store_id') || '11001'
store_id: uni.getStorageSync('store_id') || '11001',
},
success: res => {
let req = this.$u.test.jsonString(res.data) ? JSON.parse(res
.data) : res.data
// console.log(req, 'req')
onSuccess: (res) => {
const req = this.$u.test.jsonString(res.data) ? JSON.parse(res.data) : res.data;
if (req.errcode == 0) {
toUpload({
store_id: uni.getStorageSync('store_id') ||
'11001',
avatar: req.data.url
}).then((res) => {
this.getDoctor()
store_id: uni.getStorageSync('store_id') || '11001',
avatar: req.data.url,
}).then(() => {
this.getDoctor();
this.$toast('编辑成功');
})
uni.hideLoading()
});
} else {
this.$toast(res.msg);
}
}
});
}
},
});
},
logout() {

View File

@@ -154,7 +154,7 @@
<view v-if="parsedObj.question" class="text-block">
<text class="block-content">{{ parsedObj.question }}</text>
</view>
<view v-for="(row, idx) in (parsedObj.drugs || [])" :key="'fd-' + idx" class="info-row">
<view v-for="row in followUpDrugs" :key="row._wxKey" class="info-row">
<text class="label">{{ row.name || '药品' }}</text>
<text class="value">×{{ row.quantity != null ? row.quantity : 1 }}</text>
</view>
@@ -290,7 +290,7 @@
</view>
<view v-if="parsedObj.questions && parsedObj.questions.length" class="transfer-qa">
<text class="transfer-qa-title">咨询问题</text>
<view v-for="(qa, qix) in parsedObj.questions" :key="qix" class="transfer-qa-item">
<view v-for="(qa, qix) in transferQuestionsWithKey" :key="qa._wxKey" class="transfer-qa-item">
<text class="transfer-qa-q">{{ qix + 1 }}. {{ qa.question }}</text>
<text class="transfer-qa-a">{{ qa.answer }}</text>
</view>
@@ -318,6 +318,7 @@
<script>
import { parseMessageContent } from '../utils/messageParse.js';
import { withWxKey } from '@/utils/wxListKey.js';
export default {
name: 'MessageBubble',
@@ -388,6 +389,14 @@ export default {
if (st === 'no' || st === '0') return '否,未使用过';
return '';
},
followUpDrugs() {
const drugs = (this.parsedObj && this.parsedObj.drugs) || [];
return withWxKey(drugs, 'id', 'fd');
},
transferQuestionsWithKey() {
const qs = (this.parsedObj && this.parsedObj.questions) || [];
return withWxKey(qs, 'id', 'tq');
},
experienceRxPayload() {
const pc = this.parsedObj;
if (!pc || this.msg.message_type !== 11) return {};

View File

@@ -44,7 +44,7 @@
<text class="spinner-text">历史记录加载中...</text>
</view>
<view v-for="(msg, index) in messages" :key="msg.id || 'm-' + index" class="message-wrapper">
<view v-for="(msg, index) in messages" :key="msg._wxKey" class="message-wrapper">
<view v-if="shouldShowTime(msg, index)" class="time-divider">
<text class="time-text">{{ timeDividerText(msg) }}</text>
</view>
@@ -167,7 +167,7 @@
<view class="tool-cell-icon"><u-icon name="close-circle" size="30" color="#6ACDBB"></u-icon></view>
<text class="tool-cell-label">拒诊</text>
</view>
<view v-for="n in 7" :key="'tool-ph-' + n" class="tool-cell tool-cell--placeholder"></view>
<view v-for="ph in toolPlaceholderCells" :key="ph._wxKey" class="tool-cell tool-cell--placeholder"></view>
</view>
</swiper-item>
</swiper>
@@ -182,8 +182,8 @@
</view>
<scroll-view v-if="!quickReplyLoading && quickReplyList.length" class="quick-reply-scroll" scroll-y>
<view
v-for="(item, idx) in quickReplyList"
:key="idx"
v-for="item in quickReplyList"
:key="item._wxKey"
class="quick-reply-row"
@click="selectQuickReply(item)"
>
@@ -222,8 +222,8 @@
<text class="orders-v">{{ registerOrderStatusText(registerOrderBlock.status) }}</text>
</view>
<view
v-for="(sub, six) in childOrdersBlock"
:key="'osub-' + six"
v-for="sub in childOrdersWithKey"
:key="sub._wxKey"
class="orders-sub"
>
<text class="orders-sub-label">子订单</text>
@@ -235,10 +235,11 @@
<view v-if="ordersRxLoading" class="orders-hint">加载中</view>
<view v-else-if="!ordersRxList.length" class="orders-hint">暂无处方</view>
<view
v-for="(rx, orix) in ordersRxList"
:key="'orx-' + orix"
v-for="rx in ordersRxList"
:key="rx._wxKey"
class="orders-rx-row"
@click="onOrdersRxTap(orix)"
:data-wx-key="rx._wxKey"
@click="onOrdersRxTap"
>
<text class="orders-rx-no">{{ rx.order_no || rx.prescription_no || '处方' }}</text>
<text v-if="rx.total_pay_price != null" class="orders-rx-price">¥{{ rx.total_pay_price }}</text>
@@ -277,7 +278,7 @@
</view>
<view v-if="transferCard.questions && transferCard.questions.length" class="td-qa">
<text class="td-qa-title">咨询问题</text>
<view v-for="(qa, qix) in transferCard.questions" :key="'tdq-' + qix" class="td-qa-item">
<view v-for="(qa, qix) in transferQuestionsWithKey" :key="qa._wxKey" class="td-qa-item">
<text class="td-qa-q">{{ qix + 1 }}. {{ qa.question }}</text>
<text class="td-qa-a">{{ qa.answer }}</text>
</view>
@@ -326,9 +327,13 @@ import PatientDetailPanel from '../components/PatientDetailPanel.vue';
import MessageBubble from '../components/MessageBubble.vue';
import ReceptionActionBar from '../components/ReceptionActionBar.vue';
import RefuseReceptionModal from '../components/RefuseReceptionModal.vue';
import { withWxKey, ensureWxKey } from '@/utils/wxListKey.js';
import { prepareImagePath } from '@/common/js/image-compress.js';
const PENDING_RX_FROM_CHAT = 'xk_pending_rx_from_chat';
const TOOL_PLACEHOLDER_CELLS = Array.from({ length: 7 }, (_, i) => ({ _wxKey: `ph${i}` }));
export default {
components: { PatientDetailPanel, MessageBubble, ReceptionActionBar, RefuseReceptionModal },
data() {
@@ -370,7 +375,8 @@ export default {
ordersPopupOpen: false,
ordersRxList: [],
ordersRxLoading: false,
toolPanelSwiperCurrent: 0
toolPanelSwiperCurrent: 0,
toolPlaceholderCells: TOOL_PLACEHOLDER_CELLS
};
},
computed: {
@@ -427,6 +433,13 @@ export default {
const raw = ro.child_orders || ro.sub_orders || ro.orders;
return Array.isArray(raw) ? raw : [];
},
childOrdersWithKey() {
return withWxKey(this.childOrdersBlock, 'id', 'osub');
},
transferQuestionsWithKey() {
const qs = (this.transferCard && this.transferCard.questions) || [];
return withWxKey(qs, 'id', 'tdq');
},
refuseToolDisabled() {
return Number(this.patientInfo && this.patientInfo.status) !== 1;
},
@@ -586,9 +599,13 @@ export default {
this.transferCard = null;
}
},
syncMessagesFromRoom() {
const raw = chatRoomManager.getRoomMessages(this.roomId) || [];
this.messages = withWxKey(raw, 'id', 'm');
},
onMessageUpdated({ roomId }) {
if (roomId === this.roomId) {
this.messages = [...(chatRoomManager.getRoomMessages(this.roomId) || [])];
this.syncMessagesFromRoom();
this.$forceUpdate();
}
},
@@ -624,7 +641,7 @@ export default {
const lastMessageId = wasFirstPage ? 0 : chatRoomManager.lastMessageId;
const batch = await chatRoomManager.loadRoomMessages(this.roomId, lastMessageId);
if (batch && batch.length > 0) {
this.messages = [...(chatRoomManager.getRoomMessages(this.roomId) || [])];
this.syncMessagesFromRoom();
this.page++;
} else {
this.hasMore = false;
@@ -674,16 +691,17 @@ export default {
return Math.abs(a - b) < 60000;
});
if (tempIndex !== -1) {
this.$set(this.messages, tempIndex, { ...message, isTemporary: false });
const patched = ensureWxKey({ ...message, isTemporary: false }, 'id', `m${tempIndex}`);
this.$set(this.messages, tempIndex, patched);
return;
}
}
const existingIndex = this.messages.findIndex((m) => m.id === message.id);
if (existingIndex !== -1) {
this.$set(this.messages, existingIndex, message);
this.$set(this.messages, existingIndex, ensureWxKey(message, 'id', `m${existingIndex}`));
return;
}
this.messages.push(message);
this.messages.push(ensureWxKey(message, 'id', `m${this.messages.length}`));
if (message.message_type === chatConfig.messageTypes['end-consultation']) {
this.isConsultationEnded = true;
}
@@ -817,7 +835,7 @@ export default {
page_size: 30
});
const payload = this.unwrap(res) || {};
this.ordersRxList = Array.isArray(payload.list) ? payload.list : [];
this.ordersRxList = withWxKey(Array.isArray(payload.list) ? payload.list : [], 'id', 'orx');
} catch (e) {
console.warn(e);
this.ordersRxList = [];
@@ -830,8 +848,9 @@ export default {
const n = Number(status);
return map[n] != null ? map[n] : String(status);
},
onOrdersRxTap(index) {
const rx = this.ordersRxList[index];
onOrdersRxTap(e) {
const wxKey = e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.wxKey;
const rx = this.ordersRxList.find((r) => r._wxKey === wxKey);
const id = rx && (rx.id || rx.prescription_id);
if (!id) return;
let url = `/pages/my/prescriptionDetail?id=${id}`;
@@ -967,7 +986,7 @@ export default {
const res = await getQuickReplyListApi();
const raw = this.unwrap(res);
const list = Array.isArray(raw) ? raw : raw && Array.isArray(raw.list) ? raw.list : [];
this.quickReplyList = list;
this.quickReplyList = withWxKey(list, 'id', 'qr');
} catch (e) {
console.error(e);
uni.showToast({ title: '加载常用回复失败', icon: 'none' });
@@ -1042,6 +1061,7 @@ export default {
const idx = this.messages.findIndex((m) => m.id === tempId);
if (idx !== -1) {
this.$set(this.messages[idx], 'id', mid);
this.$set(this.messages[idx], '_wxKey', String(mid));
this.$set(this.messages[idx], 'isTemporary', false);
}
}
@@ -1056,9 +1076,33 @@ export default {
if (this.inputLocked) return;
uni.chooseImage({
count: 1,
success: (res) => {
this.uploadMedia(res.tempFilePaths[0], 'image');
success: async (res) => {
const tempFile = res.tempFiles && res.tempFiles[0];
const filePath = tempFile ? tempFile.path : res.tempFilePaths[0];
let fileSize = tempFile ? tempFile.size : 0;
if (!fileSize && filePath) {
try {
const info = await new Promise((resolve, reject) => {
uni.getFileInfo({
filePath,
success: resolve,
fail: reject,
});
});
fileSize = info.size;
} catch (error) {
console.error(error);
}
}
const prepared = await prepareImagePath({
path: filePath,
size: fileSize,
});
if (!prepared) return;
this.uploadMedia(prepared.path, 'image');
},
});
},
async uploadMedia(filePath, kind) {

View File

@@ -28,7 +28,7 @@
<view v-if="patientList.length" class="list">
<view
v-for="(row, idx) in patientList"
:key="rowKey(row, idx)"
:key="row._wxKey"
class="ol-card flex-row flex-ali-center"
:data-idx="idx"
@tap="onPatientCardTap"
@@ -38,7 +38,6 @@
<u-loading slot="loading"></u-loading>
</u-image>
<u-badge
:key="'ol-ub-' + rowKey(row, idx) + '-' + Number(row.unread_count || 0)"
v-if="Number(row.unread_count) > 0"
:count="Number(row.unread_count)"
:offset="[-4, -4]"
@@ -174,7 +173,7 @@ export default {
}
const next = [...this.patientList];
next.splice(idx, 1, copy);
this.patientList = this.sortPatientList(next);
this.patientList = this.mapPatientRows(this.sortPatientList(next));
},
unwrap(res) {
if (res == null) return null;
@@ -182,11 +181,17 @@ export default {
if (res.data && res.data.result !== undefined) return res.data.result;
return res;
},
rowKey(row, idx) {
mapPatientRows(rows) {
return (rows || []).map((row, idx) => {
const room = row.room_id != null && row.room_id !== '' ? String(row.room_id) : 'r0';
const reg = row.register_id != null ? row.register_id : row.id;
const ord = row.order_no != null && row.order_no !== '' ? String(row.order_no) : '';
return `${room}-${reg != null ? reg : 'x'}-${ord}-${idx}`;
const ub = Number(row.unread_count || 0);
return {
...row,
_wxKey: `${room}-${reg != null ? reg : 'x'}-${ord}-${ub}`,
};
});
},
lastMessageSortTs(row) {
const t = row.last_message_time || row.updated_at || row.register_time;
@@ -276,7 +281,7 @@ export default {
const res = await getOnlineConsultationPatientListApi({ type: this.listType });
const raw = this.unwrap(res);
const arr = Array.isArray(raw) ? raw : [];
this.patientList = this.sortPatientList(arr);
this.patientList = this.mapPatientRows(this.sortPatientList(arr));
} catch (e) {
console.error(e);
this.patientList = [];

View File

@@ -135,13 +135,15 @@
</block>
<block v-if="lists.prescription_type==2">
<view class="item" v-for="(it,index) in infoList.repice" :key="item.id">
<block v-if="lists.prescription_type==2||lists.prescription_type==5||lists.prescription_type==7">
<view class="item" v-for="(it,index) in infoList.repice" :key="it.id || index">
<!-- v-for="(it,index) in item.content" :key="it.id" -->
<view class="name" style="justify-content: space-between;">
<view class="yp_name">
<text>{{ it.content.drug_name}} </text>
<text style="font-size: 24rpx;margin-left: 10rpx;">{{ it.content.specification }}</text>
<text>{{ (it.content && it.content.drug_name) || '' }} </text>
<text
v-if="it.content && it.content.specification"
class="drug-spec">{{ it.content.specification }}</text>
</view>
<text>x{{ it.number}}</text>
</view>
@@ -347,6 +349,25 @@
})
return num
},
normalizeRepice(list) {
return (list || []).map((it) => {
let content = it.content
if (typeof content === 'string') {
try {
content = JSON.parse(content || '{}')
} catch (e) {
content = {}
}
}
if (!content || typeof content !== 'object' || Array.isArray(content)) {
content = Array.isArray(content) ? content : {}
}
return {
...it,
content,
}
})
},
getInfo() {
prescripRecordDetail({
store_id: uni.getStorageSync('store_id') || '11001',
@@ -355,12 +376,9 @@
// console.log(res, 'deta');
if (res.errcode == 0) {
// this.infoList = res.data.prescript
// this.time = res.data.issue_date
// this.rpList = res.data.recipe
// this.price = res.data.total_price
this.infoList = res.data.content
const content = res.data.content
content.repice = this.normalizeRepice(content.repice)
this.infoList = content
this.rpList = res.data.pharmacistInfo
this.lists = res.data
// console.log(this.infoList, 'info');
@@ -644,6 +662,12 @@
display: flex;
justify-content: space-between;
align-items: center;
.drug-spec {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
}
.details {

View File

@@ -207,6 +207,7 @@
infoEdit,
toUploaded
} from "@/api/all.js";
import { chooseAvatarImage } from '@/common/js/select-avatar-image.js';
export default {
data() {
return {
@@ -377,112 +378,50 @@
},
selectActed(){
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'],
success: (res) => {
uni.showLoading({
title: '请稍后...'
})
const tempFiles = res.tempFiles;
let resSize = tempFiles[0].size;
// 1M=1024KB=1048576B
console.log(resSize)
if (resSize > 1048576) {
uni.showToast({
title: "上传图片大小不能超过1MB",
icon: 'error'
});
return
}
uni.uploadFile({
url: 'https://api.xiaokang88.com/open-api/upload/old-admin-img',
filePath: res.tempFiles[0]['path'],
name: 'file',
header: {
authorization: `Bearer ${uni.getStorageSync('token')}`
},
chooseAvatarImage({
formData: {
store_id: uni.getStorageSync('store_id') || '11001'
store_id: uni.getStorageSync('store_id') || '11001',
},
success: res => {
let req = this.$u.test.jsonString(res.data) ? JSON.parse(res
.data) : res.data
// console.log(req, 'req')
onSuccess: (res) => {
const req = this.$u.test.jsonString(res.data) ? JSON.parse(res.data) : res.data;
if (req.errcode == 0) {
toUploaded({
store_id: uni.getStorageSync('store_id') ||
'11001',
avatar: req.data.url
}).then((res) => {
if (res.errcode == 0) {
this.getInfo()
store_id: uni.getStorageSync('store_id') || '11001',
avatar: req.data.url,
}).then((uploadRes) => {
if (uploadRes.errcode == 0) {
this.getInfo();
this.$toast('编辑成功');
}
})
uni.hideLoading()
});
} else {
this.$toast(res.msg);
}
}
});
}
},
});
},
selectAct() {
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'],
success: (res) => {
uni.showLoading({
title: '请稍后...'
})
const tempFiles = res.tempFiles;
let resSize = tempFiles[0].size;
// 1M=1024KB=1048576B
console.log(resSize)
if (resSize > 1048576) {
uni.showToast({
title: "上传图片大小不能超过1MB",
icon: 'error'
});
return
}
uni.uploadFile({
url: 'https://api.xiaokang88.com/open-api/upload/old-admin-img',
filePath: res.tempFiles[0]['path'],
name: 'file',
header: {
authorization: `Bearer ${uni.getStorageSync('token')}`
},
chooseAvatarImage({
formData: {
store_id: uni.getStorageSync('store_id') || '11001'
store_id: uni.getStorageSync('store_id') || '11001',
},
success: res => {
let req = this.$u.test.jsonString(res.data) ? JSON.parse(res
.data) : res.data
// console.log(req, 'req')
onSuccess: (res) => {
const req = this.$u.test.jsonString(res.data) ? JSON.parse(res.data) : res.data;
if (req.errcode == 0) {
toUpload({
store_id: uni.getStorageSync('store_id') ||
'11001',
avatar: req.data.url
}).then((res) => {
if (res.errcode == 0) {
this.getDoctor()
store_id: uni.getStorageSync('store_id') || '11001',
avatar: req.data.url,
}).then((uploadRes) => {
if (uploadRes.errcode == 0) {
this.getDoctor();
this.$toast('编辑成功');
}
})
uni.hideLoading()
});
} else {
this.$toast(res.msg);
}
}
});
}
},
});
},
// 保存编辑

View File

@@ -32,19 +32,19 @@
<scroll-view class="selected-strip-scroll" scroll-x enable-flex>
<view class="selected-strip-inner flex-row">
<view
v-for="(sel, six) in selectedDrugs"
:key="'sch-' + six"
v-for="sel in selectedDrugs"
:key="sel._wxKey"
class="selected-chip flex-row flex-ali-center"
>
<view
class="selected-chip-main flex-row flex-ali-center"
:data-six="six"
:data-wx-key="sel._wxKey"
@click="handleSelectedChipSearch"
>
<text class="selected-chip-name">{{ sel.drug_name || sel.name || '—' }}</text>
<text class="selected-chip-dose">{{ String(sel.number || 0) }}{{ sel.unit && sel.unit.name ? sel.unit.name : 'g' }}</text>
</view>
<view class="selected-chip-close" :data-six="six" @click.stop="handleSelectedChipRemove">
<view class="selected-chip-close" :data-wx-key="sel._wxKey" @click.stop="handleSelectedChipRemove">
<u-icon name="close" size="22" color="#8A92A3"></u-icon>
</view>
</view>
@@ -174,6 +174,7 @@
<script>
// 保留所有原有逻辑代码与注释
import { getProductListDoctorReception, getChineseMedicineQuickGramsApi } from '@/api/reception.js';
import { withWxKey } from '@/utils/wxListKey.js';
export default {
name: 'ChineseMedicineModal',
@@ -217,7 +218,7 @@ export default {
value(newVal) {
this.show = newVal;
if (newVal) {
this.selectedDrugs = JSON.parse(JSON.stringify(this.currentDrugs));
this.selectedDrugs = this.mapSelectedDrugs(JSON.parse(JSON.stringify(this.currentDrugs)));
this.fetchQuickGrams();
const kw = (this.initialSearchKey || '').trim();
if (kw) {
@@ -261,9 +262,16 @@ export default {
/**
* 点击已选 chip用药名搜索列表小程序端勿在 @click 传对象,用 data-six + dataset
*/
mapSelectedDrugs(list) {
return withWxKey(list || [], 'index_id', 'sch');
},
findSelectedChipIndex(wxKey) {
return this.selectedDrugs.findIndex((s) => s._wxKey === wxKey);
},
handleSelectedChipSearch(e) {
const six = Number(e && e.currentTarget && e.currentTarget.dataset ? e.currentTarget.dataset.six : NaN);
if (Number.isNaN(six)) return;
const wxKey = e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.wxKey;
const six = this.findSelectedChipIndex(wxKey);
if (six < 0) return;
const sel = this.selectedDrugs[six];
if (!sel) return;
const name = String(sel.drug_name || sel.name || '').trim();
@@ -278,8 +286,9 @@ export default {
* 从已选条移除一味(不同步二次确认)
*/
handleSelectedChipRemove(e) {
const six = Number(e && e.currentTarget && e.currentTarget.dataset ? e.currentTarget.dataset.six : NaN);
if (Number.isNaN(six) || six < 0 || six >= this.selectedDrugs.length) return;
const wxKey = e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.wxKey;
const six = this.findSelectedChipIndex(wxKey);
if (six < 0 || six >= this.selectedDrugs.length) return;
this.selectedDrugs.splice(six, 1);
this.emitSelect();
const name = (this.searchKey || '').trim();
@@ -481,14 +490,18 @@ export default {
} else if (drug.name) {
drugName = drug.name;
}
const indexId = drug.id;
const entityId = (drug.drug && drug.drug.id) || drug.id;
const wxKeyBase = indexId != null && indexId !== '' ? String(indexId) : String(entityId || '');
return {
index_id: drug.id,
id: (drug.drug && drug.drug.id) || drug.id,
index_id: indexId,
id: entityId,
drug_name: drugName,
number: drug._quantity,
price: drug.price || 0,
way_id: (drug.drug && drug.drug.way_id) || drug.way_id || 0,
select_number: 1
select_number: 1,
_wxKey: wxKeyBase ? `sch-${wxKeyBase}` : `sch${this.selectedDrugs.length}`,
};
},

View File

@@ -179,6 +179,7 @@
officeList,
newChek
} from '../../../../api/all';
import { chooseAvatarImage } from '@/common/js/select-avatar-image.js';
// } from '@/api/all.js'
export default {
@@ -338,58 +339,25 @@
uni.hideLoading()
},
selectAct() {
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'],
success: (res) => {
uni.showLoading({
title: '请稍后...'
})
const tempFiles = res.tempFiles;
let resSize = tempFiles[0].size;
// 1M=1024KB=1048576B
console.log(resSize)
if (resSize > 1048576) {
uni.showToast({
title: "上传图片大小不能超过1MB",
icon: 'error'
});
return
}
uni.uploadFile({
url: 'https://api.xiaokang88.com/open-api/upload/old-admin-img',
filePath: res.tempFiles[0]['path'],
name: 'file',
header: {
authorization: `Bearer ${uni.getStorageSync('token')}`
},
chooseAvatarImage({
formData: {
store_id: '11001'
store_id: '11001',
},
success: res => {
let req = this.$u.test.jsonString(res.data) ? JSON.parse(res
.data) : res.data
onSuccess: (res) => {
const req = this.$u.test.jsonString(res.data) ? JSON.parse(res.data) : res.data;
if (req.errcode == 0) {
this.avatarShow = false
this.form.avatar = req.data.url
uni.hideLoading()
this.avatarShow = false;
this.form.avatar = req.data.url;
} else {
this.$toast(res.msg)
this.$toast(res.msg);
}
},
fail: e => {
this.avatarShow = false
onCancel: () => {
this.avatarShow = false;
},
});
onFail: () => {
this.avatarShow = false;
},
complete: (res) => {
if (res.errMsg == "chooseImage:fail cancel") {
this.avatarShow = false
}
}
});
},
checkboxChange(e, id) {