更新
This commit is contained in:
+3
-1
@@ -2,6 +2,7 @@
|
||||
import { useDark, useThrottleFn, useWindowSize } from '@vueuse/core'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
|
||||
|
||||
import { ScreenEnum } from './enums/appEnums'
|
||||
import useAppStore from './stores/modules/app'
|
||||
import useSettingStore from './stores/modules/setting'
|
||||
@@ -9,7 +10,7 @@ import useSettingStore from './stores/modules/setting'
|
||||
const appStore = useAppStore()
|
||||
const settingStore = useSettingStore()
|
||||
const elConfig = {
|
||||
zIndex: 3000,
|
||||
zIndex: 2000,
|
||||
locale: zhCn
|
||||
}
|
||||
const isDark = useDark()
|
||||
@@ -42,6 +43,7 @@ watch(
|
||||
<template>
|
||||
<el-config-provider :locale="elConfig.locale" :z-index="elConfig.zIndex">
|
||||
<router-view />
|
||||
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 订单列表
|
||||
export function orderLists(params: any) {
|
||||
return request.get({ url: '/order.order/lists', params })
|
||||
}
|
||||
|
||||
// 订单详情
|
||||
export function orderDetail(params: any) {
|
||||
return request.get({ url: '/order.order/detail', params })
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
export function orderCreate(params: any) {
|
||||
return request.post({ url: '/order.order/create', params })
|
||||
}
|
||||
|
||||
// 编辑订单
|
||||
export function orderEdit(params: any) {
|
||||
return request.post({ url: '/order.order/edit', params })
|
||||
}
|
||||
|
||||
// 删除订单
|
||||
export function orderDelete(params: any) {
|
||||
return request.post({ url: '/order.order/delete', params })
|
||||
}
|
||||
|
||||
// 支付订单
|
||||
export function orderPay(params: any) {
|
||||
return request.post({ url: '/order.order/pay', params })
|
||||
}
|
||||
|
||||
// 取消订单
|
||||
export function orderCancel(params: any) {
|
||||
return request.post({ url: '/order.order/cancel', params })
|
||||
}
|
||||
|
||||
// 退款订单
|
||||
export function orderRefund(params: any) {
|
||||
return request.post({ url: '/order.order/refund', params })
|
||||
}
|
||||
|
||||
// 导出订单
|
||||
export function orderExport(params: any) {
|
||||
return request.get({ url: '/order.order/export', params }, { isReturnDefaultResponse: true })
|
||||
}
|
||||
|
||||
// 搜索患者(从诊单表)
|
||||
export function searchPatients(params: any) {
|
||||
return request.get({ url: '/tcm.diagnosis/searchPatient', params })
|
||||
}
|
||||
@@ -1 +1,24 @@
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}:root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,*:after,*:before{box-sizing:border-box}ul,li{list-style:none;padding:0;margin:0}picture,img,video,canvas,svg{display:block;max-width:100%}img{max-width:100%;height:auto;vertical-align:middle;image-rendering:-webkit-optimize-contrast;aspect-ratio:attr(width)/attr(height);display:inline-block;-webkit-user-drag:none;-webkit-user-select:none;user-select:none}img:not([src],[srcset]){visibility:hidden}
|
||||
|
||||
/* 修复表情选择器等弹出层被遮挡的问题 */
|
||||
[data-reka-popper-content-wrapper],
|
||||
[data-reka-popper],
|
||||
.el-popper,
|
||||
.el-picker-panel {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
/* 确保弹出层容器也有正确的层级 */
|
||||
body > div[id^="el-popper-container"],
|
||||
body > div[data-reka-focus-guard],
|
||||
body > div[data-reka-popper-content-wrapper] {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
/* TUICallKit 视频通话窗口样式 - 确保在最上层 */
|
||||
.chat-dialog-call-kit,
|
||||
body > div[class*="TUICallKit"],
|
||||
body > .TUICallKit-desktop,
|
||||
body > .TUICallKit-mobile {
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="`与 ${patientName} 聊天`"
|
||||
width="1200px"
|
||||
top="5vh"
|
||||
width="900px"
|
||||
top="10vh"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
:destroy-on-close="true"
|
||||
@@ -18,34 +18,62 @@
|
||||
<el-alert :title="error" type="error" :closable="false" />
|
||||
</div>
|
||||
<div v-else class="chat-content">
|
||||
<UIKitProvider>
|
||||
<UIKitProvider language="zh-CN" theme="light">
|
||||
<div class="chat-layout">
|
||||
<ConversationList class="conversation-list" />
|
||||
<Chat class="chat-area">
|
||||
<MessageList />
|
||||
<MessageInput />
|
||||
<MessageList :conversationID="conversationId"/>
|
||||
<MessageInput>
|
||||
<template #headerToolbar>
|
||||
<div class="message-toolbar">
|
||||
<EmojiPicker />
|
||||
<ImagePicker />
|
||||
<FilePicker />
|
||||
<AudioCallPicker />
|
||||
<VideoCallPicker />
|
||||
</div>
|
||||
</template>
|
||||
</MessageInput>
|
||||
</Chat>
|
||||
</div>
|
||||
<!-- TUICallKit 放在 dialog 外部,独立渲染 -->
|
||||
|
||||
</UIKitProvider>
|
||||
</div>
|
||||
</div>
|
||||
<TUICallKit
|
||||
|
||||
:allowedMinimized="true"
|
||||
:allowedFullScreen="true"
|
||||
class="chat-dialog-call-kit"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, nextTick, watch } from 'vue'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import { getCallSignature } from '@/api/tcm'
|
||||
import feedback from '@/utils/feedback'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import {
|
||||
ConversationList,
|
||||
Chat,
|
||||
MessageList,
|
||||
MessageInput,
|
||||
UIKitProvider,
|
||||
useLoginState
|
||||
useLoginState,
|
||||
useConversationListState,
|
||||
EmojiPicker,
|
||||
ImagePicker,
|
||||
FilePicker,
|
||||
AudioCallPicker,
|
||||
VideoCallPicker
|
||||
} from '@tencentcloud/chat-uikit-vue3'
|
||||
import TencentCloudChat from '@tencentcloud/chat'
|
||||
import '@/assets/chat-uikit.css'
|
||||
import { TUICallKit } from '@tencentcloud/call-uikit-vue'
|
||||
|
||||
const visible = ref(false)
|
||||
const isReady = ref(false)
|
||||
@@ -55,8 +83,130 @@ const patientId = ref<number | null>(null)
|
||||
const diagnosisId = ref<number | null>(null)
|
||||
const loadingText = ref('正在初始化...')
|
||||
const patientUserId = ref('')
|
||||
|
||||
const { login, logout } = useLoginState()
|
||||
const { setActiveConversation, createC2CConversation, activeConversation } = useConversationListState()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 更新用户头像到 IM
|
||||
const updateUserAvatarToIM = async (avatarUrl: string,appid: number) => {
|
||||
try {
|
||||
if (!avatarUrl) {
|
||||
console.warn('头像 URL 为空,跳过更新')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('开始更新头像到 IM:', avatarUrl)
|
||||
|
||||
// 尝试通过 SDK 实例更新头像
|
||||
// 在 UIKit 登录后,SDK 实例应该已初始化
|
||||
const updateResult = await new Promise((resolve, reject) => {
|
||||
// 延迟执行,确保 SDK 完全初始化
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
// 尝试多种方式获取 SDK 实例
|
||||
|
||||
let chat = TencentCloudChat.create( { SDKAppID: appid });
|
||||
// 调用 updateMyProfile 更新用户头像
|
||||
const response = await chat.updateMyProfile({
|
||||
avatar: avatarUrl
|
||||
})
|
||||
|
||||
console.log('IM 头像更新成功:', response)
|
||||
resolve(response)
|
||||
} catch (err) {
|
||||
console.error('更新头像异常:', err)
|
||||
resolve(null)
|
||||
}
|
||||
}, 500)
|
||||
})
|
||||
|
||||
} catch (err: any) {
|
||||
console.error('IM 头像更新失败:', err.message || err)
|
||||
// 不中断主流程,头像更新失败不影响聊天功能
|
||||
}
|
||||
}
|
||||
|
||||
// 监听当前激活的会话变化,更新标题
|
||||
watch(() => activeConversation.value, (newConversation) => {
|
||||
if (newConversation) {
|
||||
// 更新标题为当前会话的显示名称
|
||||
patientName.value = newConversation.getShowName() || patientName.value
|
||||
console.log('会话切换:', newConversation.conversationID, '名称:', patientName.value)
|
||||
}
|
||||
})
|
||||
|
||||
// 限制 TUICallKit 拖动范围 - 使用事件监听而不是 MutationObserver
|
||||
const setupCallKitDragLimit = () => {
|
||||
setTimeout(() => {
|
||||
const callKitElements = document.querySelectorAll('[class*="TUICallKit"], [id*="tui-call"]')
|
||||
|
||||
callKitElements.forEach((element: any) => {
|
||||
if (!element) return
|
||||
|
||||
// 监听鼠标释放事件(拖动结束)
|
||||
element.addEventListener('mouseup', () => {
|
||||
setTimeout(() => {
|
||||
const rect = element.getBoundingClientRect()
|
||||
const dialogElement = document.querySelector('.chat-dialog .el-dialog')
|
||||
|
||||
if (!dialogElement) return
|
||||
|
||||
const dialogRect = dialogElement.getBoundingClientRect()
|
||||
|
||||
// 获取当前位置
|
||||
const currentLeft = parseInt(element.style.left || '0')
|
||||
const currentTop = parseInt(element.style.top || '0')
|
||||
|
||||
let newLeft = currentLeft
|
||||
let newTop = currentTop
|
||||
let needAdjust = false
|
||||
|
||||
// 限制左边界
|
||||
if (rect.left < dialogRect.left) {
|
||||
newLeft = currentLeft + (dialogRect.left - rect.left)
|
||||
needAdjust = true
|
||||
}
|
||||
|
||||
// 限制右边界
|
||||
if (rect.right > dialogRect.right) {
|
||||
newLeft = currentLeft - (rect.right - dialogRect.right)
|
||||
needAdjust = true
|
||||
}
|
||||
|
||||
// 限制上边界
|
||||
if (rect.top < dialogRect.top) {
|
||||
newTop = currentTop + (dialogRect.top - rect.top)
|
||||
needAdjust = true
|
||||
}
|
||||
|
||||
// 限制下边界
|
||||
if (rect.bottom > dialogRect.bottom) {
|
||||
newTop = currentTop - (rect.bottom - dialogRect.bottom)
|
||||
needAdjust = true
|
||||
}
|
||||
|
||||
// 应用新位置(使用过渡动画)
|
||||
if (needAdjust) {
|
||||
element.style.transition = 'left 0.3s ease, top 0.3s ease'
|
||||
element.style.left = `${newLeft}px`
|
||||
element.style.top = `${newTop}px`
|
||||
|
||||
setTimeout(() => {
|
||||
element.style.transition = ''
|
||||
}, 300)
|
||||
}
|
||||
}, 10)
|
||||
})
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 监听 isReady 变化,当通话组件加载后设置拖动限制
|
||||
watch(() => isReady.value, (ready) => {
|
||||
if (ready) {
|
||||
setupCallKitDragLimit()
|
||||
}
|
||||
})
|
||||
|
||||
const open = async (data: { patientId: number; patientName: string; diagnosisId?: number }) => {
|
||||
visible.value = true
|
||||
@@ -82,24 +232,52 @@ const open = async (data: { patientId: number; patientName: string; diagnosisId?
|
||||
|
||||
patientUserId.value = res.patientUserId || `patient_${data.patientId}`
|
||||
|
||||
loadingText.value = '正在登录聊天系统...'
|
||||
loadingText.value = '正在登录聊天...'
|
||||
|
||||
// 登录 IM
|
||||
// 登录 Chat UIKit
|
||||
await login({
|
||||
sdkAppId: Number(res.sdkAppId),
|
||||
userId: res.userId,
|
||||
userSig: res.userSig,
|
||||
useUploadPlugin: true
|
||||
})
|
||||
const sdkAPPid=Number(res.sdkAppId);
|
||||
|
||||
console.log('IM 登录成功')
|
||||
console.log('Chat UIKit 登录成功,患者用户ID:', patientUserId.value)
|
||||
|
||||
loadingText.value = '加载聊天界面...'
|
||||
|
||||
// 等待一下让组件完全初始化
|
||||
setTimeout(() => {
|
||||
// 等待 UIKit 初始化完成后创建并激活会话
|
||||
setTimeout(async () => {
|
||||
isReady.value = true
|
||||
}, 500)
|
||||
|
||||
// 使用 nextTick 确保组件已渲染
|
||||
await nextTick()
|
||||
|
||||
// 增加延迟,确保 TIM SDK 完全初始化
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
// 更新用户头像到 IM - 从 Pinia store 获取当前登录用户的头像
|
||||
const avatar = userStore.userInfo?.avatar
|
||||
console.log('准备更新头像,avatar:', avatar)
|
||||
|
||||
if (avatar) {
|
||||
await updateUserAvatarToIM(avatar,sdkAPPid)
|
||||
}
|
||||
|
||||
// 创建或获取与患者的单聊会话
|
||||
try {
|
||||
const conversation = await createC2CConversation(patientUserId.value)
|
||||
conversationId.value = conversation.conversationID
|
||||
console.log('已创建/获取会话:', conversationId.value)
|
||||
|
||||
// 激活该会话
|
||||
setActiveConversation(conversationId.value)
|
||||
console.log('已激活会话')
|
||||
} catch (err) {
|
||||
console.error('创建/激活会话失败:', err)
|
||||
}
|
||||
}, 800)
|
||||
|
||||
} catch (err: any) {
|
||||
console.error('初始化聊天失败:', err)
|
||||
@@ -108,15 +286,21 @@ const open = async (data: { patientId: number; patientName: string; diagnosisId?
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
// 登出
|
||||
logout()
|
||||
const handleClose = async () => {
|
||||
try {
|
||||
// 登出 Chat
|
||||
// await logout()
|
||||
} catch (err) {
|
||||
console.error('登出失败:', err)
|
||||
}
|
||||
|
||||
visible.value = false
|
||||
isReady.value = false
|
||||
error.value = ''
|
||||
patientId.value = null
|
||||
diagnosisId.value = null
|
||||
patientUserId.value = ''
|
||||
// isReady.value = false
|
||||
// error.value = ''
|
||||
// patientId.value = null
|
||||
// diagnosisId.value = null
|
||||
// patientUserId.value = ''
|
||||
// conversationId.value = ''
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
@@ -127,12 +311,23 @@ defineExpose({ open })
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 0;
|
||||
height: 75vh;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
:deep(.el-dialog__header) {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
// 确保对话框有合适的 z-index
|
||||
:deep(.el-overlay) {
|
||||
z-index: 2500;
|
||||
}
|
||||
|
||||
// 确保对话框本身的 z-index 低于 TUICallKit
|
||||
:deep(.el-dialog) {
|
||||
z-index: 2501;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
@@ -163,6 +358,7 @@ defineExpose({ open })
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chat-layout {
|
||||
@@ -179,7 +375,85 @@ defineExpose({ open })
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.empty-chat {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 消息工具栏样式 */
|
||||
.message-toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式:确保表情选择器等弹出层有足够高的 z-index */
|
||||
.el-popper,
|
||||
.el-picker-panel,
|
||||
[data-reka-popper],
|
||||
[data-reka-popper-content-wrapper],
|
||||
[class*="emoji-picker"],
|
||||
[class*="picker-popup"],
|
||||
[class*="tui-picker"],
|
||||
body > div[id^="el-popper-container"],
|
||||
body > div[data-reka-focus-guard] {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
/* 确保聊天对话框内的弹出层也能正确显示 */
|
||||
.chat-dialog [data-reka-popper-content-wrapper] {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
/* TUICallKit 容器样式 - 限制在对话框内拖动 */
|
||||
.chat-dialog-call-kit {
|
||||
position: fixed !important;
|
||||
top: 50% !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
width: 600px !important;
|
||||
height: 400px !important;
|
||||
max-width: 90% !important;
|
||||
max-height: 80% !important;
|
||||
z-index: 300000 !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.float-window-container{
|
||||
z-index: 3000;
|
||||
}
|
||||
|
||||
/* 限制 TUICallKit 的拖动范围在对话框内 */
|
||||
.chat-content {
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
/* 确保 TUICallKit 相关的所有容器都在对话框之上 */
|
||||
body > div[class*="TUICallKit"],
|
||||
body > div[id*="tui-call"],
|
||||
body > div[class*="t-call"],
|
||||
body > .TUICallKit-desktop,
|
||||
body > .TUICallKit-mobile {
|
||||
position: fixed !important;
|
||||
z-index: 300000 !important;
|
||||
max-width: 90vw !important;
|
||||
max-height: 90vh !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* 确保最小化后的通话窗口也在最上层 */
|
||||
[class*="TUICallKit"][class*="minimized"],
|
||||
[class*="TUICallKit"][class*="minimize"],
|
||||
[class*="call-kit-mini"],
|
||||
[class*="t-call-mini"] {
|
||||
z-index: 300000 !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -998,15 +998,7 @@ defineExpose({
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* 隐藏 TUICallKit 自带的全屏容器 */
|
||||
:global(.TUICallKit-desktop),
|
||||
:global(.TUICallKit-mobile),
|
||||
:global(body > .TUICallKit-desktop),
|
||||
:global(body > .TUICallKit-mobile) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* 只显示我们窗口内的 TUICallKit */
|
||||
/* 只在我们的浮动窗口内显示 TUICallKit */
|
||||
.floating-video-window .TUICallKit-desktop,
|
||||
.floating-video-window .TUICallKit-mobile {
|
||||
display: block !important;
|
||||
@@ -1016,14 +1008,8 @@ defineExpose({
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
/* 确保 TUICallKit 不会创建遮罩层 */
|
||||
/* 确保 Element Plus 的遮罩层不会覆盖视频通话 */
|
||||
:global(.el-overlay) {
|
||||
z-index: 1000 !important;
|
||||
}
|
||||
|
||||
/* 隐藏所有可能的 TUICallKit 弹出层 */
|
||||
:global(body > div[class*="TUICall"]),
|
||||
:global(body > div[id*="tui-call"]) {
|
||||
display: none !important;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,6 +3,7 @@ import './styles/index.scss'
|
||||
import 'virtual:svg-icons-register'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { TUICallKit } from '@trtc/calls-uikit-vue'
|
||||
|
||||
import { getConfig } from './api/app'
|
||||
import App from './App.vue'
|
||||
@@ -10,6 +11,7 @@ import install from './install'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(install)
|
||||
app.use(TUICallKit)
|
||||
app.mount('#app')
|
||||
|
||||
getConfig().then((res) => {
|
||||
|
||||
@@ -0,0 +1,731 @@
|
||||
<!-- 订单列表 -->
|
||||
<template>
|
||||
<div class="order-list">
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form class="ls-form" :model="queryParams" inline>
|
||||
<el-form-item class="w-[280px]" label="订单号">
|
||||
<el-input
|
||||
v-model="queryParams.order_no"
|
||||
placeholder="请输入订单号"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item class="w-[280px]" label="患者信息">
|
||||
<el-input
|
||||
v-model="queryParams.patient_keyword"
|
||||
placeholder="患者姓名/手机号"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item class="w-[280px]" label="订单类型">
|
||||
<el-select v-model="queryParams.order_type" placeholder="请选择" clearable>
|
||||
<el-option label="挂号费" :value="1" />
|
||||
<el-option label="问诊费" :value="2" />
|
||||
<el-option label="药品费用" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item class="w-[280px]" label="订单状态">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择" clearable>
|
||||
<el-option label="待支付" :value="1" />
|
||||
<el-option label="已支付" :value="2" />
|
||||
<el-option label="已取消" :value="3" />
|
||||
<el-option label="已退款" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="创建时间">
|
||||
<daterange-picker
|
||||
v-model:startTime="queryParams.create_time_start"
|
||||
v-model:endTime="queryParams.create_time_end"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
<export-data
|
||||
class="ml-2.5"
|
||||
:fetch-fun="orderExport"
|
||||
:params="queryParams"
|
||||
:page-size="pager.size"
|
||||
/>
|
||||
<el-button
|
||||
v-perms="['order.order/create']"
|
||||
type="success"
|
||||
class="ml-2.5"
|
||||
@click="handleCreate"
|
||||
>
|
||||
+ 创建订单
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<el-table
|
||||
v-loading="pager.loading"
|
||||
:data="pager.lists"
|
||||
size="large"
|
||||
>
|
||||
<el-table-column label="订单号" prop="order_no" min-width="150" />
|
||||
|
||||
<el-table-column label="患者信息" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.patient_name }}</div>
|
||||
<div class="text-xs text-gray-400">{{ row.patient_phone }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="创建人" prop="creator_name" min-width="120" />
|
||||
|
||||
<el-table-column label="订单类型" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getOrderTypeTag(row.order_type)">
|
||||
{{ getOrderTypeText(row.order_type) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="金额" width="100">
|
||||
<template #default="{ row }">
|
||||
<span class="text-red-500 font-semibold">¥{{ row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="支付方式" width="100">
|
||||
<template #default="{ row }">
|
||||
{{ getPaymentMethodText(row.payment_method) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="订单状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusTag(row.status)">
|
||||
{{ getStatusText(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="支付时间" min-width="160">
|
||||
<template #default="{ row }">
|
||||
{{ row.payment_time || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="创建时间" min-width="160">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="280" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-perms="['order.order/detail']"
|
||||
type="primary"
|
||||
link
|
||||
@click="handleDetail(row)"
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 1"
|
||||
v-perms="['order.order/pay']"
|
||||
type="success"
|
||||
link
|
||||
@click="handlePay(row)"
|
||||
>
|
||||
支付
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 2"
|
||||
v-perms="['order.order/refund']"
|
||||
type="warning"
|
||||
link
|
||||
@click="handleRefund(row)"
|
||||
>
|
||||
退款
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 1"
|
||||
v-perms="['order.order/cancel']"
|
||||
type="danger"
|
||||
link
|
||||
@click="handleCancel(row)"
|
||||
>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['order.order/delete']"
|
||||
type="danger"
|
||||
link
|
||||
@click="handleDelete(row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
<pagination v-model="pager" @change="getLists" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<el-dialog
|
||||
v-model="detailVisible"
|
||||
title="订单详情"
|
||||
width="700px"
|
||||
>
|
||||
<el-descriptions :column="2" border v-if="detailData">
|
||||
<el-descriptions-item label="订单号">
|
||||
{{ detailData.order_no }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单状态">
|
||||
<el-tag :type="getStatusTag(detailData.status)">
|
||||
{{ getStatusText(detailData.status) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="患者姓名">
|
||||
{{ detailData.patient_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="患者电话">
|
||||
{{ detailData.patient_phone }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">
|
||||
{{ detailData.creator_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单类型">
|
||||
<el-tag :type="getOrderTypeTag(detailData.order_type)">
|
||||
{{ getOrderTypeText(detailData.order_type) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单金额">
|
||||
<span class="text-red-500 font-semibold">¥{{ detailData.amount }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="支付方式">
|
||||
{{ getPaymentMethodText(detailData.payment_method) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="支付时间">
|
||||
{{ detailData.payment_time || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ detailData.create_time }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">
|
||||
{{ detailData.remark || '无' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 订单详情项 -->
|
||||
<el-divider>订单详情</el-divider>
|
||||
<el-table :data="detailData?.details || []" size="small">
|
||||
<el-table-column label="关联类型" prop="related_type" width="100">
|
||||
<template #default="{ row }">
|
||||
{{ getRelatedTypeText(row.related_type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" prop="quantity" width="80" />
|
||||
<el-table-column label="单价" width="100">
|
||||
<template #default="{ row }">
|
||||
¥{{ row.unit_price }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总价" width="100">
|
||||
<template #default="{ row }">
|
||||
¥{{ row.total_price }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 支付弹窗 -->
|
||||
<el-dialog
|
||||
v-model="payDialogVisible"
|
||||
title="订单支付"
|
||||
width="500px"
|
||||
>
|
||||
<el-form :model="payForm" label-width="100px">
|
||||
<el-form-item label="订单号">
|
||||
<span>{{ payForm.order_no }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单金额">
|
||||
<span class="text-red-500 font-semibold">¥{{ payForm.amount }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="支付方式" required>
|
||||
<el-radio-group v-model="payForm.payment_method">
|
||||
<el-radio label="alipay">支付宝</el-radio>
|
||||
<el-radio label="wechat">微信</el-radio>
|
||||
<el-radio label="bank">银行卡</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="payDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmPay" :loading="payLoading">确认支付</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 创建订单弹窗 -->
|
||||
<el-dialog
|
||||
v-model="createDialogVisible"
|
||||
title="创建订单"
|
||||
width="600px"
|
||||
@close="resetCreateForm"
|
||||
>
|
||||
<el-form
|
||||
ref="createFormRef"
|
||||
:model="createForm"
|
||||
:rules="createRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="患者" prop="patient_id">
|
||||
<el-select
|
||||
v-model="createForm.patient_id"
|
||||
placeholder="请选择患者"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchPatients"
|
||||
:loading="patientLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in patientList"
|
||||
:key="item.id"
|
||||
:label="`${item.nickname} (${item.mobile})`"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="订单类型" prop="order_type">
|
||||
<el-select v-model="createForm.order_type" placeholder="请选择">
|
||||
<el-option label="挂号费" :value="1" />
|
||||
<el-option label="问诊费" :value="2" />
|
||||
<el-option label="药品费用" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="订单金额" prop="amount">
|
||||
<el-input-number
|
||||
v-model="createForm.amount"
|
||||
:min="0"
|
||||
:step="0.01"
|
||||
:precision="2"
|
||||
placeholder="请输入金额"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="createForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注(可选)"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="订单详情">
|
||||
<div class="w-full">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="addOrderDetail"
|
||||
>
|
||||
+ 添加订单项
|
||||
</el-button>
|
||||
<el-table :data="createForm.details" class="mt-3">
|
||||
<el-table-column label="关联类型" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-select
|
||||
v-model="row.related_type"
|
||||
placeholder="请选择"
|
||||
size="small"
|
||||
>
|
||||
<el-option label="挂号" value="appointment" />
|
||||
<el-option label="问诊" value="diagnosis" />
|
||||
<el-option label="药品" value="medicine" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联ID" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-input
|
||||
v-model.number="row.related_id"
|
||||
type="number"
|
||||
placeholder="ID"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" width="80">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
v-model="row.quantity"
|
||||
:min="1"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单价" width="100">
|
||||
<template #default="{ row, $index }">
|
||||
<el-input-number
|
||||
v-model="row.unit_price"
|
||||
:min="0"
|
||||
:step="0.01"
|
||||
:precision="2"
|
||||
size="small"
|
||||
@change="updateDetailTotal($index)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总价" width="100">
|
||||
<template #default="{ row }">
|
||||
<span>{{ (row.quantity * row.unit_price).toFixed(2) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template #default="{ row, $index }">
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click="removeOrderDetail($index)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="createDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitCreateOrder" :loading="createLoading">
|
||||
创建订单
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="orderList">
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import { orderLists, orderDetail, orderPay, orderCancel, orderDelete, orderRefund, orderExport, orderCreate, searchPatients as searchPatientsAPI } from '@/api/order'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
const queryParams = reactive({
|
||||
order_no: '',
|
||||
patient_keyword: '',
|
||||
order_type: '',
|
||||
status: '',
|
||||
create_time_start: '',
|
||||
create_time_end: ''
|
||||
})
|
||||
|
||||
const { pager, getLists, resetPage, resetParams } = usePaging({
|
||||
fetchFun: orderLists,
|
||||
params: queryParams
|
||||
})
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
resetPage()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
resetParams()
|
||||
}
|
||||
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref<any>(null)
|
||||
const payDialogVisible = ref(false)
|
||||
const payLoading = ref(false)
|
||||
const payForm = ref({
|
||||
order_id: 0,
|
||||
order_no: '',
|
||||
amount: 0,
|
||||
payment_method: 'alipay'
|
||||
})
|
||||
|
||||
// 创建订单相关
|
||||
const createDialogVisible = ref(false)
|
||||
const createFormRef = ref()
|
||||
const createLoading = ref(false)
|
||||
const patientLoading = ref(false)
|
||||
const patientList = ref<any[]>([])
|
||||
|
||||
const createForm = reactive({
|
||||
patient_id: '',
|
||||
order_type: '',
|
||||
amount: 0,
|
||||
remark: '',
|
||||
details: [] as any[]
|
||||
})
|
||||
|
||||
const createRules = {
|
||||
patient_id: [{ required: true, message: '请选择患者', trigger: 'change' }],
|
||||
order_type: [{ required: true, message: '请选择订单类型', trigger: 'change' }],
|
||||
amount: [{ required: true, message: '请输入订单金额', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 搜索患者
|
||||
const searchPatients = async (query: string) => {
|
||||
if (!query) {
|
||||
patientList.value = []
|
||||
return
|
||||
}
|
||||
try {
|
||||
patientLoading.value = true
|
||||
const res = await searchPatientsAPI({
|
||||
keyword: query,
|
||||
page_no: 1,
|
||||
page_size: 10
|
||||
})
|
||||
patientList.value = res?.lists || []
|
||||
} catch (error) {
|
||||
console.error('搜索患者失败:', error)
|
||||
} finally {
|
||||
patientLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 添加订单项
|
||||
const addOrderDetail = () => {
|
||||
createForm.details.push({
|
||||
related_type: '',
|
||||
related_id: '',
|
||||
quantity: 1,
|
||||
unit_price: 0,
|
||||
total_price: 0
|
||||
})
|
||||
}
|
||||
|
||||
// 删除订单项
|
||||
const removeOrderDetail = (index: number) => {
|
||||
createForm.details.splice(index, 1)
|
||||
}
|
||||
|
||||
// 更新订单项总价
|
||||
const updateDetailTotal = (index: number) => {
|
||||
const detail = createForm.details[index]
|
||||
detail.total_price = detail.quantity * detail.unit_price
|
||||
}
|
||||
|
||||
// 重置创建表单
|
||||
const resetCreateForm = () => {
|
||||
createForm.patient_id = ''
|
||||
createForm.order_type = ''
|
||||
createForm.amount = 0
|
||||
createForm.remark = ''
|
||||
createForm.details = []
|
||||
createFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
// 打开创建订单弹窗
|
||||
const handleCreate = () => {
|
||||
resetCreateForm()
|
||||
createDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提交创建订单
|
||||
const submitCreateOrder = async () => {
|
||||
try {
|
||||
await createFormRef.value?.validate()
|
||||
|
||||
if (createForm.details.length === 0) {
|
||||
feedback.msgWarning('请至少添加一个订单项')
|
||||
return
|
||||
}
|
||||
|
||||
createLoading.value = true
|
||||
|
||||
// 计算总金额
|
||||
const totalAmount = createForm.details.reduce((sum, detail) => {
|
||||
return sum + (detail.quantity * detail.unit_price)
|
||||
}, 0)
|
||||
|
||||
const params = {
|
||||
patient_id: createForm.patient_id,
|
||||
order_type: createForm.order_type,
|
||||
amount: totalAmount,
|
||||
remark: createForm.remark,
|
||||
details: createForm.details.map(detail => ({
|
||||
related_type: detail.related_type,
|
||||
related_id: detail.related_id,
|
||||
quantity: detail.quantity,
|
||||
unit_price: detail.unit_price,
|
||||
total_price: detail.quantity * detail.unit_price
|
||||
}))
|
||||
}
|
||||
|
||||
await orderCreate(params)
|
||||
feedback.msgSuccess('订单创建成功')
|
||||
createDialogVisible.value = false
|
||||
getLists()
|
||||
} catch (error) {
|
||||
console.error('创建订单失败:', error)
|
||||
} finally {
|
||||
createLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取订单类型文本
|
||||
const getOrderTypeText = (type: number) => {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: '挂号费',
|
||||
2: '问诊费',
|
||||
3: '药品费用'
|
||||
}
|
||||
return typeMap[type] || '未知'
|
||||
}
|
||||
|
||||
// 获取订单类型标签类型
|
||||
const getOrderTypeTag = (type: number): 'success' | 'info' | 'warning' => {
|
||||
const tagMap: Record<number, 'success' | 'info' | 'warning'> = {
|
||||
1: 'success',
|
||||
2: 'info',
|
||||
3: 'warning'
|
||||
}
|
||||
return tagMap[type] || 'info'
|
||||
}
|
||||
|
||||
// 获取订单状态文本
|
||||
const getStatusText = (status: number) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '待支付',
|
||||
2: '已支付',
|
||||
3: '已取消',
|
||||
4: '已退款'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
// 获取订单状态标签类型
|
||||
const getStatusTag = (status: number): 'warning' | 'success' | 'info' | 'danger' => {
|
||||
const tagMap: Record<number, 'warning' | 'success' | 'info' | 'danger'> = {
|
||||
1: 'warning',
|
||||
2: 'success',
|
||||
3: 'info',
|
||||
4: 'danger'
|
||||
}
|
||||
return tagMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 获取支付方式文本
|
||||
const getPaymentMethodText = (method: string | null) => {
|
||||
if (!method) return '-'
|
||||
const methodMap: Record<string, string> = {
|
||||
alipay: '支付宝',
|
||||
wechat: '微信',
|
||||
bank: '银行卡'
|
||||
}
|
||||
return methodMap[method] || '未知'
|
||||
}
|
||||
|
||||
// 获取关联类型文本
|
||||
const getRelatedTypeText = (type: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
appointment: '挂号',
|
||||
diagnosis: '问诊',
|
||||
medicine: '药品'
|
||||
}
|
||||
return typeMap[type] || '未知'
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = async (row: any) => {
|
||||
try {
|
||||
const res = await orderDetail({ id: row.id })
|
||||
detailData.value = res
|
||||
detailVisible.value = true
|
||||
} catch (error) {
|
||||
console.error('获取详情失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 支付订单
|
||||
const handlePay = (row: any) => {
|
||||
payForm.value = {
|
||||
order_id: row.id,
|
||||
order_no: row.order_no,
|
||||
amount: row.amount,
|
||||
payment_method: 'alipay'
|
||||
}
|
||||
payDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认支付
|
||||
const confirmPay = async () => {
|
||||
try {
|
||||
payLoading.value = true
|
||||
await orderPay({
|
||||
id: payForm.value.order_id,
|
||||
payment_method: payForm.value.payment_method
|
||||
})
|
||||
feedback.msgSuccess('支付成功')
|
||||
payDialogVisible.value = false
|
||||
getLists()
|
||||
} catch (error) {
|
||||
console.error('支付失败:', error)
|
||||
} finally {
|
||||
payLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 取消订单
|
||||
const handleCancel = async (row: any) => {
|
||||
try {
|
||||
await feedback.confirm('确定要取消该订单吗?')
|
||||
await orderCancel({ id: row.id })
|
||||
feedback.msgSuccess('取消成功')
|
||||
getLists()
|
||||
} catch (error) {
|
||||
// 用户取消操作
|
||||
}
|
||||
}
|
||||
|
||||
// 退款订单
|
||||
const handleRefund = async (row: any) => {
|
||||
try {
|
||||
await feedback.confirm('确定要退款该订单吗?')
|
||||
await orderRefund({ id: row.id })
|
||||
feedback.msgSuccess('退款成功')
|
||||
getLists()
|
||||
} catch (error) {
|
||||
// 用户取消操作
|
||||
}
|
||||
}
|
||||
|
||||
// 删除订单
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await feedback.confirm('确定要删除该订单吗?此操作不可恢复')
|
||||
await orderDelete({ id: row.id })
|
||||
feedback.msgSuccess('删除成功')
|
||||
getLists()
|
||||
} catch (error) {
|
||||
// 用户取消操作
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getLists()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.order-list {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -193,7 +193,7 @@
|
||||
v-perms="['doctor.appointment/prescription']"
|
||||
type="success"
|
||||
link
|
||||
@click="handleCreatePrescription(row)"
|
||||
@click="handleChat(row)"
|
||||
>
|
||||
聊天
|
||||
</el-button>
|
||||
@@ -271,6 +271,7 @@
|
||||
<script setup lang="ts">
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import { appointmentLists, cancelAppointment, completeAppointment, appointmentDetail } from '@/api/doctor'
|
||||
import { getCallSignature } from '@/api/tcm'
|
||||
import feedback from '@/utils/feedback'
|
||||
import EditPopup from '../diagnosis/edit.vue'
|
||||
import VideoCall from '@/components/video-call/index.vue'
|
||||
@@ -459,8 +460,8 @@ const handleGroupVideoCall = (row: any) => {
|
||||
})
|
||||
}
|
||||
|
||||
// 创建处方单
|
||||
const handleCreatePrescription = async (row: any) => {
|
||||
// 聊天
|
||||
const handleChat = async (row: any) => {
|
||||
if (!row.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
@@ -472,11 +473,26 @@ const handleCreatePrescription = async (row: any) => {
|
||||
return
|
||||
}
|
||||
|
||||
chatDialogRef.value?.open({
|
||||
patientId: row.patient_id,
|
||||
patientName: row.patient_name,
|
||||
diagnosisId: row.diagnosis_id || row.id // 使用诊单ID,如果没有则使用预约ID
|
||||
})
|
||||
try {
|
||||
// 获取聊天签名信息
|
||||
const res = await getCallSignature({
|
||||
patient_id: row.patient_id,
|
||||
diagnosis_id: row.diagnosis_id || row.id
|
||||
})
|
||||
|
||||
console.log('获取聊天签名成功:', res)
|
||||
|
||||
// 直接打开聊天对话框,传入必要的参数
|
||||
chatDialogRef.value?.open({
|
||||
patientId: row.patient_id,
|
||||
patientName: row.patient_name,
|
||||
diagnosisId: row.diagnosis_id || row.id,
|
||||
signatureData: res // 传入签名数据
|
||||
})
|
||||
} catch (error: any) {
|
||||
console.error('获取聊天签名失败:', error)
|
||||
feedback.msgError(error.message || '获取聊天签名失败')
|
||||
}
|
||||
}
|
||||
|
||||
loadData()
|
||||
|
||||
@@ -894,7 +894,7 @@ defineExpose({
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
/* 全局样式,用于提高弹出层的z-index */
|
||||
.high-z-index {
|
||||
z-index: 3000 !important;
|
||||
@@ -906,7 +906,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.el-overlay {
|
||||
z-index: 1499 !important;
|
||||
z-index: 1499 ;
|
||||
}
|
||||
|
||||
/* 确保日期选择器和下拉选择器的弹出层在最上层 */
|
||||
|
||||
Reference in New Issue
Block a user