Jeccg自定义弹窗(组件和页面)

本博客源自June’s Blog - 个人生活记录 (june-pj.cn)

前言

​书接上回,导师要换项目架构,选择了Jeecg,目前已经通过Jeecg的代码生成器搭建了个简单的前后端,数据库导师也搭完了,然后让我接手剩下的,完善需求。

参考链接

JeecgBoot 文档中心

需求分析

为了书写方便,会简化说明项目架构

​ 目前有三张单表:病态评估治疗方案疗效数据。其中的物理外键关系是,病态评估治疗方案一对多,病态评估疗效数据一对一。

在代码生成器生成的前端代码中,这三者是独立的,现在需求是,只能从病态评估页面中对其余两张表新增操作(需绑定病态评估信息)

可分为以下两点处理

  • 疗效数据,一对一,从病态评估页面中打开原本疗效数据页面的新增弹窗
  • 治疗方案,一对多,从病态评估页面中打开治疗方案页面,需携带病态评估单行的数据

原始数据

这里只给出需要改动的部分

病态评估SiPatientsymptom

SiPatientsymptomList.vue

<template>
  <div>
    <!--引用表格-->
    <BasicTable @register="registerTable" :rowSelection="rowSelection">
      <!--插槽:table标题-->
      <template #tableTitle>
        <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增 </a-button>
        <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出 </a-button>
        <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls"> 导入 </j-upload-button>
        <a-dropdown v-if="selectedRowKeys.length > 0">
          <template #overlay>
            <a-menu>
              <a-menu-item key="1" @click="batchHandleDelete">
                <Icon icon="ant-design:delete-outlined"></Icon>
                删除
              </a-menu-item>
            </a-menu>
          </template>
          <a-button
            >批量操作
            <Icon icon="mdi:chevron-down"></Icon>
          </a-button>
        </a-dropdown>
        <!-- 高级查询 -->
        <!--        <super-query :config="superQueryConfig" @search="handleSuperQuery" />-->
      </template>
      <!--操作栏-->
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
      </template>
      <!--字段回显插槽-->
      <template v-slot:bodyCell="{ column, record, index, text }"></template>
    </BasicTable>
    <!-- 表单区域 -->
    <SiPatientsymptomModal @register="registerModal" @success="handleSuccess"></SiPatientsymptomModal>
  </div>
</template>

<script lang="ts" name="siPatientsymptom-siPatientsymptom" setup>
  import { ref, reactive, computed, unref } from 'vue';
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage';
  import SiPatientsymptomModal from './components/SiPatientsymptomModal.vue';
  import { columns, searchFormSchema, superQuerySchema } from './SiPatientsymptom.data';
  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './SiPatientsymptom.api';
  import { downloadFile } from '/@/utils/common/renderUtils';
  import { useUserStore } from '/@/store/modules/user';

  const queryParam = reactive<any>({});
  const checkedKeys = ref<Array<string | number>>([]);
  const userStore = useUserStore();
  //注册model
  const [registerModal, { openModal }] = useModal();
  //注册table数据
  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
    tableProps: {
      title: '病人症状(病态评估)',
      api: list,
      columns,
      canResize: false,
      formConfig: {
        //labelWidth: 120,
        schemas: searchFormSchema,
        autoSubmitOnEnter: true,
        showAdvancedButton: true,
        fieldMapToNumber: [],
        fieldMapToTime: [],
      },
      actionColumn: {
        width: 300,
        fixed: 'right',
      },
      beforeFetch: (params) => {
        return Object.assign(params, queryParam);
      },
    },
    exportConfig: {
      name: '病人症状(病态评估)',
      url: getExportUrl,
      params: queryParam,
    },
    importConfig: {
      url: getImportUrl,
      success: handleSuccess,
    },
  });

  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;

  // 高级查询配置
  const superQueryConfig = reactive(superQuerySchema);

  /**
   * 高级查询事件
   */
  function handleSuperQuery(params) {
    Object.keys(params).map((k) => {
      queryParam[k] = params[k];
    });
    reload();
  }

  /**
   * 新增事件
   */
  function handleAdd() {
    openModal(true, {
      isUpdate: false,
      showFooter: true,
    });
  }

  /**
   * 编辑事件
   */
  function handleEdit(record: Recordable) {
    openModal(true, {
      record,
      isUpdate: true,
      showFooter: true,
    });
  }

  /**
   * 详情
   */
  function handleDetail(record: Recordable) {
    openModal(true, {
      record,
      isUpdate: true,
      showFooter: false,
    });
  }

  /**
   * 删除事件
   */
  async function handleDelete(record) {
    await deleteOne({ id: record.id }, handleSuccess);
  }

  /**
   * 批量删除事件
   */
  async function batchHandleDelete() {
    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
  }

  /**
   * 成功回调
   */
  function handleSuccess() {
    (selectedRowKeys.value = []) && reload();
  }

  /**
   * 操作栏
   */
  function getTableAction(record) {
    return [
      {
        label: '编辑',
        onClick: handleEdit.bind(null, record),
      },
    ];
  }

  /**
   * 下拉操作栏
   */
  function getDropDownAction(record) {
    return [
      {
        label: '详情',
        onClick: handleDetail.bind(null, record),
      },
      {
        label: '删除',
        popConfirm: {
          title: '是否确认删除',
          confirm: handleDelete.bind(null, record),
          placement: 'topLeft',
        },
      },
    ];
  }
</script>

<style scoped></style>

治疗方案SiTherapeuticschedule

SiTherapeuticscheduleList.vue

<template>
  <div>
    <!--引用表格-->
    <BasicTable @register="registerTable" :rowSelection="rowSelection">
      <!--插槽:table标题-->
      <template #tableTitle>
        <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
        <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
        <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
        <a-dropdown v-if="selectedRowKeys.length > 0">
          <template #overlay>
            <a-menu>
              <a-menu-item key="1" @click="batchHandleDelete">
                <Icon icon="ant-design:delete-outlined"></Icon>
                删除
              </a-menu-item>
            </a-menu>
          </template>
          <a-button
            >批量操作
            <Icon icon="mdi:chevron-down"></Icon>
          </a-button>
        </a-dropdown>
        <!-- 高级查询 -->
        <!--        <super-query :config="superQueryConfig" @search="handleSuperQuery" />-->
      </template>
      <!--操作栏-->
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
      </template>
      <!--字段回显插槽-->
      <template v-slot:bodyCell="{ column, record, index, text }">
        <template v-if="column.dataIndex === 'content'">
          <!--富文本件字段回显插槽-->
          <div v-html="text"></div>
        </template>
      </template>
    </BasicTable>
    <!-- 表单区域 -->
    <SiTherapeuticscheduleModal @register="registerModal" @success="handleSuccess"></SiTherapeuticscheduleModal>
  </div>
</template>

<script lang="ts" name="siTherapeuticschedule-siTherapeuticschedule" setup>
  import { ref, reactive, computed, unref } from 'vue';
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage';
  import SiTherapeuticscheduleModal from './components/SiTherapeuticscheduleModal.vue';
  import { columns, searchFormSchema, superQuerySchema } from './SiTherapeuticschedule.data';
  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './SiTherapeuticschedule.api';
  import { downloadFile } from '/@/utils/common/renderUtils';
  import { useUserStore } from '/@/store/modules/user';
  const queryParam = reactive<any>({});
  const checkedKeys = ref<Array<string | number>>([]);
  const userStore = useUserStore();
  //注册model
  const [registerModal, { openModal }] = useModal();
  //注册table数据
  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
    tableProps: {
      title: '治疗方案',
      api: list,
      columns,
      canResize: false,
      formConfig: {
        //labelWidth: 120,
        schemas: searchFormSchema,
        autoSubmitOnEnter: true,
        showAdvancedButton: true,
        fieldMapToNumber: [],
        fieldMapToTime: [],
      },
      actionColumn: {
        width: 120,
        fixed: 'right',
      },
      beforeFetch: (params) => {
        return Object.assign(params, queryParam);
      },
    },
    exportConfig: {
      name: '治疗方案',
      url: getExportUrl,
      params: queryParam,
    },
    importConfig: {
      url: getImportUrl,
      success: handleSuccess,
    },
  });

  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;

  // 高级查询配置
  const superQueryConfig = reactive(superQuerySchema);

  /**
   * 高级查询事件
   */
  function handleSuperQuery(params) {
    Object.keys(params).map((k) => {
      queryParam[k] = params[k];
    });
    reload();
  }
  /**
   * 新增事件
   */
  function handleAdd() {
    openModal(true, {
      isUpdate: false,
      showFooter: true,
    });
  }
  /**
   * 编辑事件
   */
  function handleEdit(record: Recordable) {
    openModal(true, {
      record,
      isUpdate: true,
      showFooter: true,
    });
  }
  /**
   * 详情
   */
  function handleDetail(record: Recordable) {
    openModal(true, {
      record,
      isUpdate: true,
      showFooter: false,
    });
  }
  /**
   * 删除事件
   */
  async function handleDelete(record) {
    await deleteOne({ id: record.id }, handleSuccess);
  }
  /**
   * 批量删除事件
   */
  async function batchHandleDelete() {
    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
  }
  /**
   * 成功回调
   */
  function handleSuccess() {
    (selectedRowKeys.value = []) && reload();
  }
  /**
   * 操作栏
   */
  function getTableAction(record) {
    return [
      {
        label: '编辑',
        onClick: handleEdit.bind(null, record),
      },
    ];
  }
  /**
   * 下拉操作栏
   */
  function getDropDownAction(record) {
    return [
      {
        label: '详情',
        onClick: handleDetail.bind(null, record),
      },
      {
        label: '删除',
        popConfirm: {
          title: '是否确认删除',
          confirm: handleDelete.bind(null, record),
          placement: 'topLeft',
        },
      },
    ];
  }
</script>

<style scoped></style>

SiTherapeuticschedule.data.ts

import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { rules } from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
  {
    title: '病人',
    align: 'center',
    dataIndex: 'patientName',
  },
  {
    title: '评估症状',
    align: 'center',
    dataIndex: 'psymptomName',
  },
  {
    title: '方案名称',
    align: 'center',
    dataIndex: 'scheme_dictText',
  },
  {
    title: '方案内容',
    align: 'center',
    dataIndex: 'content',
  },
];
//查询数据
export const searchFormSchema: FormSchema[] = [
  {
    label: '病人',
    field: 'patientName',
    component: 'JPopup',
    componentProps: ({ formActionType }) => {
      const { setFieldsValue } = formActionType;
      return {
        setFieldsValue: setFieldsValue,
        code: 'si_patientsbaseinfo',
        fieldConfig: [
          { source: 'name', target: 'patientName' },
          { source: 'id', target: 'patient' },
        ],
        multi: true,
      };
    },
  },
  {
    label: '评估症状',
    field: 'psymptomName',
    component: 'Input',
  },
  {
    label: '方案名称',
    field: 'scheme',
    component: 'JTreeSelect',
    componentProps: {
      dict: 'si_schemetemplate,name,id',
      pidValue: '0',
    },
  },
];
//表单数据
export const formSchema: FormSchema[] = [
  {
    label: '病人',
    field: 'patientName',
    component: 'Input',
  },
  {
    label: '评估症状',
    field: 'psymptom',
    component: 'JSearchSelect',
    componentProps: {
      dict: 'si_patientsymptom,name,id',
    },
    dynamicRules: ({ model, schema }) => {
      return [{ required: true, message: '请输入评估症状!' }];
    },
  },
  {
    label: '方案名称',
    field: 'scheme',
    component: 'JTreeSelect',
    componentProps: {
      dict: 'si_schemetemplate,name,id',
      pidValue: '0',
    },
    dynamicRules: ({ model, schema }) => {
      return [{ required: true, message: '请输入方案名称!' }];
    },
  },
  {
    label: '方案内容',
    field: 'content',
    component: 'JEditor',
  },
  // TODO 主键隐藏字段,目前写死为ID
  {
    label: '',
    field: 'id',
    component: 'Input',
    show: false,
  },
];

// 高级查询数据
export const superQuerySchema = {
  psymptom: {
    title: '评估症状',
    order: 0,
    view: 'sel_search',
    type: 'string',
    dictTable: 'si_patientsymptom',
    dictCode: 'id',
    dictText: 'name',
  },
  scheme: {
    title: '方案名称',
    order: 1,
    view: 'sel_tree',
    type: 'string',
    dict: 'si_schemetemplate,name,id',
    pidValue: '0',
  },
  content: { title: '方案内容', order: 2, view: 'umeditor', type: 'string' },
};

/**
 * 流程表单调用这个方法获取formSchema
 * @param param
 */
export function getBpmFormSchema(_formData): FormSchema[] {
  // 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
  return formSchema;
}

SiTherapeuticscheduleModal.vue

<template>
  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
      <BasicForm @register="registerForm"/>
  </BasicModal>
</template>

<script lang="ts" setup>
    import {ref, computed, unref} from 'vue';
    import {BasicModal, useModalInner} from '/@/components/Modal';
    import {BasicForm, useForm} from '/@/components/Form/index';
    import {formSchema} from '../SiTherapeuticschedule.data';
    import {saveOrUpdate} from '../SiTherapeuticschedule.api';
    // Emits声明
    const emit = defineEmits(['register','success']);
    const isUpdate = ref(true);
    //表单配置
    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
        //labelWidth: 150,
        schemas: formSchema,
        showActionButtonGroup: false,
        baseColProps: {span: 24}
    });
    //表单赋值
    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
        //重置表单
        await resetFields();
        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
        isUpdate.value = !!data?.isUpdate;
        if (unref(isUpdate)) {
            //表单赋值
            await setFieldsValue({
                ...data.record,
            });
        }
        // 隐藏底部时禁用整个表单
       setProps({ disabled: !data?.showFooter })
    });
    //设置标题
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
    //表单提交事件
    async function handleSubmit(v) {
        try {
            let values = await validate();
            setModalProps({confirmLoading: true});
            //提交表单
            await saveOrUpdate(values, isUpdate.value);
            //关闭弹窗
            closeModal();
            //刷新列表
            emit('success');
        } finally {
            setModalProps({confirmLoading: false});
        }
    }
</script>

<style lang="less" scoped>
  /** 时间和数字输入框样式 */
  :deep(.ant-input-number){
   width: 100%
  }

  :deep(.ant-calendar-picker){
   width: 100%
  }
</style>

疗效数据SiCurativeeffect

SiCurativeeffectList.vue

<template>
  <div>
    <!--引用表格-->
    <BasicTable @register="registerTable" :rowSelection="rowSelection">
      <!--插槽:table标题-->
      <template #tableTitle>
        <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
        <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
        <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
        <a-dropdown v-if="selectedRowKeys.length > 0">
          <template #overlay>
            <a-menu>
              <a-menu-item key="1" @click="batchHandleDelete">
                <Icon icon="ant-design:delete-outlined"></Icon>
                删除
              </a-menu-item>
            </a-menu>
          </template>
          <a-button
            >批量操作
            <Icon icon="mdi:chevron-down"></Icon>
          </a-button>
        </a-dropdown>
        <!-- 高级查询 -->
        <!--        <super-query :config="superQueryConfig" @search="handleSuperQuery" />-->
      </template>
      <!--操作栏-->
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
      </template>
      <!--字段回显插槽-->
      <template v-slot:bodyCell="{ column, record, index, text }"> </template>
    </BasicTable>
    <!-- 表单区域 -->
    <SiCurativeeffectModal @register="registerModal" @success="handleSuccess"></SiCurativeeffectModal>
  </div>
</template>

<script lang="ts" name="siCurativeeffect-siCurativeeffect" setup>
  import { ref, reactive, computed, unref } from 'vue';
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage';
  import SiCurativeeffectModal from './components/SiCurativeeffectModal.vue';
  import { columns, searchFormSchema, superQuerySchema } from './SiCurativeeffect.data';
  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './SiCurativeeffect.api';
  import { downloadFile } from '/@/utils/common/renderUtils';
  import { useUserStore } from '/@/store/modules/user';
  const queryParam = reactive<any>({});
  const checkedKeys = ref<Array<string | number>>([]);
  const userStore = useUserStore();
  //注册model
  const [registerModal, { openModal }] = useModal();
  //注册table数据
  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
    tableProps: {
      title: '疗效数据表',
      api: list,
      columns,
      canResize: false,
      formConfig: {
        //labelWidth: 120,
        schemas: searchFormSchema,
        autoSubmitOnEnter: true,
        showAdvancedButton: true,
        fieldMapToNumber: [],
        fieldMapToTime: [],
      },
      actionColumn: {
        width: 120,
        fixed: 'right',
      },
      beforeFetch: (params) => {
        return Object.assign(params, queryParam);
      },
    },
    exportConfig: {
      name: '疗效数据表',
      url: getExportUrl,
      params: queryParam,
    },
    importConfig: {
      url: getImportUrl,
      success: handleSuccess,
    },
  });

  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;

  // 高级查询配置
  const superQueryConfig = reactive(superQuerySchema);

  /**
   * 高级查询事件
   */
  function handleSuperQuery(params) {
    Object.keys(params).map((k) => {
      queryParam[k] = params[k];
    });
    reload();
  }
  /**
   * 新增事件
   */
  function handleAdd() {
    openModal(true, {
      isUpdate: false,
      showFooter: true,
    });
  }
  /**
   * 编辑事件
   */
  function handleEdit(record: Recordable) {
    openModal(true, {
      record,
      isUpdate: true,
      showFooter: true,
    });
  }
  /**
   * 详情
   */
  function handleDetail(record: Recordable) {
    openModal(true, {
      record,
      isUpdate: true,
      showFooter: false,
    });
  }
  /**
   * 删除事件
   */
  async function handleDelete(record) {
    await deleteOne({ id: record.id }, handleSuccess);
  }
  /**
   * 批量删除事件
   */
  async function batchHandleDelete() {
    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
  }
  /**
   * 成功回调
   */
  function handleSuccess() {
    (selectedRowKeys.value = []) && reload();
  }
  /**
   * 操作栏
   */
  function getTableAction(record) {
    return [
      {
        label: '编辑',
        onClick: handleEdit.bind(null, record),
      },
    ];
  }
  /**
   * 下拉操作栏
   */
  function getDropDownAction(record) {
    return [
      {
        label: '详情',
        onClick: handleDetail.bind(null, record),
      },
      {
        label: '删除',
        popConfirm: {
          title: '是否确认删除',
          confirm: handleDelete.bind(null, record),
          placement: 'topLeft',
        },
      },
    ];
  }
</script>

<style scoped></style>

SiCurativeeffect.data.ts

import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { rules } from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
  {
    title: '病人',
    align: 'center',
    dataIndex: 'patientName',
  },
  {
    title: '症状评估依据',
    align: 'center',
    dataIndex: 'psymptomName',
  },
  {
    title: '颈椎',
    align: 'center',
    dataIndex: 'vertebrae',
  },
  {
    title: '双肩',
    align: 'center',
    dataIndex: 'bothShoulders',
  },
  {
    title: '圆肩含胸',
    align: 'center',
    dataIndex: 'roundShouldersChest',
  },
  {
    title: '驼背',
    align: 'center',
    dataIndex: 'hunchbacked',
  },
  {
    title: '平背',
    align: 'center',
    dataIndex: 'flatback',
  },
  {
    title: '翼状肩',
    align: 'center',
    dataIndex: 'wingedShoulder',
  },
  {
    title: '肋骨外翻',
    align: 'center',
    dataIndex: 'costalValgus',
  },
  {
    title: '双肘距离',
    align: 'center',
    dataIndex: 'elbowDistance',
  },
  {
    title: '脊柱侧弯',
    align: 'center',
    dataIndex: 'scoliosis',
  },
  {
    title: '骨盆',
    align: 'center',
    dataIndex: 'pelvic',
  },
  {
    title: '腿型',
    align: 'center',
    dataIndex: 'legtype',
  },
  {
    title: '足型',
    align: 'center',
    dataIndex: 'foottype',
  },
  {
    title: '长短腿',
    align: 'center',
    dataIndex: 'unevenleg',
  },
  {
    title: '足',
    align: 'center',
    dataIndex: 'foot',
  },
  {
    title: '膝',
    align: 'center',
    dataIndex: 'knee',
  },
  {
    title: '肩',
    align: 'center',
    dataIndex: 'shoulder',
  },
  {
    title: 'LPHC',
    align: 'center',
    dataIndex: 'lphc',
  },
  {
    title: '平均得分',
    align: 'center',
    dataIndex: 'avgvalue',
  },
  {
    title: '总得分',
    align: 'center',
    dataIndex: 'sumvalue',
  },
  {
    title: '备注',
    align: 'center',
    dataIndex: 'remarks',
  },
];
//查询数据
export const searchFormSchema: FormSchema[] = [
  {
    label: '病人',
    field: 'patientName',
    component: 'JPopup',
    componentProps: ({ formActionType }) => {
      const { setFieldsValue } = formActionType;
      return {
        setFieldsValue: setFieldsValue,
        code: 'si_patientsbaseinfo',
        fieldConfig: [
          { source: 'name', target: 'patientName' },
          { source: 'id', target: 'patient' },
        ],
        multi: true,
      };
    },
  },
  {
    label: '症状评估依据',
    field: 'psymptomName',
    component: 'Input',
  },
];
//表单数据
export const formSchema: FormSchema[] = [
  {
    label: '病人',
    field: 'patientName',
    component: 'Input',
  },
  {
    label: '症状评估依据',
    field: 'psymptom',
    component: 'JSearchSelect',
    componentProps: {
      dict: 'si_patientsymptom,name,id',
    },
  },
  {
    label: '颈椎',
    field: 'vertebrae',
    component: 'InputNumber',
  },
  {
    label: '双肩',
    field: 'bothShoulders',
    component: 'InputNumber',
  },
  {
    label: '圆肩含胸',
    field: 'roundShouldersChest',
    component: 'InputNumber',
  },
  {
    label: '驼背',
    field: 'hunchbacked',
    component: 'InputNumber',
  },
  {
    label: '平背',
    field: 'flatback',
    component: 'InputNumber',
  },
  {
    label: '翼状肩',
    field: 'wingedShoulder',
    component: 'InputNumber',
  },
  {
    label: '肋骨外翻',
    field: 'costalValgus',
    component: 'InputNumber',
  },
  {
    label: '双肘距离',
    field: 'elbowDistance',
    component: 'InputNumber',
  },
  {
    label: '脊柱侧弯',
    field: 'scoliosis',
    component: 'InputNumber',
  },
  {
    label: '骨盆',
    field: 'pelvic',
    component: 'InputNumber',
  },
  {
    label: '腿型',
    field: 'legtype',
    component: 'InputNumber',
  },
  {
    label: '足型',
    field: 'foottype',
    component: 'InputNumber',
  },
  {
    label: '长短腿',
    field: 'unevenleg',
    component: 'InputNumber',
  },
  {
    label: '足',
    field: 'foot',
    component: 'InputNumber',
  },
  {
    label: '膝',
    field: 'knee',
    component: 'InputNumber',
  },
  {
    label: '肩',
    field: 'shoulder',
    component: 'InputNumber',
  },
  {
    label: 'LPHC',
    field: 'lphc',
    component: 'InputNumber',
  },
  {
    label: '平均得分',
    field: 'avgvalue',
    component: 'InputNumber',
    dynamicDisabled: true,
  },
  {
    label: '总得分',
    field: 'sumvalue',
    component: 'InputNumber',
    dynamicDisabled: true,
  },
  {
    label: '备注',
    field: 'remarks',
    component: 'InputTextArea',
  },
  // TODO 主键隐藏字段,目前写死为ID
  {
    label: '',
    field: 'id',
    component: 'Input',
    show: false,
  },
];

// 高级查询数据
export const superQuerySchema = {
  psymptom: {
    title: '症状评估依据',
    order: 0,
    view: 'sel_search',
    type: 'string',
    dictTable: 'si_patientsymptom',
    dictCode: 'id',
    dictText: 'name',
  },
  vertebrae: { title: '颈椎', order: 1, view: 'number', type: 'number' },
  bothShoulders: { title: '双肩', order: 2, view: 'number', type: 'number' },
  roundShouldersChest: { title: '圆肩含胸', order: 3, view: 'number', type: 'number' },
  hunchbacked: { title: '驼背', order: 4, view: 'number', type: 'number' },
  flatback: { title: '平背', order: 5, view: 'number', type: 'number' },
  wingedShoulder: { title: '翼状肩', order: 6, view: 'number', type: 'number' },
  costalValgus: { title: '肋骨外翻', order: 7, view: 'number', type: 'number' },
  elbowDistance: { title: '双肘距离', order: 8, view: 'number', type: 'number' },
  scoliosis: { title: '脊柱侧弯', order: 9, view: 'number', type: 'number' },
  pelvic: { title: '骨盆', order: 10, view: 'number', type: 'number' },
  legtype: { title: '腿型', order: 11, view: 'number', type: 'number' },
  foottype: { title: '足型', order: 12, view: 'number', type: 'number' },
  unevenleg: { title: '长短腿', order: 13, view: 'number', type: 'number' },
  foot: { title: '足', order: 14, view: 'number', type: 'number' },
  knee: { title: '膝', order: 15, view: 'number', type: 'number' },
  shoulder: { title: '肩', order: 16, view: 'number', type: 'number' },
  lphc: { title: 'LPHC', order: 17, view: 'number', type: 'number' },
  avgvalue: { title: '平均得分', order: 18, view: 'number', type: 'number' },
  sumvalue: { title: '总得分', order: 19, view: 'number', type: 'number' },
  remarks: { title: '备注', order: 20, view: 'textarea', type: 'string' },
};

/**
 * 流程表单调用这个方法获取formSchema
 * @param param
 */
export function getBpmFormSchema(_formData): FormSchema[] {
  // 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
  return formSchema;
}

SiCurativeeffectModal.vue

<template>
  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="1024" @ok="handleSubmit">
      <BasicForm @register="registerForm"/>
  </BasicModal>
</template>

<script lang="ts" setup>
    import {ref, computed, unref} from 'vue';
    import {BasicModal, useModalInner} from '/@/components/Modal';
    import {BasicForm, useForm} from '/@/components/Form/index';
    import {formSchema} from '../SiCurativeeffect.data';
    import {saveOrUpdate} from '../SiCurativeeffect.api';
    // Emits声明
    const emit = defineEmits(['register','success']);
    const isUpdate = ref(true);
    //表单配置
    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
        //labelWidth: 150,
        schemas: formSchema,
        showActionButtonGroup: false,
        baseColProps: {span: 8}
    });
    //表单赋值
    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
        //重置表单
        await resetFields();
        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
        isUpdate.value = !!data?.isUpdate;
        if (unref(isUpdate)) {
            //表单赋值
            await setFieldsValue({
                ...data.record,
            });
        }
        // 隐藏底部时禁用整个表单
       setProps({ disabled: !data?.showFooter })
    });
    //设置标题
    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
    //表单提交事件
    async function handleSubmit(v) {
        try {
            let values = await validate();
            setModalProps({confirmLoading: true});
            //提交表单
            await saveOrUpdate(values, isUpdate.value);
            //关闭弹窗
            closeModal();
            //刷新列表
            emit('success');
        } finally {
            setModalProps({confirmLoading: false});
        }
    }
</script>

<style lang="less" scoped>
  /** 时间和数字输入框样式 */
  :deep(.ant-input-number){
   width: 100%
  }

  :deep(.ant-calendar-picker){
   width: 100%
  }
</style>

定义打开弹窗的按钮

需要在列表数据的操作栏后添加对应按钮

SiPatientsymptomList.vue中,找到操作栏getTableAction函数

/**
 * 操作栏
 */
function getTableAction(record) {
  return [
    {
      label: '编辑',
      onClick: handleEdit.bind(null, record),
    },
    {
      label: '新增方案',	// 一对多,页面弹窗
      onClick: addTherapeuticschedule.bind(null, record),
    },
    {
      label: '新增疗效',	// 一对一,组件弹窗
      onClick: addCurativeeffect.bind(null, record),
    },
  ];
}

再定义相关函数addTherapeuticscheduleaddCurativeeffect,目前只在控制台打印一下,不做其他操作

/**
 * 新增治疗方案
 */
function addTherapeuticschedule(record: Recordable) {
  console.log('新增治疗方案');
}

/**
 * 新增疗效数据
 */
function addCurativeeffect(record: Recordable) {
  console.log('新增疗效数据');
}

再适当调整一下操作栏的宽度,找到actionColumn,将width改为300

组件弹窗

先从简单的下手,疗效数据的新增功能只需要在病态评估页面中调用其原本的新增弹窗即可。

1. 导入注册组件弹窗

因为在SiCurativeeffectModal.vue中调用了新增修改接口,所以确定这是我们需要的组件弹窗

![image-20240419220628740](https://img-blog.csdnimg.cn/img_convert/在这里插入图片描述
.webp?x-oss-process=image/format,png)

然后可以在SiCurativeeffectList.vue中观察如何导入使用的(爆红是我编译器问题,提示没用到变量之类的)

在这里插入图片描述

可分为以下三步

  1. 导入该组件
  2. 注册弹窗Modal
  3. 引用并绑定

所以我们也可以照搬在病态评估页面中

在这里插入图片描述

也分为上面三步走,因为注册的组件不能重名,所以要修改第二步的注册信息,第三步的成功回调函数直接用原页面的即可,以下是修改后的代码

    ...
	<!-- 表单区域 -->
    <SiPatientsymptomModal @register="registerModal" @success="handleSuccess"></SiPatientsymptomModal>
    <SiCurativeeffectModal @register="registerCurativeeffectModal" @success="handleSuccess" />
  </div>
</template>

<script lang="ts" name="siPatientsymptom-siPatientsymptom" setup>
  import { ref, reactive, computed, unref } from 'vue';
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage';
  import SiPatientsymptomModal from './components/SiPatientsymptomModal.vue';
  import SiCurativeeffectModal from '@/views/gaitsys/siCurativeeffect/vue3/components/SiCurativeeffectModal.vue';
  import { columns, searchFormSchema, superQuerySchema } from './SiPatientsymptom.data';
  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './SiPatientsymptom.api';
  import { downloadFile } from '/@/utils/common/renderUtils';
  import { useUserStore } from '/@/store/modules/user';

  const queryParam = reactive<any>({});
  const checkedKeys = ref<Array<string | number>>([]);
  const userStore = useUserStore();
  //注册model
  const [registerModal, { openModal }] = useModal();
  const [registerCurativeeffectModal, { openModal: openCurativeeffectModal }] = useModal();
  ...

2. 调用并携带数据

回到SiPatientsymptomList.vue页面中,观察原页面中的新增编辑操作。新增是直接打开弹窗,但是并不会携带数据,后台是插入;编辑是打开弹窗并携带数据,后台是修改。我们需要的是携带数据并插入,所以要改变一下

image-20240419222753156image-20240419222801865

因为要携带数据,确保映射到弹窗的表单数据中

/**
 * 新增疗效数据
 */
function addCurativeeffect(record: Recordable) {
  console.log('新增疗效数据');
  record.psymptom = record.id;	// 映射数据
  openCurativeeffectModal(true, {
    record,
    isUpdate: false,
    showFooter: true,
  });
}

要确保数据能映射到弹窗,回到弹窗组件SiCurativeeffectModal.vue,找到useModalInner函数,将赋值setFieldsValue函数移动到if外,使其能接收到传入的数据

image-20240420141201601

const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  //重置表单
  await resetFields();
  setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
  isUpdate.value = !!data?.isUpdate;
  await setFieldsValue({
    ...data.record,
  });
  // 隐藏底部时禁用整个表单
  setProps({ disabled: !data?.showFooter });
});

需求上说只能在病态评估页面新增,所以要将疗效数据页面的新增按钮去掉,再将弹窗中传递来的病人名称与评估数据给禁用

修改疗效数据页面SiCurativeeffectList.vue,注释或删除新增按钮

image-20240419224430999

修改弹窗SiCurativeeffect.data.ts数据显示,添加disabled字段

//表单数据
export const formSchema: FormSchema[] = [
  {
    label: '病人',
    field: 'patientName',
    component: 'Input',
    componentProps: {
      disabled: true,
    },
  },
  {
    label: '症状评估依据',
    field: 'psymptom',
    component: 'JSearchSelect',
    componentProps: {
      dict: 'si_patientsymptom,name,id',
      disabled: true,
    },
  },
  ...
]

到这一步,组件弹窗应该就可以使用了

页面弹窗

先分析一下,我们需要在病态评估页面中打开治疗方案页面,还需要携带病态评估单行的数据(即弹窗只能展示出该病人的系列治疗方案),然后在打开新增弹窗时,还要显示出携带来的病人名称与评估数据

可以分为三步

  1. 先将治疗方案页面做成一个弹窗
  2. 再将数据携带传到该弹窗,即初始化时,携带查询参数
  3. 新增时携带数据(和前面的组件弹窗类似)

参考链接

jeecg-boot:将单表列表页作为弹框,并且传递参数到解决方案(场景商品到明细信息维护)_jeecg打开弹窗传参-CSDN博客

BasicModal弹窗 (jeecg.com)

1. 将页面改为弹窗

复制SiTherapeuticscheduleList.vue到同级的components目录下,重命名为SiTherapeuticscheduleListModal.vue

把页面的div标签改为弹窗BasicModal

image-20240420130333550

image-20240420130516481

<BasicModal v-bind="$attrs" @register="registerListModal" destroyOnClose :title="title" :width="1200" @ok="closeModal">
    ...
</BasicModal>

这时候会爆红,一是没导入弹窗组件,二是有些变量没创建

先导入

import { BasicModal, useModalInner } from '/@/components/Modal';

再注册,这个页面弹窗只需要展示,不需要其他操作,所以@ok绑定的事件就直接用closeModaldestroyOnClose看字面意思就是关闭时销毁

//注册model
const [registerListModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  setModalProps({
    confirmLoading: false,
    showCancelBtn: !!data?.showFooter,
    showOkBtn: !!data?.showFooter,
  });
});
//设置标题
const title = '管理治疗方案';

2. 传参

先在SiPatientsymptomList.vue导入该页面弹窗,和上面组件弹窗步骤一样(先导入,再注册,最后引用)

image-20240420131938372

// 1.导入组件
import SiTherapeuticscheduleListModal from '@/views/gaitsys/siTherapeuticschedule/vue3/components/SiTherapeuticscheduleListModal.vue';
  import SiCurativeeffectModal from '@/views/gaitsys/siCurativeeffect/vue3/components/SiCurativeeffectModal.vue';

// 2.注册model
const [registerTherapeuticscheduleListModal, { openModal: openTherapeuticscheduleListModal }] = useModal();

// 3.引用组件
<SiTherapeuticscheduleListModal @register="registerTherapeuticscheduleListModal" @success="handleSuccess" />

然后就是打开弹窗的函数,这里传了一个record数据过去

/**
 * 新增治疗方案
 */
function addTherapeuticschedule(record: Recordable) {
  console.log('新增治疗方案');
  record.psymptom = record.id;	// 映射数据
  openTherapeuticscheduleListModal(true, {
    record,
    isUpdate: false,
    showFooter: false,
  });
}

相应的,页面弹窗组件也要接收该数据

在注册页面弹窗的时候,调用了useModalInner函数,异步传来了data数据,就用这个获取到传入的参数

let record = reactive<any>({});

//注册model
const [registerListModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  record = data.record;
  setModalProps({
    confirmLoading: false,
    showCancelBtn: !!data?.showFooter,
    showOkBtn: !!data?.showFooter,
  });
});

最后就是打开该弹窗时,只查询传入病人的信息

找到useListPage表单注册函数,里面的beforeFetch就是查询时的函数

image-20240420133018106

可以在查询时添加对应的参数,即可达成需求(需调整对应后端接口)

beforeFetch: (params) => {
  params.patientName = record.patientName;
  params.psymptomName = record.psymptomName;
  return Object.assign(params, queryParam);
},

3. 携带参数打开弹窗

因为上面创建了个全局的变量record,所以在调用新增函数handleAdd的时候传入即可

/**
 * 新增事件
 */
function handleAdd() {
  openModal(true, {
    record,
    isUpdate: false,
    showFooter: true,
  });
}

确保能在新增弹窗赋值成功,需要修改SiPatientsymptomModal.vueuseModalInner和上面组件弹窗一样

const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  //重置表单
  await resetFields();
  setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
  isUpdate.value = !!data?.isUpdate;
  await setFieldsValue({
    ...data.record,
  });
  // 隐藏底部时禁用整个表单
  setProps({ disabled: !data?.showFooter });
});

然后添加表单弹窗的字段禁用,修改SiTherapeuticschedule.data.ts的表单数据formSchema,添加disabled字段

//表单数据
export const formSchema: FormSchema[] = [
  {
    label: '病人',
    field: 'patientName',
    component: 'Input',
    componentProps: {
      disabled: true,
    },
  },
  {
    label: '评估症状',
    field: 'psymptom',
    component: 'JSearchSelect',
    componentProps: {
      dict: 'si_patientsymptom,name,id',
      disabled: true,
    },
    dynamicRules: ({ model, schema }) => {
      return [{ required: true, message: '请输入评估症状!' }];
    },
  },
  ...
];

到这一步,页面弹窗应该就可以使用了

  • 24
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JeecgBoot是一个基于SpringBoot的快速开发平台,它提供了许多常用的功能例如代码生成、权限管理、数据字典、日志管理等等。而Vue2是一种流行的JavaScript框架,它可以用来构建现代化的Web应用程序。在JeecgBoot中使用Vue2可以帮助我们更快速地开发现代化的Web应用程序。 下面是使用JeecgBoot和Vue2开发Web应用程序的基本步骤: 1. 创建一个JeecgBoot项目,可以使用JeecgBoot的代码生成器来创建一个基础的项目。 2. 在JeecgBoot项目中集成Vue2,可以使用npm包管理器来安装Vue2。在项目的根目录下执行以下命令: ``` npm install vue ``` 3. 创建Vue2组件,可以在JeecgBoot项目的前端资源目录下创建一个新的Vue2组件。例如,在src/main/resources/webapp/vue/components目录下创建一个名为HelloWorld.vue的文件,内容如下: ``` <template> <div> <h1>Hello {{ name }}!</h1> </div> </template> <script> export default { data() { return { name: 'World' } } } </script> ``` 4. 在JeecgBoot项目中使用Vue2组件,可以在JeecgBoot的JSP页面中使用Vue2组件。例如,在src/main/resources/templates目录下创建一个名为index.jsp的文件,内容如下: ``` <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JeecgBoot Vue2 Demo</title> <script src="/static/js/vue.min.js"></script> </head> <body> <div id="app"> <hello-world></hello-world> </div> <script src="/static/js/app.js"></script> </body> </html> ``` 注意,在页面中引入Vue2的JavaScript文件,以及Vue2组件JavaScript文件。 5. 编译Vue2组件,可以使用Webpack来编译Vue2组件。在项目的根目录下执行以下命令: ``` npm install webpack webpack-cli vue-loader vue-template-compiler css-loader style-loader --save-dev ``` 然后在项目的根目录下创建一个名为webpack.config.js的文件,内容如下: ``` const path = require('path'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { mode: 'development', entry: './src/main/resources/webapp/vue/index.js', output: { path: path.resolve(__dirname, 'src/main/resources/static/js'), filename: 'app.js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, plugins: [ new VueLoaderPlugin() ] }; ``` 然后在项目的src/main/resources/webapp/vue目录下创建一个名为index.js的文件,内容如下: ``` import Vue from 'vue'; import HelloWorld from './components/HelloWorld.vue'; new Vue({ el: '#app', components: { 'hello-world': HelloWorld } }); ``` 6. 编译Vue2组件,可以在项目的根目录下执行以下命令: ``` ./node_modules/.bin/webpack --config webpack.config.js ``` 这将会编译Vue2组件,并将编译结果输出到src/main/resources/static/js目录下。 7. 运行JeecgBoot应用程序,可以使用以下命令来启动JeecgBoot应用程序: ``` mvn spring-boot:run ``` 访问http://localhost:8080即可看到Vue2组件JeecgBoot应用程序中的效果。 这就是使用JeecgBoot和Vue2开发Web应用程序的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值