feat:
1. 更新框架 2. 修复框架更新后导致的问题 3. 消息系统升级
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/** 站内信类型字典 API */
|
||||
const prefix = 'admin-notice-type/';
|
||||
|
||||
export async function getAdminNoticeTypeList(data: any) {
|
||||
return requestClient.get<any>(`${prefix}list`, { params: data });
|
||||
}
|
||||
|
||||
export async function getAdminNoticeTypeOption(data?: any) {
|
||||
return requestClient.get<any>(`${prefix}option`, { params: data });
|
||||
}
|
||||
|
||||
export async function createAdminNoticeType(data: Record<string, any>) {
|
||||
return requestClient.post<any>(`${prefix}create`, data);
|
||||
}
|
||||
|
||||
export async function updateAdminNoticeType(data: Record<string, any>) {
|
||||
return requestClient.post<any>(`${prefix}update`, data);
|
||||
}
|
||||
|
||||
export async function deleteAdminNoticeType(data: Record<string, any>) {
|
||||
return requestClient.post<any>(`${prefix}delete`, data);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<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 { createAdminNoticeType, updateAdminNoticeType } from '../api';
|
||||
import { modalFormProps } from '../config/form';
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const gridApi = ref();
|
||||
const [Form, formApi] = useVbenForm(modalFormProps);
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
fullscreenButton: false,
|
||||
draggable: true,
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm: async () => {
|
||||
const e = await formApi.validate();
|
||||
if (!e.valid) return;
|
||||
const values = await formApi.getValues();
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
try {
|
||||
const api = isUpdate.value ? updateAdminNoticeType : createAdminNoticeType;
|
||||
await api(values);
|
||||
message.success('保存成功');
|
||||
gridApi.value?.query?.();
|
||||
gridApi.value?.reload?.();
|
||||
modalApi.close();
|
||||
} finally {
|
||||
modalApi.setState({ confirmLoading: false });
|
||||
}
|
||||
},
|
||||
onOpenChange(isOpen: boolean) {
|
||||
gridApi.value = isOpen ? modalApi.getData()?.gridApi : null;
|
||||
if (!isOpen) {
|
||||
formApi.resetForm();
|
||||
return;
|
||||
}
|
||||
const { values, update } = modalApi.getData<Record<string, any>>() || {};
|
||||
isUpdate.value = !!update;
|
||||
// 编辑时锁定 code,避免业务硬编码失效
|
||||
formApi.updateSchema([
|
||||
{
|
||||
fieldName: 'code',
|
||||
componentProps: { disabled: !!update },
|
||||
},
|
||||
]);
|
||||
if (values && update) {
|
||||
formApi.setValues({ ...values });
|
||||
} else {
|
||||
formApi.resetForm();
|
||||
formApi.setValues({ sort: 0, status: 1, color: 'sky', icon: '', cover_url: '' });
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Modal :title="`${isUpdate ? '编辑' : '新增'}消息类型`" class="w-[560px]">
|
||||
<Form />
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -0,0 +1,22 @@
|
||||
/** 站内信类型字典常量 */
|
||||
|
||||
export const STATUS_OPTIONS = [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '禁用', value: 0 },
|
||||
];
|
||||
|
||||
/** 主题色 token,与铃铛/卡片 CSS 映射一致 */
|
||||
export const COLOR_OPTIONS = [
|
||||
{ label: '天蓝 sky', value: 'sky' },
|
||||
{ label: '琥珀 amber', value: 'amber' },
|
||||
{ label: '翠绿 emerald', value: 'emerald' },
|
||||
{ label: '青绿 teal', value: 'teal' },
|
||||
{ label: '青色 cyan', value: 'cyan' },
|
||||
{ label: '橙色 orange', value: 'orange' },
|
||||
{ label: '紫色 violet', value: 'violet' },
|
||||
{ label: '靛蓝 indigo', value: 'indigo' },
|
||||
{ label: '蓝色 blue', value: 'blue' },
|
||||
{ label: '绿色 green', value: 'green' },
|
||||
{ label: '红色 red', value: 'red' },
|
||||
{ label: '酸橙 lime', value: 'lime' },
|
||||
];
|
||||
@@ -0,0 +1,75 @@
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
|
||||
import { COLOR_OPTIONS, STATUS_OPTIONS } from './constants';
|
||||
|
||||
/** 站内信类型表单 */
|
||||
export const modalFormProps: VbenFormProps = {
|
||||
wrapperClass: 'grid-cols-12',
|
||||
commonConfig: {
|
||||
formItemClass: 'col-span-12',
|
||||
componentProps: { class: 'w-full' },
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'id',
|
||||
label: 'ID',
|
||||
dependencies: { show: false, triggerFields: ['id'] },
|
||||
},
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'code',
|
||||
label: '类型编码',
|
||||
rules: 'required',
|
||||
componentProps: { placeholder: 'snake_case,如 withdraw_audit' },
|
||||
},
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'name',
|
||||
label: '展示名称',
|
||||
rules: 'required',
|
||||
componentProps: { placeholder: '如:提现待审' },
|
||||
},
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'icon',
|
||||
label: '图标',
|
||||
componentProps: {
|
||||
placeholder: 'iconify 名,如 ant-design:bell-outlined',
|
||||
},
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'cover_url',
|
||||
label: '封面图',
|
||||
componentProps: { placeholder: '可选图片 URL' },
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
component: 'VbenSelect',
|
||||
fieldName: 'color',
|
||||
label: '主题色',
|
||||
formItemClass: 'col-span-6',
|
||||
componentProps: { options: COLOR_OPTIONS },
|
||||
defaultValue: 'sky',
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'sort',
|
||||
label: '排序',
|
||||
formItemClass: 'col-span-6',
|
||||
componentProps: { min: 0 },
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
component: 'VbenSelect',
|
||||
fieldName: 'status',
|
||||
label: '状态',
|
||||
componentProps: { options: STATUS_OPTIONS },
|
||||
defaultValue: 1,
|
||||
},
|
||||
],
|
||||
showDefaultActions: false,
|
||||
};
|
||||
178
apps/web-antd/src/views/system/admin-notice-type/index.vue
Normal file
178
apps/web-antd/src/views/system/admin-notice-type/index.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<script lang="ts" setup>
|
||||
/**
|
||||
* 站内信类型字典:维护 code/图标/主题色,供消息中心与铃铛展示
|
||||
*/
|
||||
import type { VxeGridListeners } from '#/adapter/vxe-table';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { TableAction } from '#/components/table-action';
|
||||
|
||||
import {
|
||||
deleteAdminNoticeType,
|
||||
getAdminNoticeTypeList,
|
||||
} from './api';
|
||||
import FormModal from './components/modal.vue';
|
||||
import { STATUS_OPTIONS } from './config/constants';
|
||||
|
||||
defineOptions({ name: 'AdminNoticeType' });
|
||||
|
||||
const hasTopTableDropDownActions = ref(false);
|
||||
|
||||
const formOptions = {
|
||||
schema: [
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'code',
|
||||
label: '编码',
|
||||
componentProps: { placeholder: 'type_code' },
|
||||
},
|
||||
{
|
||||
component: 'VbenInput',
|
||||
fieldName: 'name',
|
||||
label: '名称',
|
||||
componentProps: { placeholder: '展示名' },
|
||||
},
|
||||
{
|
||||
component: 'VbenSelect',
|
||||
fieldName: 'status',
|
||||
label: '状态',
|
||||
componentProps: { options: STATUS_OPTIONS, allowClear: true },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const gridOptions = {
|
||||
checkboxConfig: { highlight: true, labelField: '' },
|
||||
columns: [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{ field: 'id', title: 'ID', width: 80 },
|
||||
{ field: 'code', title: '编码', minWidth: 160 },
|
||||
{ field: 'name', title: '名称', minWidth: 120 },
|
||||
{ field: 'icon', title: '图标', minWidth: 180 },
|
||||
{ field: 'color', title: '主题色', width: 100 },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'status_txt', title: '状态', width: 80 },
|
||||
{ field: 'created_at', title: '创建时间', width: 170 },
|
||||
{ title: '操作', slots: { default: 'action' }, width: 140, fixed: 'right' },
|
||||
],
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }: any, formValues: any) => {
|
||||
return await getAdminNoticeTypeList({
|
||||
page: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
height: 'auto',
|
||||
toolbarConfig: {
|
||||
search: true,
|
||||
refresh: true,
|
||||
slots: { buttons: 'toolbar-actions' },
|
||||
},
|
||||
};
|
||||
|
||||
const gridEvents: VxeGridListeners<any> = {
|
||||
checkboxChange() {
|
||||
hasTopTableDropDownActions.value =
|
||||
gridApi.grid.getCheckboxRecords().length > 0;
|
||||
},
|
||||
checkboxAll() {
|
||||
hasTopTableDropDownActions.value =
|
||||
gridApi.grid.getCheckboxRecords().length > 0;
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions: gridOptions as any,
|
||||
gridEvents,
|
||||
});
|
||||
|
||||
const [FormModalComp, formModalApi] = useVbenModal({
|
||||
connectedComponent: FormModal,
|
||||
});
|
||||
|
||||
const showModal = (data: any = {}, isUpdate = false) => {
|
||||
formModalApi.setData({
|
||||
values: data,
|
||||
update: isUpdate,
|
||||
gridApi,
|
||||
});
|
||||
formModalApi.open();
|
||||
};
|
||||
|
||||
const handleDelete = (row: any) => {
|
||||
deleteAdminNoticeType({ ids: [row.id] }).then(() => {
|
||||
message.success('删除成功');
|
||||
gridApi.query();
|
||||
});
|
||||
};
|
||||
|
||||
const handleBatchDelete = () => {
|
||||
const rows = gridApi.grid.getCheckboxRecords();
|
||||
if (!rows.length) return;
|
||||
deleteAdminNoticeType({ ids: rows.map((r: any) => r.id) }).then(() => {
|
||||
message.success('删除成功');
|
||||
gridApi.query();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<FormModalComp />
|
||||
<Grid>
|
||||
<template #toolbar-actions>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '新增',
|
||||
type: 'primary',
|
||||
onClick: () => showModal({}, false),
|
||||
},
|
||||
]"
|
||||
:drop-down-actions="
|
||||
hasTopTableDropDownActions
|
||||
? [
|
||||
{
|
||||
label: '批量删除',
|
||||
popConfirm: {
|
||||
title: '确认删除选中类型?',
|
||||
confirm: handleBatchDelete,
|
||||
},
|
||||
},
|
||||
]
|
||||
: []
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: () => showModal(row, true),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '确认删除该类型?',
|
||||
confirm: () => handleDelete(row),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
@@ -1,38 +1,93 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
/**
|
||||
* 医生预填审核弹窗(列表页)
|
||||
* 打开时按 ID 拉取详情,避免只显示通过/拒绝而看不到预填资料
|
||||
*/
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message, Radio, RadioGroup, Textarea } from 'ant-design-vue';
|
||||
import {
|
||||
Avatar,
|
||||
Descriptions,
|
||||
DescriptionsItem,
|
||||
Image,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Spin,
|
||||
Textarea,
|
||||
message,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { auditDoctorInput } from '../api';
|
||||
import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
|
||||
|
||||
import { auditDoctorInput, getDoctorInputDetail } from '../api';
|
||||
import {
|
||||
inputUserDisplayName,
|
||||
normalizeInputUser,
|
||||
resolveAvatarUrl,
|
||||
} from '../../store-input/utils/inputUser';
|
||||
|
||||
const auditStatus = ref<number>(1);
|
||||
const auditRemark = ref<string>('');
|
||||
const currentRow = ref<any>(null);
|
||||
const detail = ref<Record<string, any> | null>(null);
|
||||
const gridApi = ref<any>(null);
|
||||
const loading = ref(false);
|
||||
const detailLoading = ref(false);
|
||||
|
||||
const display = computed(() => detail.value || currentRow.value || null);
|
||||
|
||||
function typeText(type: number) {
|
||||
if (type === 1) return '中医医生';
|
||||
if (type === 2) return '西医医生';
|
||||
return '-';
|
||||
}
|
||||
|
||||
function signTypeText(signType: number) {
|
||||
if (signType === 1) return '电子签名';
|
||||
if (signType === 2) return '手写签名';
|
||||
return '-';
|
||||
}
|
||||
|
||||
function imgSrc(url?: string | null) {
|
||||
return resolveAvatarUrl(url) || String(url || '');
|
||||
}
|
||||
|
||||
async function loadDetail(id: number) {
|
||||
detailLoading.value = true;
|
||||
detail.value = null;
|
||||
try {
|
||||
const res = await getDoctorInputDetail(id);
|
||||
detail.value = res || null;
|
||||
normalizeInputUser(detail.value);
|
||||
} catch {
|
||||
message.error('加载预填详情失败');
|
||||
} finally {
|
||||
detailLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交医生预填审核结果
|
||||
* 通过 onConfirm 注册,与 Vben Modal 确认按钮对接
|
||||
*/
|
||||
const handleAudit = async () => {
|
||||
if (!currentRow.value) {
|
||||
const id = Number(display.value?.id || currentRow.value?.id || 0);
|
||||
if (!id) {
|
||||
message.error('数据错误');
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
try {
|
||||
await auditDoctorInput({
|
||||
id: currentRow.value.id,
|
||||
id,
|
||||
status: auditStatus.value,
|
||||
audit_remark: auditRemark.value,
|
||||
});
|
||||
message.success('审核成功');
|
||||
gridApi.value?.reload();
|
||||
gridApi.value?.reload?.();
|
||||
gridApi.value?.query?.();
|
||||
modalApi.close();
|
||||
auditStatus.value = 1;
|
||||
auditRemark.value = '';
|
||||
@@ -52,13 +107,20 @@ const [ModalComponent, modalApi] = useVbenModal({
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm: handleAudit,
|
||||
onOpenChange(isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
const { values, gridApi: api } = modalApi.getData<Record<string, any>>();
|
||||
currentRow.value = values;
|
||||
gridApi.value = api;
|
||||
auditStatus.value = 1;
|
||||
auditRemark.value = '';
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
detail.value = null;
|
||||
currentRow.value = null;
|
||||
return;
|
||||
}
|
||||
const { values, gridApi: api } = modalApi.getData<Record<string, any>>() || {};
|
||||
currentRow.value = values;
|
||||
gridApi.value = api;
|
||||
auditStatus.value = 1;
|
||||
auditRemark.value = '';
|
||||
const id = Number(values?.id || 0);
|
||||
if (id > 0) {
|
||||
await loadDetail(id);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -67,25 +129,121 @@ const [ModalComponent, modalApi] = useVbenModal({
|
||||
<template>
|
||||
<ModalComponent
|
||||
title="审核医生预填"
|
||||
class="w-[500px]"
|
||||
class="w-[820px] max-w-[96vw]"
|
||||
:confirm-loading="loading"
|
||||
>
|
||||
<div class="space-y-4 p-4">
|
||||
<div>
|
||||
<div class="mb-2 font-semibold">审核结果:</div>
|
||||
<RadioGroup v-model:value="auditStatus">
|
||||
<Radio :value="1">审核通过</Radio>
|
||||
<Radio :value="2">审核拒绝</Radio>
|
||||
</RadioGroup>
|
||||
<Spin :spinning="detailLoading">
|
||||
<div v-if="display" class="space-y-4 p-2">
|
||||
<Descriptions
|
||||
:column="{ xxl: 2, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }"
|
||||
bordered
|
||||
size="small"
|
||||
>
|
||||
<DescriptionsItem label="预填 ID">#{{ display.id }}</DescriptionsItem>
|
||||
<DescriptionsItem label="医生姓名">{{ display.name || '-' }}</DescriptionsItem>
|
||||
<DescriptionsItem label="手机号">
|
||||
<SensitiveText :record="display" field="mobile" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="身份证">
|
||||
<SensitiveText :record="display" field="idcard" />
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="身份">{{ typeText(Number(display.type)) }}</DescriptionsItem>
|
||||
<DescriptionsItem label="签名类型">
|
||||
{{ signTypeText(Number(display.sign_type)) }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="科室">{{ display.depart?.name || '-' }}</DescriptionsItem>
|
||||
<DescriptionsItem label="职称">{{ display.titleInfo?.name || '-' }}</DescriptionsItem>
|
||||
<DescriptionsItem label="录入人">
|
||||
<div class="flex items-center gap-2">
|
||||
<Avatar
|
||||
v-if="resolveAvatarUrl(display.inputUser?.avatar)"
|
||||
:src="resolveAvatarUrl(display.inputUser?.avatar)"
|
||||
:size="28"
|
||||
/>
|
||||
<span>{{ inputUserDisplayName(display.inputUser) }}</span>
|
||||
</div>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="擅长" :span="2">{{ display.good_at || '-' }}</DescriptionsItem>
|
||||
<DescriptionsItem label="简介" :span="2">{{ display.intro || '-' }}</DescriptionsItem>
|
||||
</Descriptions>
|
||||
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<div v-if="display.avatar" class="cert">
|
||||
<div class="cert-label">头像</div>
|
||||
<Image :src="imgSrc(display.avatar)" :width="80" :height="80" :preview="true" />
|
||||
</div>
|
||||
<div v-if="display.qualification" class="cert">
|
||||
<div class="cert-label">资格证书</div>
|
||||
<Image
|
||||
:src="imgSrc(display.qualification)"
|
||||
:width="80"
|
||||
:height="80"
|
||||
:preview="true"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="display.practicing" class="cert">
|
||||
<div class="cert-label">执业证书</div>
|
||||
<Image
|
||||
:src="imgSrc(display.practicing)"
|
||||
:width="80"
|
||||
:height="80"
|
||||
:preview="true"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="display.title" class="cert">
|
||||
<div class="cert-label">职称证书</div>
|
||||
<Image :src="imgSrc(display.title)" :width="80" :height="80" :preview="true" />
|
||||
</div>
|
||||
<div v-if="display.card_up" class="cert">
|
||||
<div class="cert-label">身份证正面</div>
|
||||
<Image :src="imgSrc(display.card_up)" :width="80" :height="80" :preview="true" />
|
||||
</div>
|
||||
<div v-if="display.card_down" class="cert">
|
||||
<div class="cert-label">身份证反面</div>
|
||||
<Image :src="imgSrc(display.card_down)" :width="80" :height="80" :preview="true" />
|
||||
</div>
|
||||
<div v-if="display.sign_image" class="cert">
|
||||
<div class="cert-label">签名</div>
|
||||
<Image :src="imgSrc(display.sign_image)" :width="80" :height="80" :preview="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mb-2 font-semibold">审核结果:</div>
|
||||
<RadioGroup v-model:value="auditStatus">
|
||||
<Radio :value="1">审核通过</Radio>
|
||||
<Radio :value="2">审核拒绝</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-2 font-semibold">审核备注:</div>
|
||||
<Textarea
|
||||
v-model:value="auditRemark"
|
||||
:rows="4"
|
||||
placeholder="请输入审核备注(可选)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-2 font-semibold">审核备注:</div>
|
||||
<Textarea
|
||||
v-model:value="auditRemark"
|
||||
:rows="4"
|
||||
placeholder="请输入审核备注(可选)"
|
||||
/>
|
||||
<div v-else-if="!detailLoading" class="p-8 text-center text-muted-foreground">
|
||||
暂无预填数据
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</ModalComponent>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cert {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 8px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid hsl(var(--border));
|
||||
background: hsl(var(--card, var(--background)));
|
||||
}
|
||||
|
||||
.cert-label {
|
||||
font-size: 12px;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -103,6 +103,14 @@ const [Modal, modalApi] = useVbenModal({
|
||||
gridApi.value = data.gridApi;
|
||||
storeId.value = Number(data.store_id || 0);
|
||||
storeName.value = data.store_name || '';
|
||||
const vip = data.vip || null;
|
||||
const code = String(vip?.level_code || 'V0').trim() || 'V0';
|
||||
const expireAt = Number(vip?.expire_at || 0);
|
||||
// 非普通且未过期(含终身 expire_at=0)可继承剩余时间
|
||||
const canKeep =
|
||||
!!vip &&
|
||||
code !== 'V0' &&
|
||||
!(expireAt > 0 && expireAt * 1000 <= Date.now());
|
||||
const [levels, presets] = await Promise.all([
|
||||
getVipLevelOption(),
|
||||
getVipDurationPresets(),
|
||||
@@ -111,10 +119,12 @@ const [Modal, modalApi] = useVbenModal({
|
||||
label: `${i.name}(${i.code})¥${i.price}`,
|
||||
value: i.id,
|
||||
}));
|
||||
presetOptions.value = (presets || []).map((i: any) => ({
|
||||
label: i.label,
|
||||
value: i.value,
|
||||
}));
|
||||
presetOptions.value = (presets || [])
|
||||
.filter((i: any) => i.value !== 'keep' || canKeep)
|
||||
.map((i: any) => ({
|
||||
label: i.label,
|
||||
value: i.value,
|
||||
}));
|
||||
formApi.updateSchema([
|
||||
{
|
||||
fieldName: 'level_id',
|
||||
@@ -125,7 +135,13 @@ const [Modal, modalApi] = useVbenModal({
|
||||
componentProps: { options: presetOptions.value },
|
||||
},
|
||||
]);
|
||||
formApi.setValues({ remark: '', custom_years: undefined });
|
||||
formApi.setValues({
|
||||
remark: '',
|
||||
custom_years: undefined,
|
||||
level_id: vip?.level_id ? Number(vip.level_id) : undefined,
|
||||
// 非普通会员默认继承剩余时间,不改动到期
|
||||
duration_preset: canKeep ? 'keep' : undefined,
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user