新增
This commit is contained in:
+357
-28
@@ -50,6 +50,7 @@
|
||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
<export-data
|
||||
v-perms="['order.order/export']"
|
||||
class="ml-2.5"
|
||||
:fetch-fun="orderExport"
|
||||
:params="queryParams"
|
||||
@@ -63,10 +64,35 @@
|
||||
>
|
||||
+ 创建订单
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['order.order/alltongbu']"
|
||||
type="warning"
|
||||
class="ml-2.5"
|
||||
:loading="syncLoading"
|
||||
@click="handleSyncWechatWork"
|
||||
>
|
||||
同步企业微信收款
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- Tab 筛选 + 今日收益 -->
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<el-tabs v-model="patientAssociationTab" @tab-change="handleTabChange">
|
||||
<el-tab-pane label="全部" name="" />
|
||||
<el-tab-pane label="待关联" name="pending" />
|
||||
<el-tab-pane label="已关联" name="associated" />
|
||||
</el-tabs>
|
||||
<div class="flex items-center gap-4 text-sm">
|
||||
<span class="text-gray-500">今日收益:</span>
|
||||
<span class="text-red-500 font-semibold text-lg">¥{{ todayRevenue.amount }}</span>
|
||||
<span class="text-gray-400">({{ todayRevenue.count }} 笔)</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<el-table
|
||||
@@ -78,12 +104,18 @@
|
||||
|
||||
<el-table-column label="患者信息" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.patient.patient_name }}</div>
|
||||
<div class="text-xs text-gray-400">{{ row.patient.phone }}</div>
|
||||
<div v-if="row.patient">{{ row.patient.patient_name }}</div>
|
||||
<div v-else class="text-amber-600">待关联</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="创建人" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.creator?.name || '-' }}</div>
|
||||
<div v-if="row.payee_userid" class="text-xs text-gray-400">收款: {{ row.payee_userid }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="订单类型" width="100">
|
||||
<template #default="{ row }">
|
||||
@@ -136,8 +168,17 @@
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['order.order/edit']"
|
||||
type="primary"
|
||||
link
|
||||
@click="handleEditOrder(row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-perms="['order.order/wxQrcode']"
|
||||
link
|
||||
@click="handleOrderQrcode(row)"
|
||||
>
|
||||
小程序码
|
||||
@@ -202,13 +243,19 @@
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="患者姓名">
|
||||
{{ detailData.patient.patient_name }}
|
||||
{{ detailData.patient?.patient_name || '待关联' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="患者电话">
|
||||
{{ detailData.patient.phone }}
|
||||
{{ detailData.patient?.phone || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">
|
||||
{{ detailData.creator.name }}
|
||||
{{ detailData.creator?.name || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="收款人userid" v-if="detailData.payee_userid">
|
||||
{{ detailData.payee_userid }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="付款人external_userid" v-if="detailData.payer_external_userid">
|
||||
{{ detailData.payer_external_userid }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单类型">
|
||||
<el-tag :type="getOrderTypeTag(detailData.order_type)">
|
||||
@@ -269,6 +316,7 @@
|
||||
<el-radio-group v-model="payForm.payment_method">
|
||||
<el-radio label="alipay">支付宝</el-radio>
|
||||
<el-radio label="wechat">微信</el-radio>
|
||||
<el-radio label="wechat_work">企业微信</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -291,6 +339,22 @@
|
||||
:rules="createRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="创建方式">
|
||||
<el-radio-group v-model="createForm.createType">
|
||||
<el-radio label="normal">普通订单</el-radio>
|
||||
<el-radio label="wechat_work">企业微信对外收款</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-alert
|
||||
v-if="createForm.createType === 'wechat_work'"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="mb-4"
|
||||
>
|
||||
<template #title>企业微信对外收款</template>
|
||||
创建后将生成订单号,请在企业微信发起收款时将该订单号填写为「商户订单号」,收款成功后系统将自动更新订单状态。
|
||||
</el-alert>
|
||||
<el-form-item label="患者" prop="patient_id">
|
||||
<el-select
|
||||
v-model="createForm.patient_id"
|
||||
@@ -340,10 +404,86 @@
|
||||
<template #footer>
|
||||
<el-button @click="createDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitCreateOrder" :loading="createLoading">
|
||||
创建订单
|
||||
{{ createForm.createType === 'wechat_work' ? '创建并获取收款订单号' : '创建订单' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 同步企业微信收款弹窗 -->
|
||||
<el-dialog
|
||||
v-model="syncDialogVisible"
|
||||
title="同步企业微信对外收款"
|
||||
width="420px"
|
||||
>
|
||||
<p class="text-gray-600 mb-4">拉取员工在企业微信内直接发起的对外收款记录,自动创建订单(未经过后台创建的收款)</p>
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="时间范围">
|
||||
<el-date-picker
|
||||
v-model="syncDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
:shortcuts="syncDateShortcuts"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="收款人userid">
|
||||
<el-input v-model="syncPayeeUserid" placeholder="可选,如 GaoXingLiang,排查时若返回 try_payee_userids 可逐个尝试" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="syncDialogVisible = false">取消</el-button>
|
||||
<el-button type="info" :loading="syncDebugLoading" @click="handleSyncDebug">
|
||||
排查同步为0
|
||||
</el-button>
|
||||
<el-button type="primary" :loading="syncLoading" @click="submitSyncWechatWork">
|
||||
开始同步
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 编辑订单弹窗 -->
|
||||
<el-dialog
|
||||
v-model="editOrderDialogVisible"
|
||||
title="编辑订单"
|
||||
width="480px"
|
||||
>
|
||||
<el-form v-if="editOrderForm" ref="editOrderFormRef" :model="editOrderForm" :rules="editOrderRules" label-width="100px">
|
||||
<el-form-item label="关联患者" prop="patient_id">
|
||||
<el-select
|
||||
v-model="editOrderForm.patient_id"
|
||||
filterable
|
||||
remote
|
||||
placeholder="搜索患者姓名/手机号,可留空表示待关联"
|
||||
:remote-method="searchPatientsForEdit"
|
||||
:loading="editPatientLoading"
|
||||
clearable
|
||||
class="w-full"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editPatientList"
|
||||
:key="item.id"
|
||||
:label="`${item.patient_name || '-'} (${item.phone || '-'})`"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单类型" prop="order_type">
|
||||
<el-select v-model="editOrderForm.order_type" placeholder="请选择" class="w-full">
|
||||
<el-option label="挂号费" :value="1" />
|
||||
<el-option label="问诊费" :value="2" />
|
||||
<el-option label="药品费用" :value="3" />
|
||||
<el-option label="首付费用" :value="4" />
|
||||
<el-option label="尾款费用" :value="5" />
|
||||
<el-option label="其他费用" :value="6" />
|
||||
<el-option label="全部费用" :value="7" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="editOrderDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="editOrderLoading" @click="submitEditOrder">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 小程序码弹窗 -->
|
||||
<el-dialog
|
||||
v-model="qrcodeDialogVisible"
|
||||
@@ -381,7 +521,7 @@
|
||||
|
||||
<script setup lang="ts" name="orderList">
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import { orderLists, orderDetail, orderPay, orderCancel, orderDelete, orderRefund, orderExport, orderCreate, searchPatients as searchPatientsAPI, alipayPay, wechatPay } from '@/api/order'
|
||||
import { orderLists, orderDetail, orderPay, orderCancel, orderDelete, orderRefund, orderExport, orderCreate, orderCreateForWechatWork, orderEdit, orderTodayRevenue, syncWechatWorkBills, syncWechatWorkBillsDebug, searchPatients as searchPatientsAPI, alipayPay, wechatPay } from '@/api/order'
|
||||
import { generateOrderQrcode } from '@/api/tcm'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import feedback from '@/utils/feedback'
|
||||
@@ -391,10 +531,14 @@ const queryParams = reactive({
|
||||
patient_keyword: '',
|
||||
order_type: '',
|
||||
status: '',
|
||||
patient_association: '' as '' | 'pending' | 'associated',
|
||||
create_time_start: '',
|
||||
create_time_end: ''
|
||||
})
|
||||
|
||||
const patientAssociationTab = ref<'' | 'pending' | 'associated'>('')
|
||||
const todayRevenue = ref({ amount: '0.00', count: 0 })
|
||||
|
||||
const { pager, getLists, resetPage, resetParams } = usePaging({
|
||||
fetchFun: orderLists,
|
||||
params: queryParams
|
||||
@@ -405,8 +549,25 @@ const handleSearch = () => {
|
||||
resetPage()
|
||||
}
|
||||
|
||||
// Tab 切换
|
||||
const handleTabChange = (name: string | number) => {
|
||||
queryParams.patient_association = (name as '' | 'pending' | 'associated') || ''
|
||||
resetPage()
|
||||
}
|
||||
|
||||
// 获取今日收益
|
||||
const fetchTodayRevenue = async () => {
|
||||
try {
|
||||
const res: any = await orderTodayRevenue()
|
||||
todayRevenue.value = res?.data || res || { amount: '0.00', count: 0 }
|
||||
} catch (e) {
|
||||
todayRevenue.value = { amount: '0.00', count: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
patientAssociationTab.value = ''
|
||||
resetParams()
|
||||
}
|
||||
|
||||
@@ -431,6 +592,7 @@ const patientLoading = ref(false)
|
||||
const patientList = ref<any[]>([])
|
||||
|
||||
const createForm = reactive({
|
||||
createType: 'normal' as 'normal' | 'wechat_work',
|
||||
patient_id: '',
|
||||
order_type: '',
|
||||
amount: 0,
|
||||
@@ -443,6 +605,17 @@ const createRules = {
|
||||
amount: [{ required: true, message: '请输入订单金额', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 编辑订单相关
|
||||
const editOrderDialogVisible = ref(false)
|
||||
const editOrderFormRef = ref()
|
||||
const editOrderLoading = ref(false)
|
||||
const editPatientLoading = ref(false)
|
||||
const editPatientList = ref<any[]>([])
|
||||
const editOrderForm = ref<{ id: number; patient_id: number | null; order_type: number } | null>(null)
|
||||
const editOrderRules = {
|
||||
order_type: [{ required: true, message: '请选择订单类型', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// 搜索患者
|
||||
const searchPatients = async (query: string) => {
|
||||
if (!query) {
|
||||
@@ -466,6 +639,7 @@ const searchPatients = async (query: string) => {
|
||||
|
||||
// 重置创建表单
|
||||
const resetCreateForm = () => {
|
||||
createForm.createType = 'normal'
|
||||
createForm.patient_id = ''
|
||||
createForm.order_type = ''
|
||||
createForm.amount = 0
|
||||
@@ -479,6 +653,98 @@ const handleCreate = () => {
|
||||
createDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 同步企业微信收款
|
||||
const syncDialogVisible = ref(false)
|
||||
const syncLoading = ref(false)
|
||||
const syncDebugLoading = ref(false)
|
||||
const syncPayeeUserid = ref('')
|
||||
const syncDateRange = ref<[string, string]>([
|
||||
new Date(Date.now() - 7 * 86400000).toISOString().slice(0, 10),
|
||||
new Date().toISOString().slice(0, 10)
|
||||
])
|
||||
const syncDateShortcuts = [
|
||||
{ text: '最近7天', value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 7 * 86400000)
|
||||
return [start, end]
|
||||
}},
|
||||
{ text: '最近30天', value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 30 * 86400000)
|
||||
return [start, end]
|
||||
}},
|
||||
{ text: '今天', value: () => {
|
||||
const d = new Date()
|
||||
return [d, d]
|
||||
}}
|
||||
]
|
||||
|
||||
const handleSyncWechatWork = () => {
|
||||
syncDateRange.value = [
|
||||
new Date(Date.now() - 7 * 86400000).toISOString().slice(0, 10),
|
||||
new Date().toISOString().slice(0, 10)
|
||||
]
|
||||
syncDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleSyncDebug = async () => {
|
||||
const range = syncDateRange.value
|
||||
if (!range || range.length !== 2) {
|
||||
feedback.msgError('请先选择时间范围')
|
||||
return
|
||||
}
|
||||
try {
|
||||
syncDebugLoading.value = true
|
||||
const res: any = await syncWechatWorkBillsDebug({
|
||||
begin_time: range[0],
|
||||
end_time: range[1],
|
||||
payee_userid: syncPayeeUserid.value || undefined
|
||||
})
|
||||
const d = res?.data || res
|
||||
let msg = `配置:${d.config_ok ? '✓' : '✗'} | token:${d.access_token} | errcode:${d.api_errcode} | errmsg:${d.api_errmsg || '-'} | 账单数:${d.bill_count}`
|
||||
if (d.try_payee_userids?.length) {
|
||||
msg += `。可尝试收款人: ${d.try_payee_userids.join(', ')}`
|
||||
}
|
||||
if (d.api_errcode !== 0 && d.api_errcode !== -999) {
|
||||
msg += '。提示:需使用「对外收款」应用的Secret(管理后台-应用管理-对外收款-API)'
|
||||
}
|
||||
feedback.msgSuccess(msg)
|
||||
console.log('企业微信同步调试:', d)
|
||||
} catch (e: any) {
|
||||
feedback.msgError(e?.message || '排查失败')
|
||||
} finally {
|
||||
syncDebugLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const submitSyncWechatWork = async () => {
|
||||
const range = syncDateRange.value
|
||||
if (!range || range.length !== 2) {
|
||||
feedback.msgError('请选择时间范围')
|
||||
return
|
||||
}
|
||||
try {
|
||||
syncLoading.value = true
|
||||
const res: any = await syncWechatWorkBills({
|
||||
begin_time: range[0],
|
||||
end_time: range[1]
|
||||
})
|
||||
const data = res?.data || res
|
||||
syncDialogVisible.value = false
|
||||
getLists()
|
||||
const msg = `同步完成:新增 ${data.created || 0} 笔,更新 ${data.updated || 0} 笔,跳过 ${data.skipped || 0} 笔` +
|
||||
(data.errors?.length ? `;错误:${data.errors.join(';')}` : '')
|
||||
feedback.msgSuccess(msg)
|
||||
fetchTodayRevenue()
|
||||
} catch (error: any) {
|
||||
feedback.msgError(error?.message || '同步失败')
|
||||
} finally {
|
||||
syncLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 提交创建订单
|
||||
const submitCreateOrder = async () => {
|
||||
try {
|
||||
@@ -493,10 +759,18 @@ const submitCreateOrder = async () => {
|
||||
remark: createForm.remark
|
||||
}
|
||||
|
||||
await orderCreate(params)
|
||||
feedback.msgSuccess('订单创建成功')
|
||||
createDialogVisible.value = false
|
||||
getLists()
|
||||
if (createForm.createType === 'wechat_work') {
|
||||
const res: any = await orderCreateForWechatWork(params)
|
||||
const orderNo = res?.order_no ?? res?.data?.order_no
|
||||
createDialogVisible.value = false
|
||||
getLists()
|
||||
feedback.msgSuccess(orderNo ? `订单创建成功,请在企业微信收款时使用订单号:${orderNo}` : '订单创建成功')
|
||||
} else {
|
||||
await orderCreate(params)
|
||||
feedback.msgSuccess('订单创建成功')
|
||||
createDialogVisible.value = false
|
||||
getLists()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('创建订单失败:', error)
|
||||
} finally {
|
||||
@@ -555,11 +829,60 @@ const getPaymentMethodText = (method: string | null) => {
|
||||
if (!method) return '-'
|
||||
const methodMap: Record<string, string> = {
|
||||
alipay: '支付宝',
|
||||
wechat: '微信'
|
||||
wechat: '微信',
|
||||
wechat_work: '企业微信'
|
||||
}
|
||||
return methodMap[method] || '未知'
|
||||
}
|
||||
|
||||
// 编辑订单
|
||||
const handleEditOrder = (row: any) => {
|
||||
editOrderForm.value = {
|
||||
id: row.id,
|
||||
patient_id: row.patient_id || null,
|
||||
order_type: row.order_type
|
||||
}
|
||||
editPatientList.value = row.patient ? [row.patient] : []
|
||||
editOrderDialogVisible.value = true
|
||||
}
|
||||
|
||||
const searchPatientsForEdit = async (query: string) => {
|
||||
if (!query) {
|
||||
editPatientList.value = []
|
||||
return
|
||||
}
|
||||
try {
|
||||
editPatientLoading.value = true
|
||||
const res = await searchPatientsAPI({ keyword: query, page_no: 1, page_size: 10 })
|
||||
editPatientList.value = res?.lists || []
|
||||
} catch (e) {
|
||||
editPatientList.value = []
|
||||
} finally {
|
||||
editPatientLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const submitEditOrder = async () => {
|
||||
if (!editOrderForm.value) return
|
||||
try {
|
||||
await editOrderFormRef.value?.validate()
|
||||
editOrderLoading.value = true
|
||||
await orderEdit({
|
||||
id: editOrderForm.value.id,
|
||||
patient_id: editOrderForm.value.patient_id ?? 0,
|
||||
order_type: editOrderForm.value.order_type
|
||||
})
|
||||
feedback.msgSuccess('保存成功')
|
||||
editOrderDialogVisible.value = false
|
||||
getLists()
|
||||
fetchTodayRevenue()
|
||||
} catch (e: any) {
|
||||
if (e?.message) feedback.msgError(e.message)
|
||||
} finally {
|
||||
editOrderLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = async (row: any) => {
|
||||
try {
|
||||
@@ -614,23 +937,28 @@ const confirmPay = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 调用对应的支付网关
|
||||
let payResult: any
|
||||
if (payForm.value.payment_method === 'alipay') {
|
||||
payResult = await alipayPay(payParams)
|
||||
} else if (payForm.value.payment_method === 'wechat') {
|
||||
payResult = await wechatPay(payParams)
|
||||
}
|
||||
|
||||
// 支付网关返回支付链接或二维码
|
||||
if (payResult && payResult.pay_url) {
|
||||
// 如果是支付宝,跳转到支付页面
|
||||
// 企业微信补单:直接调用 orderPay 更新订单状态
|
||||
if (payForm.value.payment_method === 'wechat_work') {
|
||||
await orderPay(payParams)
|
||||
feedback.msgSuccess('补单成功')
|
||||
} else {
|
||||
// 调用对应的支付网关
|
||||
let payResult: any
|
||||
if (payForm.value.payment_method === 'alipay') {
|
||||
window.location.href = payResult.pay_url
|
||||
payResult = await alipayPay(payParams)
|
||||
} else if (payForm.value.payment_method === 'wechat') {
|
||||
// 如果是微信,显示二维码或其他处理
|
||||
feedback.msgSuccess('请扫描二维码进行支付')
|
||||
// 可以在这里显示二维码弹窗
|
||||
payResult = await wechatPay(payParams)
|
||||
}
|
||||
|
||||
// 支付网关返回支付链接或二维码
|
||||
if (payResult && payResult.pay_url) {
|
||||
// 如果是支付宝,跳转到支付页面
|
||||
if (payForm.value.payment_method === 'alipay') {
|
||||
window.location.href = payResult.pay_url
|
||||
} else if (payForm.value.payment_method === 'wechat') {
|
||||
// 如果是微信,显示二维码或其他处理
|
||||
feedback.msgSuccess('请扫描二维码进行支付')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,6 +1048,7 @@ const handleOrderQrcodeRefresh = () => {
|
||||
|
||||
onMounted(() => {
|
||||
getLists()
|
||||
fetchTodayRevenue()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user