init
This commit is contained in:
2025-06-27 17:42:38 +08:00
commit bd6402478b
5317 changed files with 785994 additions and 0 deletions
@@ -0,0 +1,304 @@
<template>
<BasicDrawer @register="registerDrawer" width="60%" @ok="handleSubmit">
<BasicForm @register="registerForm" />
<div class="line-d">
<div style="font-size: 16px; font-weight: bold">结算费用设置</div>
<a-button type="primary" @click="addCostList">添加</a-button>
</div>
<div class="list-d">
<div class="list-line-d" style="border: none; font-weight: bold; margin: 0">
<div class="item-d">费用类型</div>
<div class="item-d">结算对象</div>
<div class="item-d">图文咨询费用</div>
<div class="item-d">音视频咨询费用</div>
<div class="item-d-s"></div>
</div>
<template v-for="(item, index) in costList">
<div class="list-line-d" :style="{ marginTop: index === 0 ? 0 : '10px' }">
<div class="item-d">
<a-select
:disabled="index < 2"
v-model:value="item['costType']"
:options="[
{
label: '职称',
value: 1,
},
{
label: '单独设置',
value: 2,
},
]"
/>
</div>
<div class="item-d">
<JDictSelectTag
placeholder="请选择结算对象"
:disabled="index < 2"
:show-choose-option="false"
dict-code="z_doct_lev"
v-model:value="item['titleId']"
/>
</div>
<div class="item-d"> <a-input placeholder="请输入" v-model:value="item['textFee']" /> </div>
<div class="item-d"> <a-input placeholder="请输入" v-model:value="item['videoFee']" /> </div>
<div class="item-d-s">
<delete-outlined v-if="index > 1" style="cursor: pointer" @click="() => costList.splice(index, 1)" />
</div>
</div>
</template>
</div>
<div class="line-d">
<div style="font-size: 16px; font-weight: bold">结算周期设置</div>
</div>
<div class="range-date-d">
<a-range-picker
v-model:value="settingDate"
picker="month"
fotmat="YYYY-MM"
valueFormat="YYYY-MM"
style="width: 50%"
@change="changeRangeDate"
/>
</div>
<div class="list-d">
<div class="list-line-d-b" style="border: none; font-weight: bold; margin: 0">
<div class="item-d">月份</div>
<div class="item-d">范围类型</div>
<div class="item-d">自定义范围</div>
</div>
<template v-for="(item, index) in settingList">
<div class="list-line-d-b" :style="{ marginTop: index === 0 ? 0 : '10px' }">
<div class="item-d"> {{ item?.yearValue }}-{{ item?.monthValue }} </div>
<div class="item-d">
<JDictSelectTag
placeholder="请选择结范围"
:show-choose-option="false"
:string-to-number="true"
:options="[
{
label: '自然月',
value: 1,
},
{
label: '自定义起止时间',
value: 2,
},
]"
v-model:value="item['periodType']"
/>
</div>
<div class="item-d">
<a-range-picker
v-if="item['periodType'] !== 1"
v-model:value="item['settingDate']"
fotmat="YYYY-MM-DD"
valueFormat="YYYY-MM-DD"
style="width: 70%"
/>
</div>
</div>
</template>
</div>
</BasicDrawer>
</template>
<script setup lang="ts">
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { useDrawerInner } from '/@/components/Drawer';
import { schemas } from '/@/views/consult/settlement/settlement.data';
import { DeleteOutlined } from '@ant-design/icons-vue';
import { ref } from 'vue';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import dayjs from 'dayjs';
import { addApi, editApi } from '/@/views/consult/settlement/settlement.api';
const isUpdate = ref(false);
const costList = ref<any[]>([]);
const settingDate = ref(null);
const settingList = ref<any[]>([]);
const emit = defineEmits(['success']);
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
settingDate.value = null;
await resetFields();
setDrawerProps({
title: data.isUpdate ? '编辑结算配置' : '新增结算配置',
showFooter: true,
});
costList.value = [
{
costType: 1,
titleId: '2',
textFee: '',
videoFee: '',
},
{
costType: 1,
titleId: '4',
textFee: '',
videoFee: '',
},
];
settingList.value = [];
isUpdate.value = data.isUpdate;
console.log(data.record);
if (data.isUpdate) {
await setFieldsValue({
...data.record,
});
costList.value = JSON.parse(JSON.stringify(data?.record?.configCosts)) || [];
settingList.value = data?.record?.configPeriods
? data?.record?.configPeriods.map((item) => {
item['settingDate'] = [item.startDate, item.endDate];
return item;
})
: [];
if (settingList.value.length > 0) {
console.log(settingList.value);
settingDate.value = [
dayjs(settingList.value[0].startDate).format('YYYY-MM'),
dayjs(settingList.value[settingList.value.length - 1].startDate).format('YYYY-MM'),
];
}
}
});
function addCostList() {
costList.value.push({
costType: 1,
titleId: undefined,
textFee: '',
videoFee: '',
});
}
function changeRangeDate(v) {
settingList.value = [];
let c = dayjs(v[1]).diff(dayjs(v[0]), 'month');
let d = null;
for (let i = 0; i <= c; i++) {
d = dayjs(v[0]).add(i, 'month');
settingList.value.push({
periodType: 1,
settleId: '',
yearValue: d.format('YYYY') * 1,
monthValue: d.format('MM') * 1,
settingDate: [d.startOf('month'), d.endOf('month')],
startDate: '',
endDate: '',
});
}
console.log(settingList.value);
}
async function handleSubmit() {
try {
await setDrawerProps({
confirmLoading: true,
});
let values = await validate();
let params = {
...values,
configCosts: costList.value,
configPeriods: settingList.value.map((item) => {
item.startDate = dayjs(item.settingDate[0]).format('YYYY-MM-DD');
item.endDate = dayjs(item.settingDate[1]).format('YYYY-MM-DD');
return item;
}),
};
if (isUpdate.value) {
await editApi(params);
} else {
await addApi(params);
}
closeDrawer();
emit('success');
} catch (e) {
console.log(e);
} finally {
await setDrawerProps({
confirmLoading: false,
});
}
}
const [registerForm, { setFieldsValue, validate, resetFields }] = useForm({
schemas,
showActionButtonGroup: false,
});
</script>
<style scoped lang="less">
.line-d {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eaeaea;
padding-bottom: 10px;
}
.list-line-d,
.list-line-d-b {
display: flex;
border: 1px solid #eaeaea;
padding: 5px;
margin-top: 10px;
> div {
display: flex;
align-items: center;
justify-content: center;
padding: 5px 0;
}
.item-d {
width: calc((100% - 50px) / 4);
}
.item-d-s {
width: 50px;
}
}
.list-line-d-b {
> :nth-child(1) {
width: 100px;
}
> :nth-child(2) {
width: 180px;
}
> :nth-child(3) {
width: calc(100% - 280px);
}
}
.list-d {
:deep(.ant-select) {
width: 90%;
}
:deep(.ant-input) {
width: 80%;
margin-right: 5%;
}
}
.range-date-d {
margin-top: 5px;
display: flex;
justify-content: center;
align-items: center;
}
</style>
@@ -0,0 +1,97 @@
<template>
<div>
<a-button
style="margin-bottom: 10px"
type="primary"
@click="
() => {
emit('toOtherPages', props.commeStatus);
console.log(props.commeStatus);
}
"
>
<template #icon><left-outlined /></template>
返回
</a-button>
<BasicTable @register="registerTable">
<template #tableTitle>
<a-button type="primary">下载</a-button>
</template>
</BasicTable>
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { consultColumn } from '/@/views/consult/settlement/settlement.data';
import { watch } from 'vue';
import { LeftOutlined } from '@ant-design/icons-vue';
import { itemApi } from '/@/views/consult/settlement/settlement.api';
const props = defineProps({
id: {
type: String,
default: () => '',
},
detailId: {
type: String,
default: () => '',
},
monthId: {
type: String,
default: () => '',
},
commeStatus: {
type: String,
default: () => '',
},
});
watch(
() => props.id,
(v) => {
reload({ page: 1 });
}
);
watch(
() => props.monthId,
(v) => {
if (v) {
reload({ page: 1 });
}
}
);
const emit = defineEmits(['toOtherPages']);
const { tableContext } = useListPage({
tableProps: {
api: itemApi,
columns: consultColumn,
tableSetting: {
redo: true,
},
beforeFetch: (params) => {
params['settleId'] = props.detailId;
params['resultId'] = props.monthId;
if (props.id) params['periodId'] = props.id;
return params;
},
showActionColumn: false,
canResize: false,
useSearchForm: false,
immediate: false,
actionColumn: {
width: 220,
fixed: 'right',
},
},
});
function toConsult() {
emit('toOtherPages', 'consult');
}
const [registerTable, { reload }, {}] = tableContext;
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,82 @@
<template>
<div>
<a-button style="margin-bottom: 10px" type="primary" @click="() => emit('toOtherPages', 'settlement')">
<template #icon><left-outlined /></template>
返回
</a-button>
<BasicTable @register="registerTable">
<!-- <template #tableTitle>-->
<!-- <a-button type="primary">下载</a-button>-->
<!-- </template>-->
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'a'">
<a-button class="list-button" type="link" @click="toMonth(record)">月详情</a-button>
<a-button class="list-button" type="link" @click="toConsult(record)">咨询详情</a-button>
</template>
</template>
</BasicTable>
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { detailColumn } from '/@/views/consult/settlement/settlement.data';
import { watch } from 'vue';
import { LeftOutlined } from '@ant-design/icons-vue';
import { resultApi } from '/@/views/consult/settlement/settlement.api';
const props = defineProps({
id: {
type: String,
default: () => '',
},
});
watch(
() => props.id,
(v) => {
if (v) {
reload({ page: 1 });
}
}
);
const emit = defineEmits(['toOtherPages', 'toConsult']);
const { tableContext } = useListPage({
tableProps: {
api: resultApi,
columns: detailColumn,
beforeFetch: (params) => {
params['settleId'] = props.id;
return params;
},
tableSetting: {
redo: true,
},
showActionColumn: false,
canResize: false,
useSearchForm: false,
immediate: false,
actionColumn: {
width: 220,
fixed: 'right',
},
},
});
function toMonth(record: Recordable) {
emit('toOtherPages', 'month', record?.id);
}
function toConsult(record: Recordable) {
emit('toOtherPages', 'consult', record?.id);
emit('toConsult', 'detail', record?.id);
}
const [registerTable, { reload }, {}] = tableContext;
</script>
<style scoped lang="less">
.list-button {
padding: 0 3px;
}
</style>
@@ -0,0 +1,79 @@
<template>
<div>
<a-button style="margin-bottom: 10px" type="primary" @click="() => emit('toOtherPages', 'detail')">
<template #icon><left-outlined /></template>
返回
</a-button>
<BasicTable @register="registerTable">
<template #tableTitle>
<a-button type="primary">下载</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'a'">
<a-button class="list-button" type="link" @click="toConsult(record)">咨询详情</a-button>
</template>
</template>
</BasicTable>
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { monthColumn } from '/@/views/consult/settlement/settlement.data';
import { watch } from 'vue';
import { LeftOutlined } from '@ant-design/icons-vue';
import { itemApi, periodApi } from '/@/views/consult/settlement/settlement.api';
const props = defineProps({
id: {
type: String,
default: () => '',
},
detailId: {
type: String,
default: () => '',
},
});
watch(
() => props.id,
(v) => {
if (v) {
reload({ page: 1 });
}
}
);
const emit = defineEmits(['toOtherPages', 'toConsult']);
const { tableContext } = useListPage({
tableProps: {
api: periodApi,
columns: monthColumn,
tableSetting: {
redo: true,
},
beforeFetch: (params) => {
params['settleId'] = props.detailId;
params['resultId'] = props.id;
return params;
},
showActionColumn: false,
canResize: false,
useSearchForm: false,
immediate: false,
actionColumn: {
width: 220,
fixed: 'right',
},
},
});
function toConsult(record: Recordable) {
emit('toConsult', 'month');
emit('toOtherPages', 'consult', record?.id);
}
const [registerTable, { reload }, {}] = tableContext;
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,21 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/health-consultation/settle/config/list',
detail = '/health-consultation/settle/config',
result = '/health-consultation/settle/result',
item = '/health-consultation/settle/result/item',
period = '/health-consultation/settle/result/period',
generate = '/health-consultation/settle/generate/',
add = '/health-consultation/settle/config/add',
edit = '/health-consultation/settle/config/edit',
}
export const listApi = (params = {}) => defHttp.get({ url: Api.list, params });
export const resultApi = (params = {}) => defHttp.get({ url: Api.result, params });
export const itemApi = (params = {}) => defHttp.get({ url: Api.item, params });
export const periodApi = (params = {}) => defHttp.get({ url: Api.period, params });
export const generateApi = (id) => defHttp.post({ url: Api.generate + id }, { isReturnNativeResponse: true });
export const addApi = (params = {}) => defHttp.post({ url: Api.add, params });
export const editApi = (params = {}) => defHttp.post({ url: Api.edit, params });
export const detailApi = (params = {}) => defHttp.get({ url: Api.detail + `/${params.id}` });
@@ -0,0 +1,267 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { getName } from '/@/views/interveneNew/compoents/utils';
import dayjs from 'dayjs';
const status = [
{
label: '待开始',
value: '0',
},
{
label: '结算中',
value: '1',
},
{
label: '已完成',
value: '2',
},
{
label: '结算异常',
value: '3',
},
{
label: '队列中',
value: '5',
},
];
export const schemas: FormSchema[] = [
{
label: '结算名称',
field: 'settleName',
component: 'Input',
required: true,
},
{
label: '是否产生通讯费用',
field: 'hasComFee',
component: 'RadioGroup',
defaultValue: true,
componentProps: () => {
return {
options: [
{
label: '是',
value: true,
},
{
label: '否',
value: false,
},
],
};
},
},
{
label: '通讯费',
field: 'comFeePerMonth',
component: 'Input',
componentProps: () => {
return {
suffix: '元',
};
},
ifShow: ({ values }) => values.hasComFee,
required: true,
},
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
export const columns: BasicColumn[] = [
{
title: '结算名称',
dataIndex: 'settleName',
},
{
title: '结算起始月份',
dataIndex: '2',
customRender: ({ record }) => {
return (
record?.configPeriods &&
record?.configPeriods.length > 0 &&
record?.configPeriods[0]?.yearValue + '-' + record?.configPeriods[0]?.monthValue
);
},
},
{
title: '结算结束月份',
dataIndex: '3',
customRender: ({ record }) => {
return (
record?.configPeriods &&
record?.configPeriods.length > 0 &&
record?.configPeriods[record?.configPeriods.length - 1]?.yearValue +
'-' +
record?.configPeriods[record?.configPeriods.length - 1]?.monthValue
);
},
},
{
title: '结算状态',
dataIndex: 'settleStatus',
customRender: ({ text }) => {
return getName(text, status);
},
},
{
title: '创建时间',
dataIndex: 'createTime',
},
{
title: '结算开始时间',
dataIndex: 'lastGenerateTime',
},
{
title: '结算完成时间',
dataIndex: 'lastFinishedTime',
},
{
title: '错误信息',
dataIndex: 'errorMsg',
defaultHidden: true,
},
{
title: '结算操作',
dataIndex: 'a',
fixed: 'right',
width: 220,
},
{
title: '配置操作',
dataIndex: 'b',
fixed: 'right',
width: 150,
},
];
export const detailColumn: BasicColumn[] = [
{
title: '专家编号',
dataIndex: 'doctorNo',
},
{
title: '专家名称',
dataIndex: 'doctorName',
},
{
title: '专家职称',
dataIndex: 'doctorTitle_dictText',
},
{
title: '医院',
dataIndex: 'hospitalName',
},
{
title: '单价(元)',
dataIndex: 'doctorPrice',
},
{
title: '回复次数',
dataIndex: 'consultCount',
},
{
title: '通讯费(元)',
dataIndex: 'comFee',
},
{
title: '咨询费(元)',
dataIndex: 'consultFee',
},
{
title: '结算费(元)',
dataIndex: 'settleInvoice',
},
{
title: '操作',
dataIndex: 'a',
width: 150,
},
];
export const monthColumn: BasicColumn[] = [
...detailColumn.slice(0, 5),
{
title: '结算年份',
dataIndex: 'yearValue',
},
{
title: '结算月份',
dataIndex: 'monthValue',
},
...detailColumn.slice(5),
];
export const consultColumn: BasicColumn[] = [
{
title: '专家编号',
dataIndex: 'doctorNo',
},
{
title: '专家名称',
dataIndex: 'doctorName',
},
{
title: '专家职称',
dataIndex: 'doctorTitle_dictText',
},
{
title: '医院',
dataIndex: 'hospitalName',
},
{
title: '科室',
dataIndex: 'departmentName',
},
{
title: '单位',
dataIndex: 'secondDepartName',
},
{
title: '部门',
dataIndex: 'userDepartName',
},
{
title: '员工名称',
dataIndex: 'userName',
},
{
title: '身份证号',
dataIndex: 'userIdCard',
},
{
title: '生日',
dataIndex: 'userBirthday',
customRender: ({ text }) => {
return text && dayjs(text).format('YYYY-MM-DD');
},
},
{
title: '年龄',
dataIndex: 'userAge',
width: 80,
},
{
title: '性别',
dataIndex: 'userSex_dictText',
width: 80,
},
{
title: '用户咨询时间',
dataIndex: 'userConsultTime',
},
{
title: '专家首次回复时间',
dataIndex: 'doctorFirstReplyTime',
},
{
title: '订单状态',
dataIndex: 'sessionStatus_dictText',
},
];
export const pageStatus = [{}];
+159
View File
@@ -0,0 +1,159 @@
<template>
<div style="padding: 10px">
<BasicTable v-show="pageStatus === 'settlement'" @register="registerTable">
<template #tableTitle>
<a-button type="primary" @click="addD">新增</a-button>
<a-button type="primary" @click="() => reload({ page: 1 })">刷新</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'a'">
<a-button class="list-button" type="link" @click="generate(record)">生成结算</a-button>
<a-button class="list-button" type="link" @click="toPage('detail', record)">查看报表</a-button>
<a-button class="list-button" type="link" @click="downLoadReport(record)">报表下载</a-button>
</template>
<template v-if="column.dataIndex === 'b'">
<a-button class="list-button" type="link" @click="updateSetting(record)">编辑配置</a-button>
<a-button class="list-button" type="link">删除</a-button>
</template>
</template>
</BasicTable>
<settlement-detail
v-show="pageStatus === 'detail'"
@to-other-pages="detailPage"
:id="detailId"
@to-consult="
(path, id) => {
toConsult = path;
consultId = '';
monthId = id;
}
"
/>
<settlement-moth
v-show="pageStatus === 'month'"
@to-other-pages="MonthPage"
:id="monthId"
:detailId="detailId"
@to-consult="(path) => (toConsult = path)"
/>
<settlement-consult
v-show="pageStatus === 'consult'"
:comme-status="toConsult"
:monthId="monthId"
:detailId="detailId"
:id="consultId"
@to-other-pages="(path) => (pageStatus = path)"
/>
<add-drawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns } from '/@/views/consult/settlement/settlement.data';
import { ref } from 'vue';
import SettlementDetail from '/@/views/consult/settlement/components/settlementDetail.vue';
import SettlementMoth from '/@/views/consult/settlement/components/settlementMoth.vue';
import SettlementConsult from '/@/views/consult/settlement/components/settlementConsult.vue';
import AddDrawer from '/@/views/consult/settlement/components/addDrawer.vue';
import { useDrawer } from '/@/components/Drawer';
import { generateApi, listApi } from '/@/views/consult/settlement/settlement.api';
import { message } from 'ant-design-vue';
import { getFileAccessHttpUrlDown } from '/@/utils/common/compUtils';
const pageStatus = ref('settlement'); // 当前页面是哪个 settlement为list页 detail为详情页 month为月明细页 consult为咨询明细页
const detailId = ref('');
const monthId = ref('');
const consultId = ref('');
const toConsult = ref('');
const [registerDrawer, { openDrawer }] = useDrawer();
const { tableContext } = useListPage({
tableProps: {
api: listApi,
columns,
tableSetting: {
redo: true,
},
showActionColumn: false,
canResize: false,
useSearchForm: false,
actionColumn: {
width: 220,
fixed: 'right',
},
},
});
function toPage(path, record) {
if (!record?.statementFile) {
return message.warn('当前未生成报表,请先生成报表');
}
pageStatus.value = path;
detailId.value = record.id;
}
function downLoadReport(record: Recordable) {
if (!record?.statementFile) {
return message.warn('当前未生成报表,请先生成报表');
}
window.open(getFileAccessHttpUrlDown(record?.statementFile));
}
function updateSetting(record: Recordable) {
openDrawer(true, {
isUpdate: true,
record,
});
}
function MonthPage(path, id) {
pageStatus.value = path;
if (path === 'consult') consultId.value = id;
}
function detailPage(path, id) {
pageStatus.value = path;
if (path === 'settlement') {
return;
} else {
consultId.value = '';
monthId.value = '';
}
if (path === 'month') {
monthId.value = id;
} else {
consultId.value = id;
}
}
function addD() {
openDrawer(true, {
isUpdate: false,
});
}
async function generate(record: Recordable) {
const { data } = await generateApi(record?.id);
if (data.code === 200) {
message.info('结算生成中,请稍后刷新');
} else {
message.warn(data.message);
}
handleSuccess();
}
function handleSuccess() {
reload();
}
const [registerTable, { reload }, {}] = tableContext;
</script>
<style scoped lang="less">
.list-button {
padding: 0 3px;
}
</style>