fix: 部分提现审核管理

This commit is contained in:
2025-04-25 15:54:57 +08:00
parent 11cc8cfa95
commit f649802c53
18 changed files with 522 additions and 44 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -1,5 +1,13 @@
import { defineOverridesPreferences } from '@vben/preferences';
// {
// "app": {
// "layout": "sidebar-nav"
// }
// }{
// "tabbar": {
// "enable": false
// }
// }
/**
* @description 项目配置文件
* 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置
@@ -9,7 +17,8 @@ export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
name: import.meta.env.VITE_APP_TITLE,
layout: 'sidebar-mixed-nav',
// layout: 'sidebar-mixed-nav',
layout: 'sidebar-nav',
// 登录过期模式
// loginExpiredMode: 'modal',
loginExpiredMode: 'page',
@@ -18,7 +27,8 @@ export const overridesPreferences = defineOverridesPreferences({
enableRefreshToken: false,
defaultAvatar:
'https://yanydy.oss-cn-hangzhou.aliyuncs.com/uploads/20241219/2b38e38414a2b9383b8643983e3f69d7.png',
watermark: true,
watermark: false,
// watermark: true,
// 是否开启检查更新
enableCheckUpdates: true,
// 检查更新的时间间隔,单位为分钟
@@ -49,4 +59,7 @@ export const overridesPreferences = defineOverridesPreferences({
icp: '浙ICP备19041368号-2',
icpLink: 'https://beian.miit.gov.cn/#/Integrated/recordQuery',
},
tabbar: {
enable: false,
},
});

View File

@@ -62,19 +62,19 @@ export const useAuthStore = defineStore('auth', () => {
: await router.push(userInfo.home_path || DEFAULT_HOME_PATH);
}
if (userInfo?.nick_name) {
// 这里修改水印内容
await updateWatermark({
contentType: 'multi-line-text',
// 水印内容
content: `${userInfo?.nick_name}\r\n${userInfo?.phone}`,
});
notification.success({
description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.nick_name}`,
duration: 3,
message: $t('authentication.loginSuccess'),
});
}
// if (userInfo?.nick_name) {
// // 这里修改水印内容
// await updateWatermark({
// contentType: 'multi-line-text',
// // 水印内容
// content: `${userInfo?.nick_name}\r\n${userInfo?.phone}`,
// });
// notification.success({
// description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.nick_name}`,
// duration: 3,
// message: $t('authentication.loginSuccess'),
// });
// }
}
} finally {
loginLoading.value = false;

View File

@@ -111,14 +111,14 @@ const openPrescriptionSourceModal = (id) => {
{
label: '查看处方',
type: 'link',
icon: 'ri:send-plane-fill',
icon: 'marketeq:eye',
// auth: ['超级订单', 'sys:user:save'],
onClick: openPrescriptionDetail.bind(null, row.id),
},
{
label: '处方溯源',
type: 'link',
icon: 'ri:send-plane-fill',
icon: 'marketeq:eye',
// auth: ['超级订单', 'sys:user:save'],
onClick: openPrescriptionSourceModal.bind(null, row.id),
},

View File

@@ -109,7 +109,16 @@ function getColor(status: any) {
{{ data.free_ship === 1 ? '是' : '否' }}
</Descriptions.Item>
<Descriptions.Item label="状态">
{{ data.status === 0 ? '待处理' : '已处理' }}
<Tag v-if="data.status === 0" color="red">待支付</Tag>
<Tag v-else-if="data.status === 1" color="orange">待发货</Tag>
<Tag v-else-if="data.status === 2" color="blue">待收货</Tag>
<Tag v-else-if="data.status === 3" color="purple">待评价</Tag>
<Tag v-else-if="data.status === 4" color="green">已退款</Tag>
<Tag v-else-if="data.status === 5" color="pink">退款中</Tag>
<Tag v-else-if="data.status === 6" color="cyan">已收货</Tag>
<Tag v-else-if="data.status === 7" color="green">确认收货</Tag>
<Tag v-else-if="data.status === 8" color="#B22222">拒绝退款</Tag>
<Tag v-else-if="data.status === 9" color="gray">已取消</Tag>
</Descriptions.Item>
<Descriptions.Item label="配送方式">
{{ deliveryMethod === 0 ? '快递到家' : '药店自提' }}
@@ -158,8 +167,21 @@ function getColor(status: any) {
</div>
<div class="mt-4">
<h3>订单商品</h3>
<div v-if="data.prescription_type === 1">
<ul class="custom-list pl-6">
<li
v-for="(item, index) in data.product_order_items"
:key="index"
class="custom-list-item"
>
{{ item.drug.drug_number }} {{ item.drug_name }} *
{{ item.number * (item.dosage > 0 ? item.dosage : 1) }}
</li>
</ul>
</div>
<Card
v-for="(item, index) in data.product_order_items"
v-else
:key="index"
class="mb-4 mt-5"
>
@@ -167,7 +189,12 @@ function getColor(status: any) {
<div
class="mr-6 h-32 w-32 overflow-hidden rounded-lg bg-gray-200 dark:bg-gray-800"
>
<Image :src="item.drug_image || '/img/empty.png'" alt="/img/empty.png" height="100%" width="100%" />
<Image
:src="item.drug_image || '/img/empty.png'"
alt="/img/empty.png"
height="100%"
width="100%"
/>
</div>
<div>
<h4>{{ item.drug_name }}</h4>
@@ -256,6 +283,34 @@ function getColor(status: any) {
</template>
<style scoped>
.custom-list {
list-style-type: none;
padding-left: 0;
}
.custom-list-item {
background-color: rgba(64, 158, 255, 0.04);
border-radius: 4px;
margin-bottom: 8px;
padding: 8px 12px;
font-size: 14px;
transition: background-color 0.3s;
&:hover {
background-color: rgba(64, 158, 255, 0.1);
}
&::before {
content: '';
display: inline-block;
width: 6px;
height: 6px;
background-color: #409eff;
border-radius: 50%;
margin-right: 8px;
vertical-align: middle;
}
}
.ant-descriptions-item-label {
font-weight: bold;
}

View File

@@ -42,7 +42,8 @@ export const gridOptions: VxeGridProps<RowType> = {
title: '订单类型&邮寄方式&订单状态',
slots: { default: 'delivery-method' },
},
{ field: 'items_price', title: '总价' },
{ field: 'items_price', title: '药品总价' },
{ field: 'total_pay_price', title: '支付总价' },
{ field: 'is_sync_erp', title: 'Erp状态', slots: { default: 'is-sync-erp' } },
{ field: 'pay_time', title: '支付时间', slots: { default: 'pay-time' } },
{ field: 'created_at', title: '下单时间' },

View File

@@ -237,11 +237,20 @@ const openPrescriptionDetail = (values) => {
{
label: '详情',
type: 'link',
icon: 'uil:edit',
icon: 'marketeq:eye',
size: 'small',
// auth: ['order', 'sys:role:detail'],
onClick: infoModal.bind(null, row),
},
{
label: '处方',
type: 'link',
icon: 'marketeq:eye',
// auth: ['超级订单', 'sys:user:save'],
onClick: openPrescriptionDetail.bind(null, row.p_id),
},
]"
:drop-down-actions="[
{
label: '发货',
type: 'link',
@@ -254,15 +263,6 @@ const openPrescriptionDetail = (values) => {
// },
},
]"
:drop-down-actions="[
{
label: '查看处方',
type: 'link',
icon: 'ri:send-plane-fill',
// auth: ['超级订单', 'sys:user:save'],
onClick: openPrescriptionDetail.bind(null, row.p_id),
},
]"
/>
</template>

View File

@@ -93,7 +93,7 @@ const openPrescriptionDetail = (values) => {
{
label: '查看处方',
type: 'link',
icon: 'ri:send-plane-fill',
icon: 'marketeq:eye',
// auth: ['超级订单', 'sys:user:save'],
onClick: openPrescriptionDetail.bind(null, row.id),
},

View File

@@ -23,13 +23,13 @@ export const gridOptions: VxeGridProps<RowType> = {
{ field: 'charge_cash', title: '手续费' },
{ field: 'status', title: '状态', slots: { default: 'status' } },
{ field: 'created_at', title: '记录时间' },
{
type: 'html',
title: '操作',
align: 'right',
slots: { default: 'action' },
width: 200,
},
// {
// type: 'html',
// title: '操作',
// align: 'right',
// slots: { default: 'action' },
// width: 200,
// },
],
keepSource: true,
pagerConfig: {},

View File

@@ -69,7 +69,7 @@ const infoModal = (id) => {
{
label: '详情',
type: 'link',
icon: 'uil:edit',
icon: 'marketeq:eye',
size: 'small',
// auth: ['order', 'sys:role:detail'],
onClick: infoModal.bind(null, row.order_id),

View File

@@ -76,7 +76,7 @@ initTableAjax();
{
label: '结算订单',
type: 'primary',
icon: 'ant-design:plus-outlined',
// icon: 'ant-design:plus-outlined',
// auth: ['超级诊所', 'sys:user:save'],
onClick: infoModal.bind(null, null, 2),
},

View File

@@ -0,0 +1,17 @@
import { requestClient } from '#/api/request';
const prefix = 'withdrawal-application/';
/**
* 提现审核
* @param data
*/
export async function getFundWaterListApi(data: any) {
return requestClient.get<any>(`${prefix}audit-list`, { params: data });
}
/**
* 拒绝申请
* @param data
*/
export async function refuseApplicationApi(data: any) {
return requestClient.post<any>(`${prefix}refuse-application`, data);
}

View File

@@ -0,0 +1,65 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { settlementApi } from '#/views/finance/monthly-payment/api';
import { refuseApplicationApi } from '#/views/finance/withdrawal-audit/api';
import { withdrawalAudit } from '../config/form';
const gridApi = ref();
const type = ref(1);
const [WithdrawalAuditForm, WithdrawalAuditFormApi] =
useVbenForm(withdrawalAudit);
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm: async () => {
const formApi = WithdrawalAuditFormApi;
formApi.validate().then(async (e: any) => {
if (e.valid) {
const values = await formApi.getValues();
modalApi.setState({ loading: true, confirmLoading: true });
const submitApi =
type.value === 1 ? refuseApplicationApi : settlementApi;
submitApi(values)
.then(() => {
message.success('保存成功');
gridApi.value?.reload();
modalApi.close();
})
.finally(() => {
modalApi.setState({ loading: false, confirmLoading: false });
});
}
});
await formApi.validateAndSubmitForm();
},
onOpenChange(isOpen: boolean) {
gridApi.value = isOpen ? modalApi.getData()?.gridApi : null;
if (isOpen) {
const { id, modalType } = modalApi.getData<Record<string, any>>();
type.value = modalType;
console.log(id, 'ssssssssssssssssssss')
WithdrawalAuditFormApi.setValues({
id,
});
}
},
});
</script>
<template>
<Modal :title="`提现审核【${type === 1 ? '拒绝' : '通过'}】`" class="w-[30%]">
<WithdrawalAuditForm />
</Modal>
</template>

View File

@@ -0,0 +1,39 @@
import type { VbenFormProps } from '#/adapter/form';
/**
* 作废表单
*/
export const withdrawalAudit: VbenFormProps = {
wrapperClass: 'grid-cols-12', // 24栅格,
commonConfig: {
formItemClass: 'col-span-12',
// 所有表单项
componentProps: {
class: 'w-full',
},
},
// handleSubmit: onSubmit,
layout: 'horizontal',
schema: [
{
component: 'VbenInput',
fieldName: 'id',
label: 'ID',
dependencies: {
show: false,
triggerFields: ['id'],
},
rules: 'required',
},
{
component: 'Textarea',
componentProps: {
placeholder: '请输入备注',
},
fieldName: 'reason',
label: '备注',
rules: 'required',
},
],
showDefaultActions: false,
};

View File

@@ -0,0 +1,60 @@
import type { VbenFormProps } from '#/adapter/form';
import dayjs from 'dayjs';
export const formOptions: VbenFormProps = {
// 默认展开
collapsed: false,
schema: [
{
component: 'Select',
componentProps: {
placeholder: '选择结算状态',
options: [
{
label: '全部',
value: '',
},
{
label: '待审核',
value: 1,
},
{
label: '审核通过',
value: 2,
},
{
label: '审核拒绝',
value: 3,
},
{
label: '打款失败',
value: 4,
},
],
},
defaultValue: '',
fieldName: 'check_status',
label: '审核状态',
},
{
component: 'RangePicker',
componentProps: {
format: 'YYYY-MM-DD', // 确保格式与你需要的一致
},
defaultValue: [dayjs().startOf('month'), dayjs()],
fieldName: 'search_time',
label: '时间范围',
},
],
// 控制表单是否显示折叠按钮
showCollapseButton: true,
submitButtonOptions: {
content: '查询',
},
// 是否在字段值改变时提交表单
// submitOnChange: true,
// submitOnChange: true,
// 按下回车时是否提交表单
submitOnEnter: true,
};

View File

@@ -0,0 +1,83 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { getFundWaterListApi } from '../api';
interface RowType {
id: string;
name: string;
logo: string;
introduce: string;
created_at: string;
}
export const gridOptions: VxeGridProps<RowType> = {
checkboxConfig: {
highlight: true,
labelField: '',
},
columns: [
{ field: 'id', align: 'left', title: 'ID', width: 50 },
{ field: 'user_info', title: '申请诊所/供应商/平台', slots: { default: 'user-info'} },
{ field: 'order_no', title: '订单号' },
{ field: 'apply_cash', title: '申请金额' },
{ field: 'true_cash', title: '打款金额' },
{ field: 'charge_cash', title: '手续费' },
{ field: 'check_id', title: '审核信息', slots: { default: 'check-id' } },
{ field: 'dakuan_status', title: '打款信息', slots: { default: 'dakuan-status'} },
{ field: 'apply_time', title: '申请时间' },
{
type: 'html',
title: '操作',
align: 'right',
slots: { default: 'action' },
width: 200,
},
],
keepSource: true,
pagerConfig: {},
columnConfig: {
useKey: true,
},
rowConfig: {
useKey: true,
},
// scrollY: {
// enabled: true,
// gt: 0,
// },
proxyConfig: {
ajax: {
// 请求后端接口方法
query: async ({ page }, formValues) => {
return await getFundWaterListApi({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
height: 'auto',
border: false,
toolbarConfig: {
// 是否显示搜索表单控制按钮
// @ts-ignore 正式环境时有完整的类型声明
search: true,
refresh: true, // 刷新
print: false, // 打印
export: false, // 导出
// custom: true, // 自定义列
zoom: true, // 最大化最小化
slots: {
buttons: 'toolbar-buttons',
},
custom: {
// 自定义列-图标
icon: 'vxe-icon-menu',
},
},
expandConfig: {
// expandAll: true,
},
showOverflow: false,
};

View File

@@ -0,0 +1,145 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import {Button, message, Tag} from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import WithdrawalAudit from './components/WithdrawalAudit.vue';
import StatisticsReconciliation from '#/views/finance/reconciliation/components/statistics.vue';
import { formOptions } from './config/search';
import { gridOptions } from './config/table';
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions,
});
const statistics = ref();
const [WithdrawalAuditModal, WithdrawalAuditModalApi] = useVbenModal({
connectedComponent: WithdrawalAudit,
});
const infoModal = (id, modalType = 0) => {
if (modalType === 0) {
message.info('正在开发');
return;
}
WithdrawalAuditModalApi.setData({
// 表单值
id,
modalType,
});
WithdrawalAuditModalApi.open();
};
</script>
<template>
<Page auto-content-height title="提现审核">
<WithdrawalAuditModal />
<StatisticsReconciliation v-if="statistics" :statistics="statistics" />
<Grid>
<template #toolbar-buttons>
<TableAction :actions="[]" :drop-down-actions="[]">
<template #more>
<Button style="margin-left: 16px">
批量操作
<Icon icon="ant-design:down-outlined" />
</Button>
</template>
</TableAction>
</template>
<template #user-info="{ row }">
<div>
<Tag color="green">{{ row?.user_type_txt || '平台' }}</Tag>
<Tag class="mt-3" color="#455cda">{{ row.store?.name || row.supplier?.name || '萧康云医' }}</Tag>
</div>
</template>
<template #check-id="{ row }">
<div v-if="row.check_id !== 0">
<span v-if="row.is_new === 0">{{ row.check_admin?.nickname || '旧后台' }}</span>
<span v-else-if="row.is_new === 1">{{ row.new_check_admin?.nick_name || '新后台' }}</span>
</div>
<div :class="row.check_id !== 0? 'mt-3': ''">
<Tag v-if="row.check_status === 1" color="purple">待审核</Tag>
<Tag v-else-if="row.check_status === 2" color="green">审核通过</Tag>
<Tag v-else-if="row.check_status === 3" color="error">审核拒绝</Tag>
<Tag v-else-if="row.check_status === 4" color="error">提现失败</Tag>
</div>
<div v-if="row.check_result" :class="row.check_id !== 0? 'mt-3': ''">
备注{{ row.check_result }}
</div>
<div v-if="row.check_time" :class="row.check_id !== 0? 'mt-3': ''">
{{ row.check_time }}
</div>
</template>
<template #dakuan-status="{ row }">
<div class="mt-3">
<Tag v-if="row.dakuan_status === 0" color="purple">未知</Tag>
<Tag v-else-if="row.dakuan_status === 1" color="green">已到账</Tag>
<Tag v-else-if="row.dakuan_status === -1" color="error">打款失败</Tag>
</div>
<div v-if="row.dakuan_time" class="mt-3">
{{ row.dakuan_time }}
</div>
</template>
<template #toolbar-tools></template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '审核通过',
type: 'link',
icon: 'marketeq:eye',
size: 'small',
// auth: ['order', 'sys:role:detail'],
onClick: infoModal.bind(null, row.id),
},
{
label: '拒绝审核',
type: 'link',
icon: 'marketeq:eye',
size: 'small',
// auth: ['order', 'sys:role:detail'],
onClick: infoModal.bind(null, row.id, 1),
},
]"
/>
</template>
</Grid>
</Page>
</template>
<style scoped lang="scss">
.custom-list {
list-style-type: none;
padding-left: 0;
}
.custom-list-item {
background-color: rgba(64, 158, 255, 0.04);
border-radius: 4px;
margin-bottom: 8px;
padding: 8px 12px;
font-size: 14px;
transition: background-color 0.3s;
&:hover {
background-color: rgba(64, 158, 255, 0.1);
}
&::before {
content: '';
display: inline-block;
width: 6px;
height: 6px;
background-color: #409eff;
border-radius: 50%;
margin-right: 8px;
vertical-align: middle;
}
}
</style>

View File

@@ -63,9 +63,9 @@ withDefaults(defineProps<Props>(), {
class="app-version text-foreground truncate text-nowrap font-semibold"
>
{{ text }}
<b>
<i>V {{ version }}</i>
</b>
<!-- <b>-->
<!-- <i>V {{ version }}</i>-->
<!-- </b>-->
</span>
</a>
</div>