<script setup lang="ts">
import {
  type PlusColumn,
  PlusPage,
  PlusDialog,
  PlusDescriptions,
  PlusPageInstance,
  useTable
} from "plus-pro-components";
import { computed, reactive, ref, toRefs, type Ref } from "vue";
import {
  cleanSystemOperlog,
  deleteSystemOperlog,
  getSystemOperlogList
} from "@/api/system/operlog";
import {
  useDict,
  useDictValue,
  useDictClass,
  useDictClassAsync
} from "@/utils/dict";
import { ElMessage, ElMessageBox } from "element-plus";
import { cloneDeep } from "lodash";

defineOptions({
  name: "Operlog"
});

const { sys_common_status, sys_oper_type } = useDict(
  "sys_common_status",
  "sys_oper_type"
);

const plusPageInstance = ref<PlusPageInstance | null>(null);

const getList = async (query: Record<string, any>) => {
  let res = await getSystemOperlogList(query);
  return {
    data: res.rows,
    total: res.total
  };
};

// 重新请求列表接口
const refresh = () => {
  plusPageInstance.value?.getList();
};

// 搜索之前函数
const handleBeforeSearch = (values: any) => {
  let params = cloneDeep(values);
  if (params.daterange && params.daterange.length === 2) {
    Reflect.set(params, "params", {});
    Reflect.set(params.params, "beginTime", values.daterange[0]);
    Reflect.set(params.params, "endTime", values.daterange[1]);
  } else {
    Reflect.deleteProperty(params, "params");
  }
  return params;
};

const tableConfig: PlusColumn[] = [
  {
    label: "日志编号",
    prop: "operId",
    valueType: "input",
    hideInSearch: true
  },
  {
    label: "系统模块",
    prop: "title",
    valueType: "input"
  },
  {
    label: "操作类型",
    prop: "businessType",
    valueType: "tag",
    // options: computed(() => sys_oper_type.value),
    fieldProps: async (value: string) => {
      return {
        type: await useDictClassAsync("sys_oper_type", value)
      };
    },
    formatter: value => useDictValue("sys_oper_type", value),
    hideInSearch: true
  },
  {
    label: "操作类型",
    prop: "businessType",
    valueType: "select",
    options: computed(() => sys_oper_type.value),
    hideInTable: true
  },
  {
    label: "请求方式",
    prop: "requestMethod",
    valueType: "input"
  },
  {
    label: "操作人员",
    prop: "operName",
    valueType: "input"
  },
  {
    label: "操作地址",
    prop: "operIp",
    valueType: "input",
    hideInSearch: true
  },
  {
    label: "操作状态",
    prop: "status",
    valueType: "tag",
    options: computed(() => sys_common_status.value),
    fieldProps: value => {
      return {
        type: useDictClass("sys_common_status", value + "")
      };
    },
    formatter: value => {
      return useDictValue("sys_common_status", value);
    },
    hideInSearch: true
  },
  {
    label: "操作状态",
    prop: "status",
    valueType: "select",
    options: computed(() => sys_common_status.value),
    hideInTable: true
  },
  {
    label: "操作时间",
    prop: "operTime",
    hideInSearch: true
  },
  {
    label: "操作时间",
    prop: "daterange",
    valueType: "date-picker",
    fieldProps: {
      type: "daterange",
      valueFormat: "YYYY-MM-DD HH:mm:ss"
    },
    hideInTable: true
  },
  {
    label: "消耗时间",
    prop: "costTime",
    valueType: "input",
    hideInSearch: true,
    formatter: value => value + "毫秒"
  }
];

const { buttons } = useTable();

buttons.value = [
  {
    // 修改
    text: "详细",
    code: "edit",
    // props v0.1.16 版本新增函数类型
    props: {
      type: "primary"
    },
    onClick(params) {
      form.value = params.row;
      state.isCreate = false;
      state.dialogVisible = true;
    }
  }
];

const multipleSelection = ref([]);

const handleSelectionChange = (val: string[]) => {
  multipleSelection.value = val;
};

const handleDelete = () => {
  // 删除前确认
  ElMessageBox.confirm("是否确认删除选中数据？", "删除确认", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    draggable: true
  })
    .then(async () => {
      try {
        let operIds = multipleSelection.value.map(
          item => item.operId
        ) as string[];
        let res = await deleteSystemOperlog(operIds.join(","));
        if (res.code === 200) {
          ElMessage.success("删除成功");
          refresh();
          multipleSelection.value = [];
        } else {
          ElMessage.error(res.msg);
        }
      } catch (e) {
        ElMessage.error("删除失败");
      }
    })
    .catch(() => {
      // 取消删除
    });
};

const handleClear = () => {
  // 清空前确认
  ElMessageBox.confirm("是否确认清空所有操作日志？", "清空确认", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
    draggable: true
  })
    .then(async () => {
      try {
        let res = await cleanSystemOperlog();
        if (res.code === 200) {
          ElMessage.success("清空成功");
          refresh();
          multipleSelection.value = [];
        } else {
          ElMessage.error(res.msg);
        }
      } catch (e) {
        ElMessage.error("清空失败");
      }
    })
    .catch(() => {
      // 取消清空
    });
};

interface State {
  dialogVisible: boolean;
  detailsVisible: boolean;
  confirmLoading: boolean;
  selectedIds: number[];
  isCreate: boolean;
  form: Record<string, any>;
  rules: Record<string, any>;
}

const state = reactive<State>({
  dialogVisible: false,
  detailsVisible: false,
  confirmLoading: false,
  selectedIds: [],
  isCreate: true,
  form: {},
  rules: {
    sysName: [{ required: true, message: "请输入系统名称", trigger: "blur" }],
    sysCode: [{ required: true, message: "请输入系统编码", trigger: "blur" }]
  }
});

const columns: PlusColumn[] = [
  {
    label: "操作模块",
    prop: "sysName",
    formatter: () => {
      return `${form.value.title}/${useDictValue("sys_oper_type", form.value.businessType)}`;
    },
    descriptionsItemProps: {
      span: 12
    }
  },
  {
    label: "请求地址",
    prop: "operUrl",
    descriptionsItemProps: {
      span: 12
    }
  },
  {
    label: "登录信息",
    prop: "operIp",
    formatter: () => {
      return `${form.value.operName}/${form.value.operIp}`;
    },
    descriptionsItemProps: {
      span: 12
    }
  },
  {
    label: "请求方式",
    prop: "requestMethod",
    descriptionsItemProps: {
      span: 12
    }
  },
  {
    label: "操作方法",
    prop: "method",
    descriptionsItemProps: {
      span: 24
    }
  },
  {
    label: "操作参数",
    prop: "operParam",
    descriptionsItemProps: {
      span: 24,
      className: "break-all"
    }
  },
  {
    label: "返回参数",
    prop: "jsonResult",
    descriptionsItemProps: {
      span: 24
    }
  },
  {
    label: "操作状态",
    prop: "status",
    formatter: () => {
      return useDictValue("sys_common_status", form.value.status);
    },
    descriptionsItemProps: {
      span: 8
    }
  },
  {
    label: "消耗时间",
    prop: "costTime",
    formatter: () => {
      return `${form.value.costTime}毫秒`;
    },
    descriptionsItemProps: {
      span: 8
    }
  },
  {
    label: "操作时间",
    prop: "operTime",
    descriptionsItemProps: {
      span: 8
    }
  }
];

const { form, dialogVisible } = toRefs(state);
</script>

<template>
  <div>
    <PlusPage
      ref="plusPageInstance"
      :columns="tableConfig"
      :request="getList"
      :pageInfoMap="{ page: 'pageNum', pageSize: 'pageSize' }"
      :beforeSearchSubmit="handleBeforeSearch"
      :table="{
        actionBar: { buttons, type: 'link', width: 140 },
        adaptive: { offsetBottom: 50 },
        isSelection: true,
        onSelectionChange: handleSelectionChange,
        rowKey: 'operId'
      }"
      :search="{
        showNumber: 3
      }"
    >
      <template #table-title>
        <el-row class="button-row">
          <el-button
            v-perms="'system:operlog:remove'"
            size="default"
            :disabled="multipleSelection.length === 0"
            type="danger"
            @click="handleDelete"
          >
            删除
          </el-button>
          <el-button
            v-perms="'system:operlog:remove'"
            size="default"
            type="danger"
            @click="handleClear"
          >
            清空日志
          </el-button>
        </el-row>
      </template>
    </PlusPage>
    <!-- 弹窗编辑 -->
    <PlusDialog
      v-model="dialogVisible"
      :title="'操作日志详细'"
      width="800"
      :has-footer="false"
    >
      <PlusDescriptions
        size="large"
        :column="24"
        :columns="columns"
        :data="form"
        :border="true"
        label-width="90px"
      />
    </PlusDialog>
  </div>
</template>

<style scoped lang="scss"></style>
