mirror of https://github.com/certd/certd
				
				
				
			perf: 站点证书监控增加导出和分组功能
							parent
							
								
									e578c52fdf
								
							
						
					
					
						commit
						2ed12c429e
					
				| 
						 | 
				
			
			@ -227,6 +227,7 @@ export default {
 | 
			
		|||
  },
 | 
			
		||||
  notificationDefault: "Use Default Notification",
 | 
			
		||||
  monitor: {
 | 
			
		||||
    remark: "Remark",
 | 
			
		||||
    title: "Site Certificate Monitoring",
 | 
			
		||||
    description: "Check website certificates' expiration at 0:00 daily; reminders sent 10 days before expiration (using default notification channel);",
 | 
			
		||||
    settingLink: "Site Monitoring Settings",
 | 
			
		||||
| 
						 | 
				
			
			@ -248,6 +249,7 @@ export default {
 | 
			
		|||
    certDomains: "Certificate Domains",
 | 
			
		||||
    certProvider: "Issuer",
 | 
			
		||||
    certStatus: "Certificate Status",
 | 
			
		||||
    error: "Error",
 | 
			
		||||
    status: {
 | 
			
		||||
      ok: "Valid",
 | 
			
		||||
      expired: "Expired",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,6 +232,7 @@ export default {
 | 
			
		|||
  },
 | 
			
		||||
  notificationDefault: "使用默认通知",
 | 
			
		||||
  monitor: {
 | 
			
		||||
    remark: "备注",
 | 
			
		||||
    title: "站点证书监控",
 | 
			
		||||
    description: "每天0点,检查网站证书的过期时间,到期前10天时将发出提醒(使用默认通知渠道);",
 | 
			
		||||
    settingLink: "站点监控设置",
 | 
			
		||||
| 
						 | 
				
			
			@ -253,6 +254,7 @@ export default {
 | 
			
		|||
    certDomains: "证书域名",
 | 
			
		||||
    certProvider: "颁发机构",
 | 
			
		||||
    certStatus: "证书状态",
 | 
			
		||||
    error: "错误信息",
 | 
			
		||||
    status: {
 | 
			
		||||
      ok: "正常",
 | 
			
		||||
      expired: "过期",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
import { dict } from "@fast-crud/fast-crud";
 | 
			
		||||
import { request } from "/src/api/service";
 | 
			
		||||
 | 
			
		||||
export function createApi() {
 | 
			
		||||
  const apiPrefix = "/basic/group";
 | 
			
		||||
  return {
 | 
			
		||||
    async GetList(query: any) {
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/page",
 | 
			
		||||
        method: "post",
 | 
			
		||||
        data: query,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async AddObj(obj: any) {
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/add",
 | 
			
		||||
        method: "post",
 | 
			
		||||
        data: obj,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async UpdateObj(obj: any) {
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/update",
 | 
			
		||||
        method: "post",
 | 
			
		||||
        data: obj,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async DelObj(id: number) {
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/delete",
 | 
			
		||||
        method: "post",
 | 
			
		||||
        params: { id },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async GetObj(id: number) {
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/info",
 | 
			
		||||
        method: "post",
 | 
			
		||||
        params: { id },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    async ListAll(type: string) {
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/all",
 | 
			
		||||
        method: "post",
 | 
			
		||||
        params: { type },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const pipelineGroupApi = createApi();
 | 
			
		||||
 | 
			
		||||
export function createGroupDictRef(type: string) {
 | 
			
		||||
  return dict({
 | 
			
		||||
    url: "/basic/group/all?type=" + type,
 | 
			
		||||
    value: "id",
 | 
			
		||||
    label: "name",
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,142 @@
 | 
			
		|||
import { useI18n } from "/src/locales";
 | 
			
		||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
 | 
			
		||||
import { pipelineGroupApi } from "./api";
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
 | 
			
		||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 | 
			
		||||
  const { t } = useI18n();
 | 
			
		||||
  const api = pipelineGroupApi;
 | 
			
		||||
  const typeRef = ref(context.type);
 | 
			
		||||
 | 
			
		||||
  const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
 | 
			
		||||
    return await api.GetList(query);
 | 
			
		||||
  };
 | 
			
		||||
  const editRequest = async (req: EditReq) => {
 | 
			
		||||
    const { form, row } = req;
 | 
			
		||||
    form.id = row.id;
 | 
			
		||||
    const res = await api.UpdateObj(form);
 | 
			
		||||
    return res;
 | 
			
		||||
  };
 | 
			
		||||
  const delRequest = async (req: DelReq) => {
 | 
			
		||||
    const { row } = req;
 | 
			
		||||
    return await api.DelObj(row.id);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const addRequest = async (req: AddReq) => {
 | 
			
		||||
    const { form } = req;
 | 
			
		||||
    form.type = typeRef.value;
 | 
			
		||||
    const res = await api.AddObj(form);
 | 
			
		||||
    return res;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    crudOptions: {
 | 
			
		||||
      settings: {
 | 
			
		||||
        plugins: {
 | 
			
		||||
          mobile: {
 | 
			
		||||
            props: {
 | 
			
		||||
              rowHandle: {
 | 
			
		||||
                width: 160,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      request: {
 | 
			
		||||
        pageRequest,
 | 
			
		||||
        addRequest,
 | 
			
		||||
        editRequest,
 | 
			
		||||
        delRequest,
 | 
			
		||||
      },
 | 
			
		||||
      search: {
 | 
			
		||||
        initialForm: {
 | 
			
		||||
          type: typeRef.value,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      form: {
 | 
			
		||||
        labelCol: {
 | 
			
		||||
          //固定label宽度
 | 
			
		||||
          span: null,
 | 
			
		||||
          style: {
 | 
			
		||||
            width: "100px",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        col: {
 | 
			
		||||
          span: 22,
 | 
			
		||||
        },
 | 
			
		||||
        wrapper: {
 | 
			
		||||
          width: 600,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      rowHandle: {
 | 
			
		||||
        width: 200,
 | 
			
		||||
        group: {
 | 
			
		||||
          editable: {
 | 
			
		||||
            edit: {
 | 
			
		||||
              text: t("certd.edit"),
 | 
			
		||||
              order: -1,
 | 
			
		||||
              type: "primary",
 | 
			
		||||
              click({ row, index }) {
 | 
			
		||||
                crudExpose.openEdit({
 | 
			
		||||
                  index,
 | 
			
		||||
                  row,
 | 
			
		||||
                });
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      table: {
 | 
			
		||||
        editable: {
 | 
			
		||||
          enabled: true,
 | 
			
		||||
          mode: "cell",
 | 
			
		||||
          exclusive: true,
 | 
			
		||||
          //排他式激活效果,将其他行的编辑状态触发保存
 | 
			
		||||
          exclusiveEffect: "save", //自动保存其他行编辑状态,cancel = 自动关闭其他行编辑状态
 | 
			
		||||
          async updateCell(opts) {
 | 
			
		||||
            const { row, key, value } = opts;
 | 
			
		||||
            //如果是添加,需要返回{[rowKey]:xxx},比如:{id:2}
 | 
			
		||||
            return await api.UpdateObj({ id: row.id, [key]: value });
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      columns: {
 | 
			
		||||
        id: {
 | 
			
		||||
          title: "ID",
 | 
			
		||||
          key: "id",
 | 
			
		||||
          type: "number",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: true,
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 100,
 | 
			
		||||
            editable: {
 | 
			
		||||
              disabled: true,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          form: {
 | 
			
		||||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        name: {
 | 
			
		||||
          title: t("certd.groupName"),
 | 
			
		||||
          search: {
 | 
			
		||||
            show: true,
 | 
			
		||||
          },
 | 
			
		||||
          type: "text",
 | 
			
		||||
          form: {
 | 
			
		||||
            rules: [
 | 
			
		||||
              {
 | 
			
		||||
                required: true,
 | 
			
		||||
                message: t("certd.enterGroupName"),
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 400,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="pi-group-selector flex full-w">
 | 
			
		||||
    <div class="flex-1">
 | 
			
		||||
      <fs-dict-select :value="modelValue" :dict="groupDictRef" :allow-clear="true" @update:value="doUpdate"></fs-dict-select>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <fs-table-select
 | 
			
		||||
      class="flex-0"
 | 
			
		||||
      :create-crud-options="createCrudOptions"
 | 
			
		||||
      :crud-options-override="{
 | 
			
		||||
        search: { show: false, initialForm: { type: props.type } },
 | 
			
		||||
        table: {
 | 
			
		||||
          scroll: {
 | 
			
		||||
            x: 540,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      }"
 | 
			
		||||
      :model-value="modelValue"
 | 
			
		||||
      :dict="groupDictRef"
 | 
			
		||||
      :show-current="false"
 | 
			
		||||
      :show-select="false"
 | 
			
		||||
      :dialog="{ width: 960 }"
 | 
			
		||||
      :destroy-on-close="false"
 | 
			
		||||
      height="400px"
 | 
			
		||||
      @update:model-value="doUpdate"
 | 
			
		||||
      @dialog-closed="doRefresh"
 | 
			
		||||
    >
 | 
			
		||||
      <template #default="scope">
 | 
			
		||||
        <fs-button class="ml-5" type="primary" icon="ant-design:edit-outlined" @click="scope.open({ context: { type: props.type } })"></fs-button>
 | 
			
		||||
      </template>
 | 
			
		||||
    </fs-table-select>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { createGroupDictRef } from "./api";
 | 
			
		||||
import createCrudOptions from "./crud";
 | 
			
		||||
import { dict, FsDictSelect } from "@fast-crud/fast-crud";
 | 
			
		||||
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
  modelValue?: number;
 | 
			
		||||
  type: string;
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
defineOptions({
 | 
			
		||||
  name: "GroupSelector",
 | 
			
		||||
});
 | 
			
		||||
const groupDictRef = createGroupDictRef(props.type);
 | 
			
		||||
const emit = defineEmits(["refresh", "update:modelValue", "change"]);
 | 
			
		||||
function doRefresh() {
 | 
			
		||||
  emit("refresh");
 | 
			
		||||
  groupDictRef.reloadDict();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function doUpdate(value: any) {
 | 
			
		||||
  emit("update:modelValue", value);
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <fs-page>
 | 
			
		||||
    <template #header>
 | 
			
		||||
      <div class="title">
 | 
			
		||||
        分组管理
 | 
			
		||||
        <span class="sub">流水线分组</span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
 | 
			
		||||
  </fs-page>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, onActivated, onMounted } from "vue";
 | 
			
		||||
import { useFs } from "@fast-crud/fast-crud";
 | 
			
		||||
import createCrudOptions from "./crud";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "BasicGroupManager",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
 | 
			
		||||
 | 
			
		||||
    // 页面打开后获取列表数据
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      crudExpose.doRefresh();
 | 
			
		||||
    });
 | 
			
		||||
    onActivated(() => {
 | 
			
		||||
      crudExpose.doRefresh();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      crudBinding,
 | 
			
		||||
      crudRef,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
// @ts-ignore
 | 
			
		||||
import { useI18n } from "/src/locales";
 | 
			
		||||
import { AddReq, ColumnCompositionProps, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
 | 
			
		||||
import { AddReq, ColumnCompositionProps, ColumnProps, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DataFormatterContext, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
 | 
			
		||||
import { siteInfoApi } from "./api";
 | 
			
		||||
import * as settingApi from "./setting/api";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,8 @@ import { mitter } from "/@/utils/util.mitt";
 | 
			
		|||
import { useSiteIpMonitor } from "./ip/use";
 | 
			
		||||
import { useSiteImport } from "/@/views/certd/monitor/site/use";
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
 | 
			
		||||
import GroupSelector from "../../basic/group/group-selector.vue";
 | 
			
		||||
import { createGroupDictRef } from "../../basic/group/api";
 | 
			
		||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 | 
			
		||||
  const { t } = useI18n();
 | 
			
		||||
  const api = siteInfoApi;
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +92,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const GroupTypeSite = "site";
 | 
			
		||||
  const groupDictRef = createGroupDictRef(GroupTypeSite);
 | 
			
		||||
 | 
			
		||||
  function getDefaultGroupId() {
 | 
			
		||||
    const searchFrom = crudExpose.getSearchValidatedFormData();
 | 
			
		||||
    if (searchFrom.groupId) {
 | 
			
		||||
      return searchFrom.groupId;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return {
 | 
			
		||||
    id: "siteMonitorCrud",
 | 
			
		||||
    crudOptions: {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +111,53 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
        editRequest,
 | 
			
		||||
        delRequest,
 | 
			
		||||
      },
 | 
			
		||||
      tabs: {
 | 
			
		||||
        name: "groupId",
 | 
			
		||||
        show: true,
 | 
			
		||||
      },
 | 
			
		||||
      toolbar: {
 | 
			
		||||
        buttons: {
 | 
			
		||||
          export: {
 | 
			
		||||
            show: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        export: {
 | 
			
		||||
          dataFrom: "search",
 | 
			
		||||
          columnFilter: (col: ColumnProps) => {
 | 
			
		||||
            //列过滤器,返回true则导出该列
 | 
			
		||||
            //例如: 只导出show=true的列
 | 
			
		||||
            return col.show === true;
 | 
			
		||||
          },
 | 
			
		||||
          dataFormatter: (opts: DataFormatterContext) => {
 | 
			
		||||
            //例如 格式化日期
 | 
			
		||||
            const { row, originalRow, col, exportCol } = opts;
 | 
			
		||||
            const key = col.key;
 | 
			
		||||
            const element = originalRow[key];
 | 
			
		||||
            if (key.includes("Time") && element) {
 | 
			
		||||
              row[key] = dayjs(element).format("YYYY-MM-DD HH:mm:ss");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (col.width) {
 | 
			
		||||
              exportCol.width = col.width / 10;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (col.key === "certInfo" && originalRow?.certProvider) {
 | 
			
		||||
              row[key] = originalRow?.certProvider + " " + originalRow?.certDomains;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //参数说明
 | 
			
		||||
            // DataFormatterContext = {row: any,originalRow: any, key: string, col: ColumnProps, exportCol:ExportColumn}
 | 
			
		||||
            // row = 当前行数据
 | 
			
		||||
            // originalRow = 当前行原始数据
 | 
			
		||||
            // key = 当前列的key
 | 
			
		||||
            // col = 当前列的配置
 | 
			
		||||
            // exportCol = 当前列的导出配置
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      pagination: {
 | 
			
		||||
        pageSizeOptions: ["10", "20", "50", "100", "200"],
 | 
			
		||||
      },
 | 
			
		||||
      settings: {
 | 
			
		||||
        plugins: {
 | 
			
		||||
          //这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +216,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              await crudExpose.openAdd({});
 | 
			
		||||
              const defaultGroupId = getDefaultGroupId();
 | 
			
		||||
              await crudExpose.openAdd({
 | 
			
		||||
                row: { groupId: defaultGroupId },
 | 
			
		||||
              });
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          //导入按钮
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +228,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
            text: t("certd.monitor.bulkImport"),
 | 
			
		||||
            type: "primary",
 | 
			
		||||
            async click() {
 | 
			
		||||
              const defaultGroupId = getDefaultGroupId();
 | 
			
		||||
              openSiteImportDialog({
 | 
			
		||||
                defaultGroupId,
 | 
			
		||||
                afterSubmit() {
 | 
			
		||||
                  crudExpose.doRefresh();
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -219,10 +282,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      tabs: {
 | 
			
		||||
        name: "disabled",
 | 
			
		||||
        show: true,
 | 
			
		||||
      },
 | 
			
		||||
      // tabs: {
 | 
			
		||||
      //   name: "disabled",
 | 
			
		||||
      //   show: true,
 | 
			
		||||
      // },
 | 
			
		||||
      columns: {
 | 
			
		||||
        id: {
 | 
			
		||||
          title: "ID",
 | 
			
		||||
| 
						 | 
				
			
			@ -403,6 +466,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
          column: {
 | 
			
		||||
            sorter: true,
 | 
			
		||||
            width: 155,
 | 
			
		||||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        certExpiresTime: {
 | 
			
		||||
| 
						 | 
				
			
			@ -451,6 +515,46 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        groupId: {
 | 
			
		||||
          title: t("certd.fields.group"),
 | 
			
		||||
          type: "dict-select",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: true,
 | 
			
		||||
          },
 | 
			
		||||
          dict: groupDictRef,
 | 
			
		||||
          form: {
 | 
			
		||||
            component: {
 | 
			
		||||
              name: GroupSelector,
 | 
			
		||||
              vModel: "modelValue",
 | 
			
		||||
              type: GroupTypeSite,
 | 
			
		||||
              onRefresh() {
 | 
			
		||||
                groupDictRef.reloadDict();
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 130,
 | 
			
		||||
            align: "center",
 | 
			
		||||
            component: {
 | 
			
		||||
              color: "auto",
 | 
			
		||||
            },
 | 
			
		||||
            sorter: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        remark: {
 | 
			
		||||
          title: t("certd.monitor.remark"),
 | 
			
		||||
          search: {
 | 
			
		||||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
          type: "text",
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 200,
 | 
			
		||||
            sorter: true,
 | 
			
		||||
            cellRender({ value }) {
 | 
			
		||||
              return <a-tooltip title={value}>{value}</a-tooltip>;
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        lastCheckTime: {
 | 
			
		||||
          title: t("certd.monitor.lastCheckTime"),
 | 
			
		||||
          search: {
 | 
			
		||||
| 
						 | 
				
			
			@ -618,6 +722,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        error: {
 | 
			
		||||
          title: t("certd.monitor.error"),
 | 
			
		||||
          search: {
 | 
			
		||||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
          type: "text",
 | 
			
		||||
          form: { show: false },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 200,
 | 
			
		||||
            sorter: true,
 | 
			
		||||
            cellRender({ value }) {
 | 
			
		||||
              return <a-tooltip title={value}>{value}</a-tooltip>;
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,13 @@
 | 
			
		|||
import { useFormWrapper } from "@fast-crud/fast-crud";
 | 
			
		||||
import { siteInfoApi } from "./api";
 | 
			
		||||
import { useI18n } from "/src/locales";
 | 
			
		||||
 | 
			
		||||
import GroupSelector from "../../basic/group/group-selector.vue";
 | 
			
		||||
export function useSiteImport() {
 | 
			
		||||
  const { t } = useI18n();
 | 
			
		||||
  const { openCrudFormDialog } = useFormWrapper();
 | 
			
		||||
 | 
			
		||||
  async function openSiteImportDialog(opts: { afterSubmit: any }) {
 | 
			
		||||
    const { afterSubmit } = opts;
 | 
			
		||||
  async function openSiteImportDialog(opts: { afterSubmit: any; defaultGroupId?: number }) {
 | 
			
		||||
    const { afterSubmit, defaultGroupId } = opts;
 | 
			
		||||
    await openCrudFormDialog<any>({
 | 
			
		||||
      crudOptions: {
 | 
			
		||||
        columns: {
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,21 @@ export function useSiteImport() {
 | 
			
		|||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          groupId: {
 | 
			
		||||
            type: "select",
 | 
			
		||||
            title: t("certd.fields.group"),
 | 
			
		||||
            form: {
 | 
			
		||||
              value: defaultGroupId,
 | 
			
		||||
              component: {
 | 
			
		||||
                name: GroupSelector,
 | 
			
		||||
                vModel: "modelValue",
 | 
			
		||||
                type: "site",
 | 
			
		||||
              },
 | 
			
		||||
              col: {
 | 
			
		||||
                span: 24,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        form: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
ALTER TABLE cd_site_info ADD COLUMN "remark" varchar(512);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE "cd_group"
 | 
			
		||||
(
 | 
			
		||||
  "id"          integer PRIMARY KEY AUTOINCREMENT NOT NULL,
 | 
			
		||||
  "user_id"     integer      NOT NULL,
 | 
			
		||||
  "name"        varchar(100) NOT NULL,
 | 
			
		||||
  "icon"        varchar(100),
 | 
			
		||||
  "favorite"    boolean      NOT NULL DEFAULT (false),
 | 
			
		||||
  "type"        varchar(512),
 | 
			
		||||
  "create_time" datetime     NOT NULL DEFAULT (CURRENT_TIMESTAMP),
 | 
			
		||||
  "update_time" datetime     NOT NULL DEFAULT (CURRENT_TIMESTAMP)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
--分组字段
 | 
			
		||||
ALTER TABLE cd_site_info ADD COLUMN "group_id" integer;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,78 @@
 | 
			
		|||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
 | 
			
		||||
import { Constants, CrudController } from '@certd/lib-server';
 | 
			
		||||
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
 | 
			
		||||
import { GroupService } from '../../../modules/basic/service/group-service.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知
 | 
			
		||||
 */
 | 
			
		||||
@Provide()
 | 
			
		||||
@Controller('/api/basic/group')
 | 
			
		||||
export class GroupController extends CrudController<GroupService> {
 | 
			
		||||
  @Inject()
 | 
			
		||||
  service: GroupService;
 | 
			
		||||
  @Inject()
 | 
			
		||||
  authService: AuthService;
 | 
			
		||||
 | 
			
		||||
  getService(): GroupService {
 | 
			
		||||
    return this.service;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Post('/page', { summary: Constants.per.authOnly })
 | 
			
		||||
  async page(@Body(ALL) body: any) {
 | 
			
		||||
    body.query = body.query ?? {};
 | 
			
		||||
    delete body.query.userId;
 | 
			
		||||
    const buildQuery = qb => {
 | 
			
		||||
      qb.andWhere('user_id = :userId', { userId: this.getUserId() });
 | 
			
		||||
    };
 | 
			
		||||
    const res = await this.service.page({
 | 
			
		||||
      query: body.query,
 | 
			
		||||
      page: body.page,
 | 
			
		||||
      sort: body.sort,
 | 
			
		||||
      buildQuery,
 | 
			
		||||
    });
 | 
			
		||||
    return this.ok(res);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Post('/list', { summary: Constants.per.authOnly })
 | 
			
		||||
  async list(@Body(ALL) body: any) {
 | 
			
		||||
    body.query = body.query ?? {};
 | 
			
		||||
    body.query.userId = this.getUserId();
 | 
			
		||||
    return await super.list(body);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Post('/add', { summary: Constants.per.authOnly })
 | 
			
		||||
  async add(@Body(ALL) bean: any) {
 | 
			
		||||
    bean.userId = this.getUserId();
 | 
			
		||||
    return await super.add(bean);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Post('/update', { summary: Constants.per.authOnly })
 | 
			
		||||
  async update(@Body(ALL) bean) {
 | 
			
		||||
    await this.service.checkUserId(bean.id, this.getUserId());
 | 
			
		||||
    delete bean.userId;
 | 
			
		||||
    return await super.update(bean);
 | 
			
		||||
  }
 | 
			
		||||
  @Post('/info', { summary: Constants.per.authOnly })
 | 
			
		||||
  async info(@Query('id') id: number) {
 | 
			
		||||
    await this.service.checkUserId(id, this.getUserId());
 | 
			
		||||
    return await super.info(id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Post('/delete', { summary: Constants.per.authOnly })
 | 
			
		||||
  async delete(@Query('id') id: number) {
 | 
			
		||||
    await this.service.checkUserId(id, this.getUserId());
 | 
			
		||||
    return await super.delete(id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Post('/all', { summary: Constants.per.authOnly })
 | 
			
		||||
  async all(@Query('type') type: string) {
 | 
			
		||||
    const list: any = await this.service.find({
 | 
			
		||||
      where: {
 | 
			
		||||
        userId: this.getUserId(),
 | 
			
		||||
        type,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    return this.ok(list);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
 | 
			
		||||
 | 
			
		||||
export const GROUP_TYPE_SITE = 'site';
 | 
			
		||||
 | 
			
		||||
@Entity('cd_group')
 | 
			
		||||
export class GroupEntity {
 | 
			
		||||
  @PrimaryGeneratedColumn()
 | 
			
		||||
  id: number;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'user_id', comment: '用户id' })
 | 
			
		||||
  userId: number;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'name', comment: '分组名称' })
 | 
			
		||||
  name: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'icon', comment: '图标' })
 | 
			
		||||
  icon: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'favorite', comment: '收藏' })
 | 
			
		||||
  favorite: boolean;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'type', comment: '类型', length: 512 })
 | 
			
		||||
  type: string;
 | 
			
		||||
 | 
			
		||||
  @Column({
 | 
			
		||||
    name: 'create_time',
 | 
			
		||||
    comment: '创建时间',
 | 
			
		||||
    default: () => 'CURRENT_TIMESTAMP',
 | 
			
		||||
  })
 | 
			
		||||
  createTime: Date;
 | 
			
		||||
 | 
			
		||||
  @Column({
 | 
			
		||||
    name: 'update_time',
 | 
			
		||||
    comment: '修改时间',
 | 
			
		||||
    default: () => 'CURRENT_TIMESTAMP',
 | 
			
		||||
  })
 | 
			
		||||
  updateTime: Date;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
 | 
			
		||||
import { BaseService } from '@certd/lib-server';
 | 
			
		||||
import { InjectEntityModel } from '@midwayjs/typeorm';
 | 
			
		||||
import { Repository } from 'typeorm';
 | 
			
		||||
import { merge } from 'lodash-es';
 | 
			
		||||
import { GroupEntity } from '../entity/group.js';
 | 
			
		||||
 | 
			
		||||
@Provide()
 | 
			
		||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
 | 
			
		||||
export class GroupService extends BaseService<GroupEntity> {
 | 
			
		||||
  @InjectEntityModel(GroupEntity)
 | 
			
		||||
  repository: Repository<GroupEntity>;
 | 
			
		||||
 | 
			
		||||
  //@ts-ignore
 | 
			
		||||
  getRepository() {
 | 
			
		||||
    return this.repository;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async add(bean: any) {
 | 
			
		||||
    if (!bean.type) {
 | 
			
		||||
     throw new Error('type is required');
 | 
			
		||||
    }
 | 
			
		||||
    bean = merge(
 | 
			
		||||
      {
 | 
			
		||||
        favorite: false,
 | 
			
		||||
      },
 | 
			
		||||
      bean
 | 
			
		||||
    );
 | 
			
		||||
    return await this.repository.save(bean);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +56,12 @@ export class SiteInfoEntity {
 | 
			
		|||
  @Column({ name: 'disabled', comment: '禁用启用' })
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'remark', comment: '备注', length: 512 })
 | 
			
		||||
  remark: string;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'group_id', comment: '分组id' })
 | 
			
		||||
  groupId: number;
 | 
			
		||||
 | 
			
		||||
  @Column({ name: 'create_time', comment: '创建时间', default: () => 'CURRENT_TIMESTAMP' })
 | 
			
		||||
  createTime: Date;
 | 
			
		||||
  @Column({ name: 'update_time', comment: '修改时间', default: () => 'CURRENT_TIMESTAMP' })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue