Files
xk-admin/apps/web-antd/src/views/system/store/index.vue
李琦 235cccc146
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
转诊方优化
2026-03-07 13:11:23 +08:00

461 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts" setup>
import type { VxeGridListeners } from '#/adapter/vxe-table';
import { computed, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { useUserStore } from '@vben/stores';
import { useClipboard } from '@vueuse/core';
import { Button, Image, message, Modal, Switch, Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { Icon } from '#/components/icon';
import QrCodePreview from '#/components/modal/QrCodePreview.vue';
import { TableAction } from '#/components/table-action';
import {
batchSyncDrugPriceApi,
deleteStore,
openPcWindowsApiByStore,
openQrCodeApi,
updateClinicTypeApi,
updateStoreShippingFree,
updateStoreSubscribeStatus,
} from './api';
import FormModalDemo from './components/modal.vue';
import DrugPriceModal from './components/DrugPriceModal.vue';
import BindConsultationModal from './components/BindConsultationModal.vue';
import { formOptions } from './config/search';
import { gridOptions } from './config/table';
const userStore = useUserStore();
// 判断是否为平台管理员(user_type === 2)
const isPlatformAdmin = computed(() => {
return userStore?.userInfo?.roles?.user_type === 2;
});
const hasTopTableDropDownActions = ref(false);
const gridEvents: VxeGridListeners<any> = {
checkboxChange() {
// eslint-disable-next-line no-use-before-define
const records = gridApi.grid.getCheckboxRecords();
hasTopTableDropDownActions.value = records.length > 0;
},
checkboxAll() {
// eslint-disable-next-line no-use-before-define
const records = gridApi.grid.getCheckboxRecords();
hasTopTableDropDownActions.value = records.length > 0;
},
};
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions,
gridEvents,
});
const [QrCodePreviewModal, QrCodePreviewApi] = useVbenModal({
connectedComponent: QrCodePreview,
});
const openQrCodeModal = (url, title, address) => {
QrCodePreviewApi.setData({
// 表单值
values: url,
title,
address,
});
QrCodePreviewApi.open();
};
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: FormModalDemo,
});
const [DrugPriceModalComponent, drugPriceModalApi] = useVbenModal({
connectedComponent: DrugPriceModal,
});
const [BindConsultationModalComponent, bindConsultationModalApi] = useVbenModal({
connectedComponent: BindConsultationModal,
});
const showModal = (data = {}, isUpdate = false) => {
formModalApi.setData({
// 表单值
values: data,
update: isUpdate,
gridApi,
});
formModalApi.open();
};
/**
* 打开修改药品价格模态框
*/
const showDrugPriceModal = (row: any) => {
drugPriceModalApi.setData({
store_id: row.id,
});
drugPriceModalApi.open();
};
/**
* 打开绑定在线复诊配置弹窗
*/
const showBindConsultationModal = (row: any) => {
bindConsultationModalApi.setData({
values: row,
gridApi,
});
bindConsultationModalApi.open();
};
const deleteApi = (row: any) => {
let ids = [];
if (row) {
ids.push(row);
} else {
ids = gridApi.grid.getCheckboxRecords().map((item) => item.id);
}
deleteStore({ ids }).then(() => {
message.success('删除成功!');
gridApi.reload();
});
};
/**
* 开启后台账号
*/
function openPcWindows(id) {
openPcWindowsApiByStore(id).then(() => {
message.success('操作成功!');
gridApi.reload();
});
}
/**
* 开启后台账号
*/
function openQrCode(id) {
openQrCodeApi(id).then(() => {
message.success('操作成功!');
gridApi.reload();
});
}
function copyText(source) {
copy(source);
message.success('复制成功');
}
const { copy } = useClipboard({ legacy: true });
/**
* 更新包邮状态
*/
const updateShippingFree = (id: number) => {
updateStoreShippingFree({ id }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
/**
* 更新价格波动订阅状态
*/
const updateSubscribe = (id: number) => {
updateStoreSubscribeStatus({ id }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
/**
* 批量同步总仓库药品
*/
const batchSyncDrugPrice = () => {
const records = gridApi.grid.getCheckboxRecords();
if (records.length === 0) {
message.warning('请至少选择一条记录!');
return;
}
const ids = records.map((item) => item.id);
batchSyncDrugPriceApi(ids)
.then((res) => {
message.success(`批量同步任务已创建,共 ${res.data.success} 个门店的任务已提交!`);
gridApi.query();
})
.catch(() => {
message.error('批量同步失败!');
});
};
/**
* 切换诊所类型
*/
const handleSwitchClinicType = (row: any) => {
if (!row) return;
const currentType = row.clinic_type || 2; // 默认为中医诊所
const newType = currentType === 1 ? 2 : 1;
const currentTypeText = currentType === 1 ? '西医诊所' : '中医诊所';
const newTypeText = newType === 1 ? '西医诊所' : '中医诊所';
const clinicName = row.name || '该诊所';
Modal.confirm({
title: '确认切换诊所类型',
content: `确定要将【${clinicName}】的诊所类型从【${currentTypeText}】切换为【${newTypeText}】吗?`,
okText: '确定',
cancelText: '取消',
onOk: async () => {
try {
await updateClinicTypeApi({ id: row.id, clinic_type: newType });
message.success(`诊所类型已切换为【${newTypeText}】`);
gridApi.query();
} catch (error) {
console.error('切换诊所类型失败:', error);
message.error('切换失败,请稍后重试');
}
}
});
};
</script>
<template>
<Page auto-content-height title="诊所管理">
<FormModal />
<QrCodePreviewModal />
<DrugPriceModalComponent />
<BindConsultationModalComponent />
<Grid>
<template #toolbar-buttons>
<TableAction
:actions="[
{
label: '新增',
type: 'primary',
icon: 'ant-design:plus-outlined',
auth: ['Super Admin', 'Admin'],
onClick: showModal.bind(null),
},
]"
:drop-down-actions="[
{
label: '删除',
icon: 'ant-design:delete-outlined',
ifShow: hasTopTableDropDownActions,
auth: ['Super Admin', 'Admin'],
// auth: ['超级诊所', 'sys:user:save'],
popConfirm: {
title: '确定删除吗?',
confirm: deleteApi.bind(null, false),
},
},
{
label: '同步总仓库药品',
icon: 'ant-design:sync-outlined',
ifShow: hasTopTableDropDownActions,
popConfirm: {
title: '确定要同步选中门店的总仓库药品吗?同步将更新价格、上架下架状态,并自动添加新药品。',
confirm: batchSyncDrugPrice,
},
},
]"
>
<template #more>
<Button style="margin-left: 16px">
批量操作
<Icon icon="ant-design:down-outlined" />
</Button>
</template>
</TableAction>
</template>
<template #mobile="{ row }">
<div>
诊所联系人:{{ row.contact }}
<Button type="link" @click="copyText(row.contact)">复制</Button>
</div>
<div>
号码:{{ row.mobile }}
<Button type="link" @click="copyText(row.mobile)">复制</Button>
</div>
</template>
<template #qr_code="{ row }">
<div class="qr_code">
<Image
:preview="false"
:src="row.qr_code"
height="30"
width="30"
@click="
openQrCodeModal(
row.qr_code,
row.name,
`${row.province.name}${row.city.name}${row.position}`,
)
"
/>
</div>
</template>
<template #type="{ row }">
</template>
<template #clinic_type="{ row }">
<Tag
:color="row.clinic_type === 1 ? 'blue' : row.clinic_type === 2 ? 'green' : 'default'"
class="clinic-type-tag cursor-pointer"
@click="handleSwitchClinicType(row)"
>
{{ row.clinic_type === 1 ? '西医诊所' : row.clinic_type === 2 ? '中医诊所' : '未设置' }}
</Tag>
</template>
<template #online_consultation_config="{ row }">
<div
v-if="row.is_internet_medical === 1 && row.online_consultation_doctor_name"
class="cursor-pointer hover:text-blue-500"
@click="showBindConsultationModal(row)"
>
<div>负责人:{{ row.online_consultation_doctor_name }}</div>
</div>
<div
v-else-if="row.delegate_store_name || row.online_consultation_doctor_name"
class="cursor-pointer hover:text-blue-500"
@click="showBindConsultationModal(row)"
>
<div v-if="row.delegate_store_name">委托:{{ row.delegate_store_name }}</div>
<div v-if="row.online_consultation_doctor_name">负责人:{{ row.online_consultation_doctor_name }}</div>
</div>
<Button v-else type="link" size="small" @click="showBindConsultationModal(row)">
绑定
</Button>
</template>
<template #is_shipping_free="{ row }">
<Switch
:checked="row.is_shipping_free"
:checked-value="1"
:un-checked-value="0"
checked-children="包邮"
un-checked-children="不包邮"
@click="updateShippingFree(row.id)"
/>
</template>
<template #subscribe_price_change="{ row }">
<Tag
:color="row.subscribe_price_change === 0 ? 'success' : 'default'"
style="cursor: pointer"
@click="updateSubscribe(row.id)"
>
{{ row.subscribe_price_change === 0 ? '订阅' : '不订阅' }}
</Tag>
</template>
<template #start-time="{ row }">
早:<Tag color="success">{{ row.start_time }}</Tag>
<br />
<br />
晚:<Tag color="error">{{ row.end_time }}</Tag>
</template>
<template #toolbar-tools></template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '编辑',
type: 'link',
icon: 'uil:edit',
size: 'small',
auth: ['Super Admin', 'Admin'],
onClick: showModal.bind(null, row, true),
},
{
label: '删除',
type: 'link',
icon: 'ant-design:delete-outlined',
size: 'small',
auth: ['Super Admin', 'Admin'],
// auth: ['store', 'sys:role:detail'],
popConfirm: {
title: '确定删除吗?',
confirm: deleteApi.bind(null, row.id),
},
},
]"
:drop-down-actions="[
// {
// label: '编辑',
// type: 'link',
// icon: 'ant-design:delete-outlined',
// size: 'small',
// // auth: ['store', 'sys:role:detail'],
// onClick: showModal.bind(null, row, true),
// },
// {
// label: '删除',
// type: 'link',
// icon: 'ant-design:delete-outlined',
// size: 'small',
// // auth: ['store', 'sys:role:detail'],
// popConfirm: {
// title: '确定删除吗?',
// confirm: deleteApi.bind(null, row.id),
// },
// },
{
label: '开通后台',
type: 'link',
icon: 'uil:edit',
size: 'small',
auth: ['Super Admin', 'Admin'],
// auth: ['store', 'sys:role:detail'],
popConfirm: {
title: '确定开通后台吗?',
confirm: openPcWindows.bind(null, row.id),
},
},
{
label: '生成诊所二维码',
type: 'link',
icon: 'uil:edit',
size: 'small',
auth: ['Super Admin', 'Admin'],
// auth: ['store', 'sys:role:detail'],
popConfirm: {
title: '确定生成诊所二维码吗?',
confirm: openQrCode.bind(null, row.id),
},
},
{
label: '修改药品价格',
type: 'link',
icon: 'ant-design:edit-outlined',
size: 'small',
ifShow: isPlatformAdmin,
onClick: showDrugPriceModal.bind(null, row),
},
]"
/>
</template>
</Grid>
</Page>
</template>
<style scoped>
.qr_code:hover {
cursor: pointer;
}
/* 诊所类型标签样式 */
.clinic-type-tag {
transition: all 0.2s ease;
user-select: none;
&:hover {
opacity: 0.8;
transform: scale(1.05);
}
&:active {
transform: scale(0.95);
}
}
</style>