Ben Lin
2024-07-22 c24509087b1193c18ee4c87487b0fc4bf8ee0918
src/views/tigerprojects/system/lowcode/high/index.vue
@@ -1,4 +1,12 @@
<!--
 * @Description: 低代码高级呈现页面
 * @Author: Ben Lin
 * @version:
 * @Date: 2024-06-18 15:09:48
 * @LastEditors: Ben Lin
 * @LastEditTime: 2024-07-22 16:02:35
-->
<!--
 *                        _oo0oo_
 *                       o8888888o
 *                       88" . "88
@@ -33,38 +41,28 @@
 *                别人笑我忒疯癫,我笑自己命太贱;  
 *                不见满街漂亮妹,哪个归得程序员?
 -->
<!--
 * @Description: 低代码高级呈现页面
 * @Author: Ben Lin
 * @version:
 * @Date: 2024-05-30 13:28:20
 * @LastEditors: Ben Lin
 * @LastEditTime: 2024-06-14 09:19:23
-->
<template>
  <PageWrapper class="high-form" :title="title" :content="contentStr" @back="goBack">
    <a-card :title="item.title" :bordered="false" v-for="(item, index) in baseCards" :key="item.name">
      <BasicForm @register="useFormData[item.name][0]" />
    </a-card>
    <a-card title="明细" :bordered="false" class="!mt-5">
      <div>
        <BasicTable @register="registerTable">
          <template #toolbar>
            <a-button type="primary" @click="handleCreate" preIcon="add_02|svg"> 新增 </a-button>
          </template>
          <template #action="{ record }">
            <TableAction :actions="createActions(record)" />
          </template>
          <template #[item]="{ field }" v-for="item in colSlots" :key="item">
            <!-- <template #form-BAS_REASON3aadd="{ field }"> -->
            <a-button v-if="field" class="mt-1 ml-1" size="small" @click="handleSelectItem(item)"
              preIcon="search|svg" />
            <NormalModal @register="registerItemAdd" @success="(d, u) => handleItemSuccess(d, u, item)" />
          </template>
        </BasicTable>
      </div>
    </a-card>
    <a-card :title="item.title" :bordered="false" class="!m-5" v-for="(item, index) in otherCards" :key="item.name">
  <PageWrapper
    class="high-form"
    :title="titleInfo['pageTitle']"
    :content="titleInfo['pageContent']"
    @back="goBack"
  >
    <Suspense>
      <baseForm :entityName="entityName" />
    </Suspense>
    <!-- <a-card :title="titleInfo['baseTableTitle']" :bordered="false" class="!mt-5"> -->
    <Suspense>
      <dtl :entityName="entityName" @search="dtlFormSearch" />
    </Suspense>
    <!-- </a-card> -->
    <a-card
      :title="item.title"
      :bordered="false"
      class="!m-5"
      v-for="(item, index) in otherCards"
      :key="item.name"
    >
      <BasicForm @register="useFormData[item.name][0]" />
    </a-card>
@@ -72,262 +70,287 @@
      <a-button class="mr-4" type="info" @click="cancel"> 取消 </a-button>
      <a-button type="primary" @click="submitAll"> 提交 </a-button>
    </template>
    <normalDrawer @register="registerDrawer" @success="handleSuccess" />
    <CustModal @register="registerCust" @success="custSuccess" :type="cType" :detailSlots="dtlSlots">
      <!-- 用插槽自定义多表单 -->
      <template #[item.name] v-for="item in dtlSlots" :key="item.name">
        <BasicForm @register="useFormData[item.name][0]" v-if="useFormData[item.name]">
          <!-- 用插槽自定义弹出选择框 -->
          <template #[name]="{ field }" v-for="name in item.slots" :key="name">
            <a-button class="mt-1 ml-1" size="small" @click="handleCustClick(field)" :preIcon="item.preIcons[name]" />
            <NormalModal @register="useModalData[name][0]" @success="(d, u) => handleEntSuccess(d, u, item.name)" />
          </template>
        </BasicForm>
        <!-- 自定义内容 -->
      </template>
    </CustModal>
    <Suspense>
      <CustModal
        @register="registerCust"
        @success="custSuccess"
        :type="cType"
        :detailSlots="dtlSlots"
        :entityName="entityName"
      >
        <!-- 用插槽自定义多表单 -->
        <template #[item.name] v-for="item in dtlSlots" :key="item.name">
          <BasicForm @register="useFormData[item.name][0]" v-if="useFormData[item.name]">
            <!-- 用插槽自定义弹出选择框 -->
            <template #[name]="{ field }" v-for="name in item.slots" :key="name">
              <a-button
                class="mt-1 ml-1"
                size="small"
                @click="handleCustClick(field)"
                :preIcon="item.preIcons[name]"
              />
              <GeneralModal
                @register="useModalData[name][0]"
                @success="(d, u) => handleEntSuccess(d, u, item.name)"
              />
            </template>
          </BasicForm>
          <!-- 自定义内容 -->
        </template>
      </CustModal>
    </Suspense>
  </PageWrapper>
</template>
<script lang="ts" setup>
import { h, onMounted, ref, unref } from 'vue';
import { Tag, Tooltip, Card } from 'ant-design-vue';
import { BasicTable, useTable, TableAction, BasicColumn, FormSchema } from '/@/components/Table';
import { useDrawer } from '/@/components/Drawer';
import { PageWrapper } from '/@/components/Page';
import normalDrawer from '../normalDrawer.vue';
import NormalModal from '/@/views/components/NormalModal.vue';
import { GetEnum, getEntity, getListByPage } from '/@/api/tigerapi/system';
import { useGlobSetting } from '/@/hooks/setting';
import { useRoute, useRouter } from 'vue-router';
import CustModal from '/@/views/components/CustModal.vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import {
  GetActionColumn,
  GetActionsData,
  OpenSelectItem,
  GetSelectSuccess,
  custOnChange,
  getFormSchema,
  OpenCustModal,
  GetUseModalData,
  GetBasicColumnAndInit,
} from '../data';
import { useModal } from '/@/components/Modal';
import { useLocale } from '/@/locales/useLocale';
import { useGo } from '/@/hooks/web/usePage';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { useTabs } from '/@/hooks/web/useTabs';
import { isNullOrEmpty } from '/@/utils/is';
  import { Ref, h, nextTick, onMounted, provide, reactive, ref, unref } from 'vue';
  import { Card } from 'ant-design-vue';
  import { PageWrapper } from '/@/components/Page';
  import dtl from './dtl.vue';
  import baseForm from './baseForm.vue';
  import GeneralModal from '/@/views/components/GeneralModal.vue';
  import { AddAfterDelete, SaveEntity } from '/@/api/tigerapi/system';
  import { useGlobSetting } from '/@/hooks/setting';
  import { useRoute, useRouter } from 'vue-router';
  import CustModal from '/@/views/components/CustModal.vue';
  import { BasicForm, useForm } from '/@/components/Form/index';
  import { custOnChange, OpenCustModal } from '../data';
  import { useModal } from '/@/components/Modal';
  import { useLocale } from '/@/locales/useLocale';
  import { useGo } from '/@/hooks/web/usePage';
  import { useMultipleTabStore } from '/@/store/modules/multipleTab';
  import { useTabs } from '/@/hooks/web/useTabs';
  import { buildUUID } from '/@/utils/uuid';
  import { isNullOrEmpty, isNullOrUnDef } from '/@/utils/is';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { isFunction } from 'xe-utils';
const ACard = Card;
const { getLocale } = useLocale();
const route = useRoute();
const go = useGo();
const tabStore = useMultipleTabStore();
const router = useRouter();
const { currentRoute } = router;
function getCurrentTab() {
  const route = unref(currentRoute);
  return tabStore.getTabList.find((item) => item.fullPath === route.fullPath)!;
}
const currentTab = getCurrentTab();
const objParams = ref(JSON.parse(decodeURI(route.params?.id as string)));
const entityName = ref(objParams.value.Name);
const title = ref(objParams.value.pageTitle);
const contentStr = ref(objParams.value.pageContent);
const globSetting = useGlobSetting();
const _crudFormSchema = ref([]);
const formSchemas = ref({}); //弹出框或高级页面多表单结构
const useModalData = ref({}); //表单中插槽渲染按钮打开模态框useModal方法
const useFormData = ref({});
const colSlots = ref<any>(objParams.value.colSlots); //按钮插槽
const crudColSlots = ref<any>(objParams.value.crudColSlots);
const cType = ref('');
const dtlSlots = ref([] as any[]);
const selectVals = ref({});
const baseCards = ref([] as any[]);
const otherCards = ref([] as any[]);
//获取表格列信息并初始化一些数据,如:formSchemas(弹出框或高级页面多表单结构), useFormData(表单中插槽渲染按钮打开模态框useModal方法)...等
const _columns = GetBasicColumnAndInit(entityName.value, formSchemas, useFormData, baseCards, otherCards, useForm);
const data = ref([]);
  const { t } = useI18n();
const [registerCust, { openModal: openCustomModal, closeModal }] = useModal();
const [registerItemAdd, { openModal: openItemModal }] = useModal();
const [registerDrawer, { openDrawer }] = useDrawer();
const { setTitle } = useTabs();
const [registerTable, { getForm, reload, setProps }] = useTable({
  title: '列表信息',
  // api: getListByPage,
  // searchInfo: { TABLE_NAME: entityName.value },
  dataSource: data.value,
  columns: _columns,
  formConfig: {
    labelWidth: 140,
    schemas: getFormSchema(entityName.value),
  },
  useSearchForm: true,
  showTableSetting: true,
  bordered: true,
  canResize: true,
  showIndexColumn: false,
  actionColumn: GetActionColumn(entityName.value), //自定义操作列
});
setTitle(objParams.value.Title); //设置标签页标题
/**
 * @description: 生成列表中操作项的按钮
 * @param {*} record
 * @return {*}
 */
function createActions(record) {
  return GetActionsData(
    {
      record,
      isUpdate: true,
      entityName: entityName.value,
      formJson: _crudFormSchema.value,
      cType,
      dtlSlots,
      useModalData,
      useFormData,
      crudColSlots,
    },
    openDrawer,
    reload,
    openCustomModal,
    useForm,
    useModal,
    go,
  );
}
function handleCreate() {
  openDrawer(true, {
    isUpdate: false,
    entityName: entityName.value,
    formJson: _crudFormSchema.value,
    crudColSlots,
  });
}
function handleSuccess() {
  reload();
}
function goBack() {
  // 本例的效果时点击返回始终跳转到账号列表页,实际应用时可返回上一页
  const param = { ID: entityName.value, colSlots: [], crudColSlots: [] };
  go(`/BAS_DEFECT_GRP/LC/${encodeURI(JSON.stringify(param))}`);
}
onMounted(() => {
  useFormData.value[baseCards.value[0]['name']][1].resetFields();
  getEntity({ sqlcmd: ` ID = '${objParams.value.ID}'`, entityName: entityName.value }).then((res) => {
    if (!isNullOrEmpty(res.Data.Items)) {
      useFormData.value[baseCards.value[0]['name']][1].setFieldsValue(res.Data.Items[0]);
    }
  });
});
async function submitAll() {
  try {
    // const [values, testValues] = await Promise.all([validate(), validateTestForm()]);
    // values.ID = params.RULE_ID;
    // const action = await SaveRule({ ...values, ...testValues });
    // if (action.IsSuccessed) {
    //   await DeleteRuleDtl(params.RULE_ID);
    //   const dtlAction = await SaveRuleDtl(data.value);
    //   if (dtlAction.IsSuccessed) {
    //     cancel();
    //   }
    // }
  } catch (error) { }
}
async function cancel() {
  try {
    tabStore.closeTab(currentTab, router);
  } catch (error) { }
}
/**
 * @description: 弹出选择框选择成功后事件
 * @param {*} d
 * @param {*} u
 * @param {*} item
 * @return {*}
 */
function handleItemSuccess(d, u, item) {
  getForm().setFieldsValue(GetSelectSuccess(d, u, getForm().getFieldsValue()[`${item.replace(/form-/, '').replace(/add/, '')}PSelect_0`]));
}
/**
 * @description: 弹出选择框
 * @param {*} item
 * @return {*}
 */
function handleSelectItem(item) {
  OpenSelectItem(openItemModal, getForm().getFieldsValue()[`${item.replace(/form-/, '').replace(/add/, '')}PSelect_0`]);
}
/**
 * @description: Select 自定义onChange方法
 * @param {*} obj
 * @return {*}
 */
function onChangeConfig(obj: any) {
  if (obj.component == 'Select') {
    var options = obj.componentProps.options;
    var onChange = obj.componentProps.onChange;
    obj.componentProps = ({ schema, tableAction, formActionType, formModel }) => {
      return {
        options: options,
        onChange: (e) => custOnChange(e, onChange, entityName.value),
      };
    };
  const ACard = Card;
  const { getLocale } = useLocale();
  const go = useGo();
  const route = useRoute();
  const tabStore = useMultipleTabStore();
  const router = useRouter();
  const { currentRoute } = router;
  function getCurrentTab() {
    const route = unref(currentRoute);
    return tabStore.getTabList.find((item) => item.fullPath === route.fullPath)!;
  }
}
  const currentTab = getCurrentTab();
  const routeParams = ref(JSON.parse(decodeURI(route.params?.id as string)));
  // 从sessionStorage中读取参数并转换回对象
  const savedParams = sessionStorage.getItem(`${routeParams.value.sName}_params`);
  const objParams = savedParams ? ref(JSON.parse(decodeURI(savedParams))) : ref({});
  const entityName = ref(routeParams.value.Name);
  const titleInfo = ref({}); //getTitle(objParams.value.Name);
  const isAllUpdate = ref(objParams.value.CODE != '0');
  const globSetting = useGlobSetting();
  const formSchemas = ref({}); //弹出框或高级页面多表单结构
  const useModalData = ref({}); //表单中插槽渲染按钮打开模态框useModal方法
  const useFormData = ref({});
  const useTableData = ref({});
  const cType = ref('');
  const dtlSlots = ref([] as any[]);
  const selectVals = ref({});
  const baseCards = ref([] as any[]);
  const otherCards = ref([] as any[]);
  const isMounted = ref(false);
  const custImport = ref<any[]>([]);
  const keyFieldValues = ref<any>(null);
  const data = ref<any>({});
  const useTables = ref<any>({});
  for (const i in objParams.value['drawers']) {
    data.value[objParams.value['drawers'][i]['name']] = ref<Recordable[]>([]);
  }
  provide<Ref<any>>('objParams', objParams);
  provide<Ref<any>>('data', data);
  provide<Ref<any>>('keyFieldValues', keyFieldValues);
  provide<Ref<{}>>('useFormData', useFormData);
  provide<Ref<any>>('baseCards', baseCards);
  provide<Ref<any>>('useTables', useTables);
/**
 * @description: 弹出框确定返回
 * @param {*} d
 * @return {*}
 */
function custSuccess(d) {
  reload();
}
  const [registerCust, { openModal: openCustomModal, closeModal }] = useModal();
  const { setTitle } = useTabs();
  setTitle(objParams.value.Title); //设置标签页标题
/**
 * @description: 各表单内弹出选择框选择成功后方法
 * @param {*} d
 * @param {*} u
 * @param {*} item
 * @return {*}
 */
function handleEntSuccess(d, u, item) {
  var values = GetSelectSuccess(d, u, cType.value);
  selectVals.value = values; //保存弹出框选择的结果
  let _val = {};
  _val[d.returnFieldName] = values[d.returnFieldName];
  useFormData.value[item][1].setFieldsValue(_val);
}
  function goBack() {
    if (!isNullOrUnDef(custImport.value)) {
      const [{ GetHomeUrl }] = custImport.value['default']();
      // 本例的效果时点击返回始终跳转到账号列表页,实际应用时可返回上一页
      go(GetHomeUrl(entityName.value));
    }
  }
/**
 * @description: 打开自定义模态框
 * @param {*} item
 * @return {*}
 */
function handleCustClick(item) {
  OpenCustModal(
    useModalData.value[item][1].openModal, //带入openModal方法
    cType.value,
    item,
    [],
    // selectVals.value['ROUTE_CODE'],
  ); //[openRvModal], selectVals.value['ID']这是自定义参数,按实际需求
}
  onMounted(async () => {
    isMounted.value = false;
    await nextTick();
    /* 动态import实体名.ts的自定义方法 */
    try {
      custImport.value = await import(`../entityts/${entityName.value}.ts`);
      const [{ GetTitle }] = custImport.value['default']();
      titleInfo.value = GetTitle();
    } catch (e) {}
    isMounted.value = true;
  });
  /**
   * @description: 异步全部提交方法
   * @return {*}
   */
  async function submitAll() {
    try {
      const validates = await validate();
      const Keys = Object.getOwnPropertyNames(useFormData.value);
      let i;
      let p = [] as Promise<any>[];
      for (i = 0; i < Keys.length; i++) {
        p.push(
          SaveEntity(
            validates[Keys[i]],
            unref(isAllUpdate),
            baseCards.value[i]['entityName'],
            `${objParams.value['IsExist']}='${validates[Keys[i]][objParams.value['IsExist']]}'`,
            true,
          ),
        );
      }
      await Promise.all(p);
      if (
        !custImport.value['default']()[0].SubmitAll &&
        !isFunction(custImport.value['default']()[0].SubmitAll)
      ) {
        /* 默认提交 */
        objParams.value['drawers'].forEach((d) => {
          let where = `${d['code']} = '${keyFieldValues.value[d['code']]}'`;
          /* type: all-表示需要code的所有的值 */
          if (d['type'] == 'all' && data.value[d['keyName']].length > 0) {
            where = `${d['code']} in (${data.value[d['keyName']].map((value) => `'${value[d['code']]}'`).join(',')})`;
          }
          /* 如果高级表单中关联的是ID(IsID == true),则不用初始化ID */
          if (!objParams.value['IsID']) {
            data.value[d['name']].map((item) => {
              item.ID = buildUUID();
            });
          }
          AddAfterDelete(d['name'], data.value[d['name']], where).then((action) => {
            if (action.IsSuccessed) {
              cancel();
            }
          });
        });
      } else {
        /* 如果自定义提交方法存在就用自定义提交 */
        custImport.value['default']()[0].SubmitAll(data, keyFieldValues, cancel);
      }
    } catch (error) {}
  }
  async function cancel() {
    try {
      tabStore.closeTab(currentTab, router);
    } catch (error) {}
  }
  /**
   * @description: 验证表单
   * @return {*}
   */
  async function validate() {
    let validates = {};
    const Keys = Object.getOwnPropertyNames(useFormData.value);
    let i;
    for (i = 0; i < Keys.length; i++) {
      validates[Keys[i]] = await useFormData.value[Keys[i]][1].validate();
    }
    return validates;
  }
  /**
   * @description: 表格查询回调,根据对应子组件中表格的查询按钮提交事件转入动态调用的实体名方法去执行对应的查询逻辑,返回后刷新数据
   * @param {*} d
   * @return {*}
   */
  function dtlFormSearch(d) {
    try {
      var values = useTables.value[d.type][1].getForm().getFieldsValue();
      let data = custImport.value['default']()[0].FormSearch({ ...d, ...{ values: values } });
      useTables.value[d.type][1].setProps({
        dataSource: [],
      });
      useTables.value[d.type][1].setProps({
        dataSource: data,
      });
      useTables.value[d.type][1].reload();
    } catch (e) {}
  }
  /**
   * @description: Select 自定义onChange方法
   * @param {*} obj
   * @return {*}
   */
  function onChangeConfig(obj: any) {
    if (obj.component == 'Select') {
      var options = obj.componentProps.options;
      var onChange = obj.componentProps.onChange;
      obj.componentProps = ({ schema, tableAction, formActionType, formModel }) => {
        return {
          options: options,
          onChange: (e) => custOnChange(e, onChange, entityName.value),
        };
      };
    }
  }
  /**
   * @description: 弹出框确定返回
   * @param {*} d
   * @return {*}
   */
  function custSuccess(d) {
    useTableData.value['table'][1].reload();
  }
  /**
   * @description: 各表单内弹出选择框选择成功后方法
   * @param {*} d
   * @param {*} u
   * @param {*} item
   * @return {*}
   */
  function handleEntSuccess(d, u, item) {
    /* 动态import实体名.ts的自定义方法 */
    try {
      import(`../entityts/${cType.value}.ts`).then((m) => {
        const [{ GetSelectSuccess }] = m.default();
        var values = GetSelectSuccess(d, u);
        selectVals.value = values; //保存弹出框选择的结果
        let _val = {};
        d.returnFieldName.map((x) => {
          _val[x] = values[x];
        });
        useFormData.value[item][1].setFieldsValue(_val);
      });
    } catch (e) {}
  }
  /**
   * @description: 打开自定义模态框
   * @param {*} item
   * @return {*}
   */
  function handleCustClick(item) {
    OpenCustModal(
      useModalData.value[item][1].openModal, //带入openModal方法
      cType.value,
      item,
      [],
      // selectVals.value['ROUTE_CODE'],
    ); //[openRvModal], selectVals.value['ID']这是自定义参数,按实际需求
  }
</script>
<style lang="less" scoped>
.high-form {
  padding-bottom: 48px;
}
  .high-form {
    padding-bottom: 48px;
  }
</style>