Pārlūkot izejas kodu

feat: 修改框架

DESKTOP-USV654P\pc 6 mēneši atpakaļ
vecāks
revīzija
657ce360b1

+ 1 - 0
apps/web-baicai/src/api/index.ts

@@ -1,3 +1,4 @@
 export * from './core';
 export * from './examples';
+export * from './plugins';
 export * from './system';

+ 34 - 0
apps/web-baicai/src/api/plugins/config.ts

@@ -0,0 +1,34 @@
+import { requestClient } from '#/api/request';
+
+export namespace PluginsConfigApi {
+  export interface SmsConfig {
+    testCode: string;
+    provider?: number;
+    sdkAppId?: number;
+    accessKeyId?: string;
+    accessKeySecret?: string;
+  }
+  export interface EmailConfig {
+    host: string;
+    port: number;
+    emailFrom: string;
+    enableSsl: boolean;
+    useDefaultCredentials: boolean;
+    userName: string;
+    password: string;
+    useError: boolean;
+    emailTo?: string;
+  }
+
+  export const getSmsDetail = () =>
+    requestClient.get<SmsConfig>('/plugins/config/sms/entity');
+
+  export const editSmsDetail = (data: SmsConfig) =>
+    requestClient.post('/plugins/config/sms', data);
+
+  export const getEmailDetail = () =>
+    requestClient.get<SmsConfig>('/plugins/config/email/entity');
+
+  export const editEmailDetail = (data: SmsConfig) =>
+    requestClient.post('/plugins/config/email', data);
+}

+ 2 - 0
apps/web-baicai/src/api/plugins/index.ts

@@ -0,0 +1,2 @@
+export * from './config';
+export * from './template';

+ 44 - 0
apps/web-baicai/src/api/plugins/template.ts

@@ -0,0 +1,44 @@
+import type { BasicFetchResult, BasicPageParams } from '#/api/model';
+
+import { requestClient } from '#/api/request';
+
+export namespace PluginsTemplateApi {
+  export interface PageParams extends BasicPageParams {
+    pluginsType?: number;
+    name?: string;
+    code?: string;
+    signName?: string;
+    templateCode?: string;
+  }
+
+  export interface BasicRecordItem {
+    pluginsType?: number;
+    name?: string;
+    code?: string;
+    signName?: string;
+    templateCode?: string;
+  }
+
+  export interface RecordItem extends BasicRecordItem {
+    id: number;
+  }
+
+  export type PageResult = BasicFetchResult<RecordItem>;
+
+  export const getPage = (params: PageParams) =>
+    requestClient.get<PageResult>('/plugins/template/page', { params });
+
+  export const getDetail = (id: number) =>
+    requestClient.get<RecordItem>('/plugins/template/entity', {
+      params: { id },
+    });
+
+  export const addDetail = (data: BasicRecordItem) =>
+    requestClient.post('/plugins/template', data);
+
+  export const editDetail = (data: RecordItem) =>
+    requestClient.put('/plugins/template', data);
+
+  export const deleteDetail = (id: number) =>
+    requestClient.delete('/plugins/template', { data: { id } });
+}

+ 2 - 0
apps/web-baicai/src/api/system/enum.ts

@@ -7,6 +7,8 @@ export namespace EnumApi {
     Gender = 'Gender',
     MenuType = 'MenuType',
     PathType = 'PathType',
+    PluginsType = 'PluginsType',
+    Provider = 'Provider',
     QueryType = 'QueryType',
     Status = 'Status',
     TenantType = 'TenantType',

+ 6 - 11
apps/web-baicai/src/components/form/component-map.ts

@@ -6,24 +6,19 @@ import { getFileNameWithoutExtension, toPascalCase } from '#/utils';
 
 const componentMap = new Map<CustomComponentType | string, Component>();
 // import.meta.glob() 直接引入所有的模块 Vite 独有的功能
-const modules = import.meta.glob('./components/**/*.vue', { eager: true });
+const modules = import.meta.glob(
+  ['./components/**/*.vue', '../../views/**/components/form/*.vue'],
+  { eager: true },
+);
 // 加入到路由集合中
 Object.keys(modules).forEach((key) => {
   if (!key.includes('-ignore')) {
-    const mod = (modules as any)[key].default || {};
+    const component = (modules as any)[key].default || {};
     const compName = getFileNameWithoutExtension(key);
-    componentMap.set(toPascalCase(compName), mod);
+    componentMap.set(toPascalCase(compName), component);
   }
 });
 
-export function add(compName: string, component: Component) {
-  componentMap.set(compName, component);
-}
-
-export function del(compName: string) {
-  componentMap.delete(compName);
-}
-
 /**
  * 注册组件
  * @param components

+ 2 - 1
apps/web-baicai/src/components/form/helper.ts

@@ -5,7 +5,8 @@ import { requestClient } from '#/api/request';
 
 export const createApiFunction = (apiConfig: ApiConfig) => {
   const api: any =
-    typeof apiConfig.url === 'string' && !apiConfig.url
+    apiConfig.url === undefined ||
+    (typeof apiConfig.url === 'string' && !apiConfig.url)
       ? (params: any) => {
           switch (apiConfig.type) {
             case 'api': {

+ 203 - 0
apps/web-baicai/src/views/plugins/config/data.config.ts

@@ -0,0 +1,203 @@
+import type { VbenFormSchema } from '@vben/common-ui';
+
+import { h } from 'vue';
+
+import { EnumApi } from '#/api';
+
+export const useSmsSchema = (): VbenFormSchema[] => {
+  return [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '请输入短信测试',
+      },
+      fieldName: 'testCode',
+      label: '短信测试',
+      rules: 'required',
+    },
+    {
+      component: 'BcRadio',
+      componentProps: {
+        api: {
+          type: 'enum',
+          params: EnumApi.EnumType.Provider,
+        },
+        isBtn: true,
+      },
+      fieldName: 'provider',
+      label: '短信服务商',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'AccessKey ID',
+      },
+      fieldName: 'accessKeyId',
+      label: 'AccessKey',
+      // rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'SecretKey Secret',
+      },
+      fieldName: 'accessKeySecret',
+      label: 'SecretKey',
+      // rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '短信SDKAPPID,示例值:1400006666',
+      },
+
+      dependencies: {
+        triggerFields: ['provider'],
+        show(values) {
+          return [1].includes(values.provider);
+        },
+      },
+      fieldName: 'sdkAppId',
+      label: '短信SdkAppId',
+      // rules: 'required',
+    },
+    {
+      component: h('div', { class: 'text-sm font-thin' }, [
+        h(
+          'div',
+          null,
+          '短信服务商的不同,模板的格式不同,请注意修改系统通知模板;',
+        ),
+        h(
+          'div',
+          null,
+          '短信的签名、模板,请在相关的平台设置和获取,审核后才可使用;',
+        ),
+        h('div', null, '修改短信账户信息后,请保存成功后再进行发送测试短信;'),
+        h(
+          'div',
+          null,
+          '测试短信的模板变量,阿里云格式如:{"参数名","值"},腾讯云如:值1,值2',
+        ),
+      ]),
+      formItemClass: 'items-start',
+      fieldName: 'remark',
+      label: '填写说明',
+    },
+  ];
+};
+
+export const useEmailSchema = (): VbenFormSchema[] => {
+  return [
+    {
+      component: 'Switch',
+      fieldName: 'enableSsl',
+      label: 'SSL加密连接',
+      rules: 'required',
+      componentProps: {
+        placeholder: '请输入显示字数',
+        class: 'w-auto',
+      },
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '发送邮件的SMTP服务器地址',
+      },
+      fieldName: 'host',
+      label: 'SMTP服务器',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'SMTP服务器端口,一般是25',
+      },
+      fieldName: 'host',
+      label: 'SMTP端口',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '发件人邮箱地址',
+      },
+      fieldName: 'emailFrom',
+      label: '发件人地址',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '发件人邮箱账号',
+      },
+      fieldName: 'userName',
+      label: '邮箱账号',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '发件人邮箱密码',
+      },
+      fieldName: 'password',
+      label: '邮箱密码',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '发件人发件人呢称',
+      },
+      fieldName: 'nickName',
+      label: '发件人呢称',
+      rules: 'required',
+    },
+    {
+      component: 'Switch',
+      componentProps: {
+        placeholder: '启用错误日志发送邮箱',
+        class: 'w-auto',
+      },
+      fieldName: 'useError',
+      label: '启用错误日志发送邮箱',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '启用错误日志发送邮箱',
+      },
+      fieldName: 'emailTo',
+      label: '接收错误日志的邮箱',
+      rules: 'required',
+      dependencies: {
+        triggerFields: ['useError'],
+        show(values) {
+          return values.useError;
+        },
+      },
+    },
+    {
+      component: h('div', { class: 'text-sm font-thin' }, [
+        h(
+          'div',
+          null,
+          '短信服务商的不同,模板的格式不同,请注意修改系统通知模板;',
+        ),
+        h(
+          'div',
+          null,
+          '短信的签名、模板,请在相关的平台设置和获取,审核后才可使用;',
+        ),
+        h('div', null, '修改短信账户信息后,请保存成功后再进行发送测试短信;'),
+        h(
+          'div',
+          null,
+          '测试短信的模板变量,阿里云格式如:{"参数名","值"},腾讯云如:值1,值2',
+        ),
+      ]),
+      formItemClass: 'items-start',
+      fieldName: 'remark',
+      label: '填写说明',
+    },
+  ];
+};

+ 58 - 0
apps/web-baicai/src/views/plugins/config/index.vue

@@ -0,0 +1,58 @@
+<script lang="ts" setup>
+import { onMounted, reactive } from 'vue';
+
+import { alert, Page } from '@vben/common-ui';
+
+import { Tabs } from 'ant-design-vue';
+
+import { useFormOptions, useVbenForm } from '#/adapter';
+import { PluginsConfigApi } from '#/api';
+
+import { useEmailSchema, useSmsSchema } from './data.config';
+
+const [FormSms, formSmsApi] = useVbenForm(
+  useFormOptions({
+    showDefaultActions: true,
+    schema: useSmsSchema(),
+    handleSubmit: async (values: Record<string, any>) => {
+      await PluginsConfigApi.editSmsDetail(values);
+      alert('保存成功');
+    },
+  }),
+);
+
+const [FormEmail, formEmailApi] = useVbenForm(
+  useFormOptions({
+    showDefaultActions: true,
+    schema: useEmailSchema(),
+    handleSubmit: async (values: Record<string, any>) => {
+      await PluginsConfigApi.editEmailDetail(values);
+      alert('保存成功');
+    },
+  }),
+);
+
+const state = reactive({
+  activeKey: '1',
+});
+
+onMounted(async () => {
+  const smsData = await PluginsConfigApi.getSmsDetail();
+  formSmsApi.setValues(smsData);
+  const emailData = await PluginsConfigApi.getEmailDetail();
+  formEmailApi.setValues(emailData);
+});
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Tabs v-model:active-key="state.activeKey" type="card">
+      <Tabs.TabPane key="1" tab="短信平台">
+        <FormSms />
+      </Tabs.TabPane>
+      <Tabs.TabPane key="2" tab="邮箱设置">
+        <FormEmail />
+      </Tabs.TabPane>
+    </Tabs>
+  </Page>
+</template>

+ 78 - 0
apps/web-baicai/src/views/plugins/template/components/edit.vue

@@ -0,0 +1,78 @@
+<script lang="ts" setup>
+import { computed, ref, unref } from 'vue';
+
+import { alert, useVbenModal } from '@vben/common-ui';
+
+import { useFormOptions, useVbenForm } from '#/adapter';
+import { PluginsTemplateApi } from '#/api';
+
+import { useSchema } from '../data.config';
+
+defineOptions({
+  name: 'PluginsTemplateEdit',
+});
+const emit = defineEmits(['success']);
+const modelRef = ref<Record<string, any>>({});
+const isUpdate = ref(true);
+
+const [Form, { validate, setValues, getValues }] = useVbenForm(
+  useFormOptions({
+    schema: useSchema(),
+  }),
+);
+
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
+  fullscreenButton: false,
+  draggable: true,
+  closeOnClickModal: false,
+  onCancel() {
+    close();
+  },
+  onConfirm: async () => {
+    try {
+      const { valid } = await validate();
+      if (!valid) return;
+
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? PluginsTemplateApi.editDetail(
+            postParams as PluginsTemplateApi.RecordItem,
+          )
+        : PluginsTemplateApi.addDetail(
+            postParams as PluginsTemplateApi.BasicRecordItem,
+          ));
+
+      alert('操作成功');
+
+      emit('success');
+      close();
+    } finally {
+      unlock();
+    }
+  },
+  onOpenChange: async (isOpen: boolean) => {
+    if (isOpen) {
+      setState({ loading: true });
+      const data = getData<Record<string, any>>();
+      isUpdate.value = !!data.isUpdate;
+      modelRef.value = { ...data.baseData };
+
+      if (unref(isUpdate)) {
+        const entity = await PluginsTemplateApi.getDetail(data.baseData.id);
+        modelRef.value = { ...entity };
+        setValues(entity);
+      }
+      setState({ loading: false });
+    }
+  },
+});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑模板' : '新增模板'));
+</script>
+<template>
+  <Modal class="w-[1000px]" :title="getTitle">
+    <Form />
+  </Modal>
+</template>

+ 195 - 0
apps/web-baicai/src/views/plugins/template/data.config.ts

@@ -0,0 +1,195 @@
+import type {
+  OnActionClickFn,
+  VbenFormSchema,
+  VxeTableGridOptions,
+} from '#/adapter';
+
+import { h } from 'vue';
+
+import { EnumApi, PluginsTemplateApi } from '#/api';
+
+export function getPluginsTypeOptions() {
+  return [
+    { color: 'processing', label: '短信模板', value: 0 },
+    { color: 'success', label: '邮箱模板', value: 1 },
+  ];
+}
+
+export const useSearchSchema = (): VbenFormSchema[] => {
+  return [
+    {
+      component: 'BcSelect',
+      fieldName: 'pluginsType',
+      label: '类型',
+      componentProps: {
+        api: {
+          type: 'enum',
+          params: EnumApi.EnumType.PluginsType,
+        },
+        showSearch: true,
+      },
+    },
+    {
+      component: 'Input',
+      fieldName: 'name',
+      label: '名称',
+    },
+    {
+      component: 'Input',
+      fieldName: 'code',
+      label: '编码',
+    },
+    {
+      component: 'Input',
+      fieldName: 'signName',
+      label: '短信签名',
+    },
+    {
+      component: 'Input',
+      fieldName: 'templateCode',
+      label: '模板标识',
+    },
+  ];
+};
+
+export function useColumns(
+  onActionClick?: OnActionClickFn<PluginsTemplateApi.RecordItem>,
+): VxeTableGridOptions<PluginsTemplateApi.RecordItem>['columns'] {
+  return [
+    { title: '序号', type: 'seq', width: 50 },
+    {
+      align: 'left',
+      field: 'pluginsType',
+      title: '类型',
+      width: 100,
+      cellRender: { name: 'CellTag', options: getPluginsTypeOptions() },
+    },
+    {
+      align: 'left',
+      field: 'code',
+      title: '调用名称',
+      width: 120,
+    },
+    { align: 'left', field: 'name', title: '标题' },
+    {
+      align: 'right',
+      cellRender: {
+        attrs: {
+          nameField: 'name',
+          nameTitle: '标题',
+          onClick: onActionClick,
+        },
+        name: 'CellAction',
+        options: [
+          {
+            code: 'edit',
+            auth: ['plugins-template:edit'],
+          },
+          {
+            code: 'delete',
+            auth: ['plugins-template:delete'],
+          },
+        ],
+      },
+      field: 'operation',
+      fixed: 'right',
+      headerAlign: 'center',
+      showOverflow: false,
+      title: '操作',
+      width: 100,
+    },
+  ];
+}
+
+export const useSchema = (): VbenFormSchema[] => {
+  return [
+    {
+      component: 'BcRadio',
+      fieldName: 'pluginsType',
+      label: '类型',
+      componentProps: {
+        api: {
+          type: 'enum',
+          params: EnumApi.EnumType.PluginsType,
+        },
+        isBtn: true,
+      },
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '请输入编号',
+      },
+      fieldName: 'code',
+      label: '编号',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '请输入名称',
+      },
+      fieldName: 'name',
+      label: '名称',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '请输入已报备通过的短信签名',
+      },
+      fieldName: 'signName',
+      label: '短信签名',
+      rules: 'required',
+
+      dependencies: {
+        triggerFields: ['pluginsType'],
+        show(values) {
+          return [0].includes(values.pluginsType);
+        },
+      },
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '请输入模板标识',
+      },
+      fieldName: 'templateCode',
+      label: '模板标识',
+      rules: 'required',
+
+      dependencies: {
+        triggerFields: ['pluginsType'],
+        show(values) {
+          return [0].includes(values.pluginsType);
+        },
+      },
+    },
+    {
+      component: 'Textarea',
+      componentProps: {
+        placeholder: '请输入',
+      },
+      fieldName: 'content',
+      label: '短信内容',
+    },
+    {
+      component: h('div', { class: 'text-sm font-thin' }, [
+        h(
+          'div',
+          null,
+          '阿里云的模板内容请填写JSON格式字符串,格式如:{"code":"{code}"}',
+        ),
+        h(
+          'div',
+          null,
+          '腾讯云的模板内容请用英文逗号分隔开,且变量顺序要和报备的一致;',
+        ),
+      ]),
+      formItemClass: 'items-start',
+      fieldName: 'remark',
+      label: '填写说明',
+    },
+  ];
+};

+ 91 - 0
apps/web-baicai/src/views/plugins/template/index.vue

@@ -0,0 +1,91 @@
+<script lang="ts" setup>
+import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter';
+
+import { alert, Page, useVbenModal } from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
+
+import { useTableGridOptions, useVbenVxeGrid } from '#/adapter';
+import { PluginsTemplateApi } from '#/api';
+
+import FormEdit from './components/edit.vue';
+import { useColumns, useSearchSchema } from './data.config';
+
+const [FormEditModal, formEditApi] = useVbenModal({
+  connectedComponent: FormEdit,
+  destroyOnClose: true,
+});
+
+const handelSuccess = () => {
+  reload();
+};
+const handleDelete = async (id: number) => {
+  await PluginsTemplateApi.deleteDetail(id);
+  alert('数据删除成功');
+  handelSuccess();
+};
+
+const handleEdit = (record: Record<string, any>, isUpdate: boolean) => {
+  formEditApi
+    .setData({
+      isUpdate,
+      baseData: { id: record.id },
+    })
+    .open();
+};
+const handleActionClick = async ({
+  code,
+  row,
+}: OnActionClickParams<SmsApi.RecordTemplateItem>) => {
+  switch (code) {
+    case 'delete': {
+      await handleDelete(row.id);
+      break;
+    }
+    case 'edit': {
+      handleEdit(row, true);
+      break;
+    }
+  }
+};
+
+const [Grid, { reload }] = useVbenVxeGrid(
+  useTableGridOptions({
+    formOptions: {
+      schema: useSearchSchema(),
+    },
+    gridOptions: {
+      columns: useColumns(handleActionClick),
+      proxyConfig: {
+        ajax: {
+          query: async ({ page }, formValues) => {
+            return await PluginsTemplateApi.getPage({
+              pageIndex: page.currentPage,
+              pageSize: page.pageSize,
+              ...formValues,
+            });
+          },
+        },
+      },
+    } as VxeTableGridOptions,
+  }),
+);
+</script>
+
+<template>
+  <Page auto-content-height>
+    <FormEditModal @success="handelSuccess" />
+    <Grid>
+      <template #toolbar-tools>
+        <Button
+          class="mr-2"
+          type="primary"
+          v-access:code="'plugins-template:add'"
+          @click="() => handleEdit({}, false)"
+        >
+          新增模板
+        </Button>
+      </template>
+    </Grid>
+  </Page>
+</template>