feat:
1. 更新框架 2. 修复框架更新后导致的问题
This commit is contained in:
@@ -227,7 +227,7 @@ const copyToClipboard = async (text: string) => {
|
||||
<DoctorCardModals />
|
||||
<OaAccountModals />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -168,7 +168,7 @@ export function createAdminGridOptions(
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -83,7 +83,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -81,7 +81,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
},
|
||||
gridEvents: {
|
||||
@@ -139,7 +139,7 @@ onMounted(async () => {
|
||||
<Page auto-content-height>
|
||||
<FormModalComp />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -68,7 +68,7 @@ const showDetail = (row: any) => {
|
||||
<FormModal />
|
||||
<DetailModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -65,7 +65,7 @@ const deleteApi = (row: any) => {
|
||||
<Page auto-content-height title="仓药绑定管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -64,7 +64,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -85,7 +85,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -49,7 +49,7 @@ function auditTagColor(status: number) {
|
||||
<Page auto-content-height title="仓品审核">
|
||||
<AuditModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction :actions="[]" :drop-down-actions="[]" />
|
||||
</template>
|
||||
<template #image="{ row }">
|
||||
|
||||
@@ -85,7 +85,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -49,7 +49,7 @@ function auditTagColor(status: number) {
|
||||
<Page auto-content-height title="我的商品">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -66,7 +66,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -122,7 +122,7 @@ const deleteApi = (row: any) => {
|
||||
<BankCardReportModalComponent />
|
||||
<BankCardStatusModalComponent />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ const gridOptions = {
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -221,7 +221,7 @@ function handleSyncPinyin() {
|
||||
<Form />
|
||||
</FormModal>
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -68,7 +68,7 @@ const gridOptions = {
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -187,7 +187,7 @@ function handleSyncPinyin() {
|
||||
<Form />
|
||||
</FormModal>
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ const gridOptions = computed(() => ({
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -227,7 +227,7 @@ function handleSyncPinyin() {
|
||||
<Form />
|
||||
</FormModal>
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ const gridOptions = {
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -164,7 +164,7 @@ async function handleDelete(ids: number[]) {
|
||||
<Form />
|
||||
</FormModal>
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@ export const inputGridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
},
|
||||
showOverflow: false,
|
||||
|
||||
@@ -88,7 +88,7 @@ const getStatusText = (status: number) => {
|
||||
<FormModal />
|
||||
<DetailModalComponent />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -115,7 +115,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
},
|
||||
gridEvents: {
|
||||
@@ -270,7 +270,7 @@ async function handleConfirmImport(payload: { rows: any[]; sourceId: number }) {
|
||||
<FormulaDrugsModalComp />
|
||||
<MissingDrugModalComp />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:flex="false"
|
||||
:actions="[
|
||||
|
||||
@@ -104,7 +104,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -112,7 +112,7 @@ const deleteZonesApi = (row: any) => {
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<Button
|
||||
v-if="hasTopTableDropDownActions"
|
||||
danger
|
||||
|
||||
@@ -86,7 +86,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -78,7 +78,7 @@ const collapseAll = () => {
|
||||
<Page auto-content-height title="菜单管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -69,7 +69,7 @@ const deleteApi = (row: any) => {
|
||||
<Page auto-content-height title="公告管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -147,7 +147,7 @@ onMounted(() => {
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="chat" tab="群聊">
|
||||
<Grid v-if="activeKey === 'chat'">
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -68,7 +68,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -89,7 +89,7 @@ function formatPayload(raw: any): string {
|
||||
<template>
|
||||
<Page auto-content-height title="OA 通知发送日志">
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<span class="text-xs text-gray-400">
|
||||
日志为只读,记录每次 OA 通知发送的请求和响应(含成功和失败)
|
||||
</span>
|
||||
|
||||
@@ -66,7 +66,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -201,7 +201,7 @@ loadPlatforms();
|
||||
<AppCredentialEditModal />
|
||||
<ChatBindEditModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -135,7 +135,7 @@ const deleteApi = (row: any) => {
|
||||
<div v-show="!showForm">
|
||||
<Page auto-content-height title="OA 通知场景管理">
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -107,7 +107,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -423,7 +423,7 @@ const batchSyncDrugPrice = () => {
|
||||
<BindPrescriptionTypesModalComponent />
|
||||
<StoreExternalFieldModalComponent />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -116,7 +116,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -111,7 +111,7 @@ const deleteQualificationsApi = (row: any) => {
|
||||
<!-- Tab 2: 平台资质管理 -->
|
||||
<TabPane key="qualifications" tab="平台资质管理">
|
||||
<QualificationsGrid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -81,7 +81,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -68,7 +68,7 @@ const deleteApi = (row: any) => {
|
||||
<Page auto-content-height title="平台资质管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
// {
|
||||
|
||||
@@ -62,7 +62,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -68,7 +68,7 @@ const deleteApi = (row: any) => {
|
||||
<Page auto-content-height title="平台管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -1,182 +1,182 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
|
||||
|
||||
import { Button, Input, InputNumber, Popover, Tag } from 'ant-design-vue';
|
||||
|
||||
|
||||
|
||||
type TagOption = { label: string; value: number | string };
|
||||
|
||||
|
||||
|
||||
const props = withDefaults(
|
||||
|
||||
defineProps<{
|
||||
|
||||
disabled?: boolean;
|
||||
|
||||
displayFormatter?: (value: unknown) => string;
|
||||
|
||||
label?: string;
|
||||
|
||||
options?: TagOption[];
|
||||
|
||||
placeholder?: string;
|
||||
|
||||
type?: 'number' | 'tags' | 'text';
|
||||
|
||||
value?: null | number | string;
|
||||
|
||||
}>(),
|
||||
|
||||
{
|
||||
|
||||
disabled: false,
|
||||
|
||||
label: '',
|
||||
|
||||
options: () => [],
|
||||
|
||||
placeholder: '请输入',
|
||||
|
||||
type: 'text',
|
||||
|
||||
value: '',
|
||||
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
||||
save: [value: number | string];
|
||||
|
||||
}>();
|
||||
|
||||
|
||||
|
||||
const open = ref(false);
|
||||
|
||||
const draftText = ref('');
|
||||
|
||||
const draftNumber = ref<null | number>(null);
|
||||
|
||||
const saving = ref(false);
|
||||
|
||||
|
||||
|
||||
watch(open, (visible) => {
|
||||
|
||||
if (!visible) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (props.type === 'number') {
|
||||
|
||||
const raw = props.value;
|
||||
|
||||
draftNumber.value =
|
||||
|
||||
raw !== null && raw !== undefined && raw !== '' ? Number(raw) : null;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
draftText.value = String(props.value ?? '');
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
function displayText() {
|
||||
|
||||
if (props.displayFormatter) {
|
||||
|
||||
return props.displayFormatter(props.value);
|
||||
|
||||
}
|
||||
|
||||
if (props.value === null || props.value === undefined || props.value === '') {
|
||||
|
||||
return '点击设置';
|
||||
|
||||
}
|
||||
|
||||
if (props.type === 'tags') {
|
||||
|
||||
const matched = props.options.find(
|
||||
|
||||
(item) => String(item.value) === String(props.value),
|
||||
|
||||
);
|
||||
|
||||
return matched?.label ?? String(props.value);
|
||||
|
||||
}
|
||||
|
||||
return String(props.value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function isEmptyValue() {
|
||||
|
||||
return props.value === null || props.value === undefined || props.value === '';
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function confirmSave() {
|
||||
|
||||
saving.value = true;
|
||||
|
||||
try {
|
||||
|
||||
if (props.type === 'number') {
|
||||
|
||||
if (draftNumber.value === null || draftNumber.value === undefined) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
emit('save', draftNumber.value);
|
||||
|
||||
} else {
|
||||
|
||||
const text = draftText.value.trim();
|
||||
|
||||
if (!text) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
emit('save', text);
|
||||
|
||||
}
|
||||
|
||||
open.value = false;
|
||||
|
||||
} finally {
|
||||
|
||||
saving.value = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function selectTag(value: number | string) {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { Button, Input, InputNumber, Popover, Tag } from 'ant-design-vue';
|
||||
|
||||
type TagOption = { label: string; value: number | string };
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
disabled?: boolean;
|
||||
displayFormatter?: (value: unknown) => string;
|
||||
label?: string;
|
||||
options?: TagOption[];
|
||||
placeholder?: string;
|
||||
type?: 'number' | 'tags' | 'text';
|
||||
value?: null | number | string;
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
label: '',
|
||||
options: () => [],
|
||||
placeholder: '请输入',
|
||||
type: 'text',
|
||||
value: '',
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
save: [value: number | string];
|
||||
}>();
|
||||
|
||||
const open = ref(false);
|
||||
const draftText = ref('');
|
||||
const draftNumber = ref<null | number>(null);
|
||||
const saving = ref(false);
|
||||
|
||||
watch(open, (visible) => {
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
if (props.type === 'number') {
|
||||
const raw = props.value;
|
||||
draftNumber.value =
|
||||
raw !== null && raw !== undefined && raw !== '' ? Number(raw) : null;
|
||||
return;
|
||||
}
|
||||
draftText.value = String(props.value ?? '');
|
||||
});
|
||||
|
||||
function displayText() {
|
||||
if (props.displayFormatter) {
|
||||
return props.displayFormatter(props.value);
|
||||
}
|
||||
if (props.value === null || props.value === undefined || props.value === '') {
|
||||
return '点击设置';
|
||||
}
|
||||
if (props.type === 'tags') {
|
||||
const matched = props.options.find(
|
||||
(item) => String(item.value) === String(props.value),
|
||||
);
|
||||
return matched?.label ?? String(props.value);
|
||||
}
|
||||
return String(props.value);
|
||||
}
|
||||
|
||||
function isEmptyValue() {
|
||||
return props.value === null || props.value === undefined || props.value === '';
|
||||
}
|
||||
|
||||
async function confirmSave() {
|
||||
saving.value = true;
|
||||
try {
|
||||
if (props.type === 'number') {
|
||||
if (draftNumber.value === null || draftNumber.value === undefined) {
|
||||
return;
|
||||
}
|
||||
emit('save', draftNumber.value);
|
||||
} else {
|
||||
const text = draftText.value.trim();
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
emit('save', text);
|
||||
}
|
||||
open.value = false;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function selectTag(value: number | string) {
|
||||
emit('save', value);
|
||||
open.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Popover v-model:open="open" trigger="click" placement="bottomLeft">
|
||||
<template #content>
|
||||
<div class="inline-editor-popover min-w-[220px]">
|
||||
<div v-if="label" class="mb-2 text-xs text-muted-foreground">{{ label }}</div>
|
||||
<template v-if="type === 'tags'">
|
||||
<div class="inline-editor-popover__tags">
|
||||
<Tag
|
||||
v-for="opt in options"
|
||||
:key="String(opt.value)"
|
||||
class="cursor-pointer transition-colors duration-200"
|
||||
:color="String(value) === String(opt.value) ? 'processing' : 'default'"
|
||||
@click="selectTag(opt.value)"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</Tag>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="type === 'number'">
|
||||
<InputNumber
|
||||
v-model:value="draftNumber"
|
||||
class="w-full"
|
||||
:min="0"
|
||||
:placeholder="placeholder"
|
||||
/>
|
||||
<div class="inline-editor-popover__actions">
|
||||
<Button size="small" @click="open = false">取消</Button>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
:loading="saving"
|
||||
@click="confirmSave"
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Input
|
||||
v-model:value="draftText"
|
||||
:placeholder="placeholder"
|
||||
@press-enter="confirmSave"
|
||||
/>
|
||||
<div class="inline-editor-popover__actions">
|
||||
<Button size="small" @click="open = false">取消</Button>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
:loading="saving"
|
||||
@click="confirmSave"
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-edit-trigger cursor-pointer border-b border-dashed border-transparent text-left transition-colors duration-200 hover:border-primary/50 hover:text-primary disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:class="{
|
||||
'text-muted-foreground': isEmptyValue() && !displayFormatter,
|
||||
}"
|
||||
:disabled="disabled"
|
||||
@click.stop
|
||||
>
|
||||
{{ displayText() }}
|
||||
</button>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.inline-editor-popover__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
.inline-editor-popover__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -54,7 +54,7 @@ export const gridOptions: VxeGridProps = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -69,7 +69,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -69,7 +69,7 @@ const deleteApi = (row: any) => {
|
||||
<Page auto-content-height title="快捷导航管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -97,7 +97,7 @@ const deleteApi = (row: any) => {
|
||||
<AuthMenu ref="authMenuRef" />
|
||||
<QuickNav ref="quickNavRef" />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -1 +1,83 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import type { SalespersonDashboardTrendItem } from '../api';
|
||||
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
EchartsUI,
|
||||
type EchartsUIType,
|
||||
useEcharts,
|
||||
} from '@vben/plugins/echarts';
|
||||
|
||||
const props = defineProps<{
|
||||
/** 本周期 trend,用于环比柱状图「本周期」系列 */
|
||||
current: SalespersonDashboardTrendItem[];
|
||||
/** 上一等长周期 compare_trend,用于「上周期」系列 */
|
||||
previous: SalespersonDashboardTrendItem[];
|
||||
}>();
|
||||
|
||||
const chartRef = ref<EchartsUIType>();
|
||||
const { renderEcharts, resize } = useEcharts(chartRef);
|
||||
|
||||
const maxLen = computed(() => Math.max(props.current.length, props.previous.length));
|
||||
|
||||
function resolveInputTotal(item: SalespersonDashboardTrendItem) {
|
||||
return item.input_total ?? item.clinic_count + item.pharmacy_count;
|
||||
}
|
||||
|
||||
/** 按序号对齐本周期与上周期录入总数,tooltip 展示真实时间标签 */
|
||||
async function renderChart() {
|
||||
const labels = Array.from({ length: maxLen.value }, (_, i) => `T${i + 1}`);
|
||||
const currentData = props.current.map((item) => resolveInputTotal(item));
|
||||
const previousData = props.previous.map((item) => resolveInputTotal(item));
|
||||
|
||||
await renderEcharts({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter(params: any) {
|
||||
const list = Array.isArray(params) ? params : [params];
|
||||
const idx = list[0]?.dataIndex ?? 0;
|
||||
const cur = props.current[idx];
|
||||
const prev = props.previous[idx];
|
||||
const lines = [`序号 ${idx + 1}`];
|
||||
if (cur) lines.push(`本周期 ${cur.label}:${resolveInputTotal(cur)} 家`);
|
||||
if (prev) lines.push(`上周期 ${prev.label}:${resolveInputTotal(prev)} 家`);
|
||||
return lines.join('<br/>');
|
||||
},
|
||||
},
|
||||
legend: { data: ['本周期录入', '上周期录入'] },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
xAxis: { type: 'category', data: labels },
|
||||
yAxis: { type: 'value', name: '录入数(家)', minInterval: 1 },
|
||||
series: [
|
||||
{
|
||||
name: '本周期录入',
|
||||
type: 'bar',
|
||||
data: currentData,
|
||||
itemStyle: { color: '#1677ff' },
|
||||
},
|
||||
{
|
||||
name: '上周期录入',
|
||||
type: 'bar',
|
||||
data: previousData,
|
||||
itemStyle: { color: '#bfbfbf' },
|
||||
},
|
||||
],
|
||||
});
|
||||
await nextTick();
|
||||
resize();
|
||||
}
|
||||
|
||||
watch([() => props.current, () => props.previous], renderChart, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<EchartsUI ref="chartRef" class="dashboard-chart" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-chart {
|
||||
width: 100%;
|
||||
height: 320px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1 +1,86 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import type { SalespersonDashboardTrendItem } from '../api';
|
||||
|
||||
import { nextTick, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
EchartsUI,
|
||||
type EchartsUIType,
|
||||
useEcharts,
|
||||
} from '@vben/plugins/echarts';
|
||||
|
||||
const props = defineProps<{
|
||||
/** 来自 dashboardData.trend:按时间桶聚合的录入趋势 */
|
||||
data: SalespersonDashboardTrendItem[];
|
||||
}>();
|
||||
|
||||
const chartRef = ref<EchartsUIType>();
|
||||
const { renderEcharts, resize } = useEcharts(chartRef);
|
||||
|
||||
/** 录入总数兜底:兼容旧接口未返回 input_total 的情况 */
|
||||
function resolveInputTotal(item: SalespersonDashboardTrendItem) {
|
||||
return item.input_total ?? item.clinic_count + item.pharmacy_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 trend 数据映射为 ECharts series
|
||||
* - 堆叠柱:录入诊所 / 录入药店
|
||||
* - 折线:录入总数
|
||||
*/
|
||||
async function renderChart() {
|
||||
const labels = props.data.map((item) => item.label);
|
||||
const clinicData = props.data.map((item) => item.clinic_count);
|
||||
const pharmacyData = props.data.map((item) => item.pharmacy_count);
|
||||
const totalData = props.data.map((item) => resolveInputTotal(item));
|
||||
|
||||
await renderEcharts({
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: { data: ['录入诊所', '录入药店', '录入总数'] },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: labels,
|
||||
axisLabel: { rotate: labels.length > 10 ? 45 : 0 },
|
||||
},
|
||||
yAxis: { type: 'value', name: '录入数(家)', minInterval: 1 },
|
||||
series: [
|
||||
{
|
||||
name: '录入诊所',
|
||||
type: 'bar',
|
||||
stack: 'input',
|
||||
data: clinicData,
|
||||
itemStyle: { color: '#1677ff' },
|
||||
},
|
||||
{
|
||||
name: '录入药店',
|
||||
type: 'bar',
|
||||
stack: 'input',
|
||||
data: pharmacyData,
|
||||
itemStyle: { color: '#52c41a' },
|
||||
},
|
||||
{
|
||||
name: '录入总数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: totalData,
|
||||
itemStyle: { color: '#722ed1' },
|
||||
},
|
||||
],
|
||||
});
|
||||
await nextTick();
|
||||
resize();
|
||||
}
|
||||
|
||||
watch(() => props.data, renderChart, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<EchartsUI ref="chartRef" class="dashboard-chart" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-chart {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -101,7 +101,7 @@ export const inputGridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
},
|
||||
showOverflow: false,
|
||||
@@ -192,7 +192,7 @@ export const auditGridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
},
|
||||
showOverflow: false,
|
||||
|
||||
@@ -117,7 +117,7 @@ const getStatusText = (status: number) => {
|
||||
<FormModal />
|
||||
<DetailModalComponent />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -97,7 +97,7 @@ const rowImageSrc = (row: DrugItem) => {
|
||||
/>
|
||||
</Tabs>
|
||||
<DrugGrid v-if="activeTab">
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<Button type="primary" @click="handleBatchSaveCurrent">
|
||||
批量保存
|
||||
</Button>
|
||||
|
||||
@@ -251,7 +251,7 @@ export const getDrugPriceGridOptions = (
|
||||
refresh: true,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
},
|
||||
height: 500,
|
||||
|
||||
@@ -121,7 +121,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
export: false,
|
||||
zoom: true,
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
icon: 'vxe-icon-menu',
|
||||
|
||||
@@ -504,7 +504,7 @@ const handleSwitchClinicType = (row: any) => {
|
||||
<StoreExternalFieldModalComponent />
|
||||
<SalespersonCommissionDrawer ref="salespersonDrawerRef" />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -83,7 +83,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
custom: {
|
||||
// 自定义列-图标
|
||||
|
||||
@@ -68,7 +68,7 @@ const deleteApi = (row: any) => {
|
||||
<Page auto-content-height title="供应商管理">
|
||||
<FormModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
// custom: true, // 自定义列
|
||||
zoom: true, // 最大化最小化
|
||||
slots: {
|
||||
buttons: 'toolbar-buttons',
|
||||
buttons: 'toolbar-actions',
|
||||
},
|
||||
},
|
||||
showOverflow: false,
|
||||
|
||||
@@ -74,7 +74,7 @@ const deleteApi = (row: any) => {
|
||||
<FormModal />
|
||||
<AssistantConfigModal />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
|
||||
@@ -45,6 +45,6 @@ export const gridOptions: VxeGridProps<any> = {
|
||||
search: true,
|
||||
refresh: true,
|
||||
zoom: true,
|
||||
slots: { buttons: 'toolbar-buttons' },
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user