<template>
  <div>
    <PlusPage
      v-if="refreshTable"
      ref="plusPageInstance"
      :columns="tableConfig"
      :request="getList"
      :before-search-submit="handleBeforeSearch"
      :is-card="true"
      :search="{
        labelWidth: 100,
        showNumber: 3
      }"
      :table="{
        actionBar: { buttons, type: 'link', width: 140 },
        adaptive: { offsetBottom: 50 },
        treeProps: { children: 'children' },
        rowKey: 'menuId',
        defaultExpandAll: defaultExpandAll
      }"
      :pagination="false"
    >
      <template #table-title>
        <el-row class="button-row">
          <el-button
            v-perms="'system:menu:add'"
            size="default"
            type="success"
            @click="handleCreate"
          >
            新增
          </el-button>
          <el-button size="default" type="default" @click="toggleExpandAll">
            展开/折叠
          </el-button>
        </el-row>
      </template>
    </PlusPage>
    <!-- 弹窗编辑 -->
    <PlusDialogForm
      ref="dialogForm"
      v-model="form"
      v-model:visible="dialogVisible"
      :form="{
        columns,
        labelPosition: 'right',
        labelWidth: 100,
        rules,
        rowProps: { gutter: 20 },
        colProps: { span: 12 }
      }"
      :dialog="{ title: dialogTitle + '菜单', width: 800, confirmLoading }"
      @confirm="handleSubmit"
      @close="handleClose"
    >
      <template #plus-field-icon>
        <IconSelect v-model="form.icon" class="w-full" />
      </template>
    </PlusDialogForm>
  </div>
</template>

<script lang="ts" setup>
import {
  computed,
  h,
  nextTick,
  onMounted,
  reactive,
  ref,
  resolveDirective,
  toRefs
} from "vue";
import type { FormRules } from "element-plus";
import { ElMessage } from "element-plus";
import {
  type FieldValues,
  type PlusColumn,
  PlusDialogForm,
  PlusPage,
  PlusPageInstance,
  useTable
} from "plus-pro-components";
import { IconSelect } from "@/components/ReIcon";
import { cloneDeep } from "lodash";
import {
  addMenu,
  deleteMenu,
  getSystemList,
  getSystemMenuDetailById,
  getSystemMenuList,
  updateMenu
} from "@/api/system/menu";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";

defineOptions({
  name: "SystemMenu"
});

onMounted(async () => {
  await getSystem();
});

// 菜单列表
const menuList = ref([]);
const plusPageInstance = ref<PlusPageInstance | null>(null);

const refreshTable = ref(true);
const defaultExpandAll = ref(false);

const getList = async (query: Record<string, any>) => {
  let res = await getSystemMenuList(query);
  let list = listToTree(res.data);
  menuList.value = list;
  return {
    data: list,
    total: list.length
  };
};

const listToTree = (data: object[]) => {
  // * 先生成parent建立父子关系
  const obj = {};
  data.forEach((item: any) => {
    obj[item.menuId] = item;
  });
  // * obj -> {1001: {id: 1001, parentId: 0, name: 'AA'}, 1002: {...}}
  // console.log(obj, "obj")
  const parentList = [];
  data.forEach((item: any) => {
    const parent = obj[item.parentId];
    if (parent) {
      // * 当前项有父节点
      parent.children = parent.children || [];
      parent.children.push(item);
    } else {
      // * 当前项没有父节点 -> 顶层
      parentList.push(item);
    }
  });
  return parentList;
};

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

// 搜索之前函数
const handleBeforeSearch = (values: any) => {
  // 返回新的参数
  return cloneDeep(values);
};

const dialogTitle = computed(() => (state.isCreate ? "新增" : "编辑"));

const { buttons } = useTable();

const systemList = ref([]);

const getSystem = async () => {
  // 获取系统列表
  let res = await getSystemList();
  systemList.value = res.data.map((item: any) => ({
    label: item.sysName,
    value: item.sysCode
  }));
};

// 表格数据
const tableConfig: PlusColumn[] = [
  {
    label: "菜单名称",
    prop: "menuName",
    width: 180,
    tableColumnProps: {
      showOverflowTooltip: true
    }
  },
  {
    label: "图标",
    prop: "icon",
    width: 80,
    render: value => h(useRenderIcon(value ?? "")),
    hideInSearch: true
  },
  {
    label: "排序",
    prop: "orderNum",
    width: 80,
    hideInSearch: true
  },
  {
    label: "权限标识",
    prop: "perms",
    hideInSearch: true
  },
  {
    label: "网关URL",
    prop: "url",
    hideInSearch: true
  },
  {
    label: "组件路径",
    prop: "component",
    hideInSearch: true
  },
  {
    label: "状态",
    prop: "status",
    valueType: "tag",
    hideInSearch: true,
    fieldProps: value => ({
      type: value === "0" ? "primary" : "danger"
    }),
    fieldSlots: {
      default: ({ value }) => (value === "0" ? "正常" : "停用")
    }
  },
  {
    label: "系统",
    prop: "systemCode",
    valueType: "select",
    options: computed(() => systemList.value),
    hideInTable: true,
    fieldProps: {
      clearable: true,
      placeholder: "请选择系统",
      style: { width: "100%" }
    }
  },
  {
    label: "菜单状态",
    prop: "status",
    valueType: "select",
    options: [
      { label: "正常", value: "0" },
      { label: "停用", value: "1" }
    ],
    hideInTable: true,
    fieldProps: {
      clearable: true,
      placeholder: "请选择菜单状态",
      style: { width: "100%" }
    }
  },
  {
    label: "创建时间",
    prop: "createTime",
    valueType: "date-picker",
    hideInSearch: true,
    minWidth: 180
  }
];

const toggleExpandAll = () => {
  refreshTable.value = false;
  defaultExpandAll.value = !defaultExpandAll.value;
  nextTick(() => {
    refreshTable.value = true;
  });
};

/*--------------------表单--------------------*/

// 表单实例
const dialogForm = ref(null);

interface State {
  dialogVisible: boolean;
  detailsVisible: boolean;
  confirmLoading: boolean;
  selectedIds: number[];
  isCreate: boolean;
  form: {
    component: string; // 组件路径
    icon: string; // 菜单图标
    isCache: string; // 是否缓存 （0缓存 1不缓存）
    isFrame: string; // 是否外链 （0是 1否）
    menuName: string; // 菜单名称
    menuType: string; // 菜单类型（M目录 C菜单 F按钮）
    orderNum: string; // 显示排序
    parentId: number; // 上级菜单
    path: string; // 路由地址
    perms: string; // 权限标识
    query: string; // 路由参数
    routeName: string; // 路由名称
    status: string; // 菜单状态（0正常 1停用）
    systemCode: string; // 系统编码
    url: string; // 网关URL
    urlmatch: string; // 网关权限
    visible: string; // 显示状态（0显示 1隐藏）
  };
  rules: FormRules;
}

const state = reactive<State>({
  dialogVisible: false,
  detailsVisible: false,
  confirmLoading: false,
  selectedIds: [],
  isCreate: false,
  form: {
    component: null, // 组件路径
    icon: "", // 菜单图标
    isCache: "0", // 是否缓存 （0缓存 1不缓存）
    isFrame: "1", // 是否外链 （0是 1否）
    menuName: null, // 菜单名称
    menuType: "M", // 菜单类型（M目录 C菜单 F按钮）
    orderNum: null, // 显示排序
    parentId: 0, // 上级菜单
    path: null, // 路由地址
    perms: null, // 权限标识
    query: null, // 路由参数
    routeName: null, // 路由名称
    status: "0", // 菜单状态（0正常 1停用）
    systemCode: null, // 系统编码
    url: null, // 网关URL
    urlmatch: null, // 网关权限
    visible: "0" // 显示状态（0显示 1隐藏）
  },
  rules: {
    parentId: [{ required: true, message: "请选择上级菜单", trigger: "blur" }],
    orderNum: [{ required: true, message: "请输入排序", trigger: "blur" }],
    menuName: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
    path: [{ required: true, message: "请输入路由地址", trigger: "blur" }]
  }
});

const columns: PlusColumn[] = [
  {
    label: "上级菜单",
    prop: "parentId",
    colProps: { span: 24 },
    valueType: "tree-select",
    fieldProps: {
      placeholder: "请选择上级菜单",
      clearable: true,
      showSearch: true,
      checkStrictly: true,
      defaultExpandAll: false,
      style: { width: "100%" },
      data: computed(() => {
        return [
          { menuId: 0, menuName: "主类目", children: [...menuList.value] }
        ];
      }),
      // el-tree-select 组件属性
      props: {
        label: "menuName",
        value: "menuId",
        children: "children"
      }
    }
  },
  {
    label: "系统编码",
    prop: "systemCode",
    valueType: "select",
    colProps: { span: 24 },
    options: computed(() => systemList.value),
    fieldProps: {
      placeholder: "请输入系统编码",
      clearable: true
    }
  },
  {
    label: "菜单类型",
    prop: "menuType",
    valueType: "radio",
    colProps: { span: 24 },
    fieldProps: {
      placeholder: "请选择菜单类型",
      clearable: true,
      options: [
        { label: "目录", value: "M" },
        { label: "菜单", value: "C" },
        { label: "按钮", value: "F" }
      ]
    }
  },
  {
    label: "菜单图标",
    prop: "icon",
    colProps: { span: 12 },
    hideInForm: computed(() => form.value.menuType === "F")
  },
  {
    label: "显示排序",
    prop: "orderNum",
    valueType: "input-number",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入显示排序",
      style: { width: "100%" },
      min: 0
    }
  },
  {
    label: "菜单名称",
    prop: "menuName",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入菜单名称",
      clearable: true
    }
  },
  {
    label: "路由名称",
    prop: "routeName",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入路由名称",
      clearable: true
    },
    hideInForm: computed(() => form.value.menuType !== "C")
  },
  {
    label: "是否外链",
    prop: "isFrame",
    valueType: "radio",
    colProps: { span: 12 },
    fieldProps: {
      options: [
        { label: "是", value: "0" },
        { label: "否", value: "1" }
      ]
    },
    tooltip: "选择是外链则路由地址需要以`http(s)://`开头",
    hideInForm: computed(() => form.value.menuType === "F")
  },
  {
    label: "路由地址",
    prop: "path",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入路由地址",
      clearable: true
    },
    tooltip:
      "访问的路由地址，如：`role`，如外网地址需内链访问则以`http(s)://`开头",
    hideInForm: computed(() => form.value.menuType === "F")
  },
  {
    label: "组件路径",
    prop: "component",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入组件路径",
      clearable: true
    },
    tooltip: "访问的组件路径，如：`system/role/index`，默认在`views`目录下",
    hideInForm: computed(() => form.value.menuType !== "C")
  },
  {
    label: "权限字符",
    prop: "perms",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入权限标识",
      clearable: true
    },
    tooltip:
      "控制器中定义的权限字符，如：@PreAuthorize(`@ss.hasPermi('system:role:list')`)",
    hideInForm: computed(() => form.value.menuType === "M")
  },
  {
    label: "网关URL",
    prop: "url",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入URL",
      clearable: true
    }
  },
  {
    label: "网关权限",
    prop: "urlmatch",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入网关权限标识",
      clearable: true
    },
    tooltip: "控制器中定义的权限字符"
  },
  {
    label: "路由参数",
    prop: "query",
    colProps: { span: 12 },
    fieldProps: {
      placeholder: "请输入路由参数",
      clearable: true
    },
    tooltip: '访问路由的默认传递参数，如：`{"id": 1, "name": "ry"}`',
    hideInForm: computed(() => form.value.menuType !== "C")
  },
  {
    label: "是否缓存",
    prop: "isCache",
    valueType: "radio",
    colProps: { span: 12 },
    fieldProps: {
      options: [
        { label: "是", value: "0" },
        { label: "否", value: "1" }
      ]
    },
    tooltip: "选择是则会被`keep-alive`缓存，需要匹配组件的`name`和地址保持一致",
    hideInForm: computed(() => form.value.menuType !== "C")
  },
  {
    label: "显示状态",
    prop: "visible",
    valueType: "radio",
    colProps: { span: 12 },
    fieldProps: {
      options: [
        { label: "显示", value: "0" },
        { label: "隐藏", value: "1" }
      ]
    },
    tooltip: "选择隐藏则路由将不会出现在侧边栏，但仍然可以访问",
    hideInForm: computed(() => form.value.menuType === "F")
  },
  {
    label: "菜单状态",
    prop: "status",
    valueType: "radio",
    colProps: { span: 12 },
    fieldProps: {
      options: [
        { label: "正常", value: "0" },
        { label: "停用", value: "1" }
      ]
    },
    tooltip: "选择停用则路由将不会出现在侧边栏，也不能被访问"
  }
];

// 创建
const handleCreate = (): void => {
  form.value = {
    component: null, // 组件路径
    icon: "", // 菜单图标
    isCache: "0", // 是否缓存 （0缓存 1不缓存）
    isFrame: "1", // 是否外链 （0是 1否）
    menuName: null, // 菜单名称
    menuType: "M", // 菜单类型（M目录 C菜单 F按钮）
    orderNum: null, // 显示排序
    parentId: 0, // 上级菜单
    path: null, // 路由地址
    perms: null, // 权限标识
    query: null, // 路由参数
    routeName: null, // 路由名称
    status: "0", // 菜单状态（0正常 1停用）
    systemCode: null, // 系统编码
    url: null, // 网关URL
    urlmatch: null, // 网关权限
    visible: "0" // 显示状态（0显示 1隐藏）
  };
  state.isCreate = true;
  state.dialogVisible = true;
};

const handleSubmit = async (values: FieldValues) => {
  console.log(values, "Submit");
  confirmLoading.value = true;
  if (state.isCreate) {
    try {
      let params = form.value;
      let res = await addMenu(params);
      if (res.code === 200) {
        ElMessage.success("新增成功");
        confirmLoading.value = false;
        dialogVisible.value = false;
        refresh();
      } else {
        ElMessage.error(res.msg);
      }
    } finally {
      confirmLoading.value = false;
    }
  } else {
    // 编辑
    try {
      let params = form.value;
      let res = await updateMenu(params);
      if (res.code === 200) {
        ElMessage.success("修改成功");
        confirmLoading.value = false;
        dialogVisible.value = false;
        refresh();
      } else {
        ElMessage.error(res.msg);
      }
    } finally {
      confirmLoading.value = false;
    }
  }
};

const handleClose = () => {
  /*// 重置表单
  nextTick(() => {
    if (dialogForm.value) {
      dialogForm.value.formInstance.resetFields()
    }
  })*/
  console.log(dialogForm.value.formInstance);
  dialogForm.value.formInstance.resetFields();
};

// 权限
const perms = resolveDirective("perms");

buttons.value = [
  {
    // 修改
    text: "修改",
    code: "edit",
    // props v0.1.16 版本新增函数类型
    props: {
      type: "primary"
    },
    onClick(params) {
      getSystemMenuDetailById(params.row.menuId).then(res => {
        form.value = res.data;
        state.isCreate = false;
        state.dialogVisible = true;
      });
    },
    directives: [[perms, "system:menu:edit"]]
  },
  {
    // 新增
    text: "新增",
    code: "view",
    props: {
      type: "success"
    },
    onClick(params) {
      console.log("新增", params);
      form.value = {
        component: null, // 组件路径
        icon: "", // 菜单图标
        isCache: "0", // 是否缓存 （0缓存 1不缓存）
        isFrame: "1", // 是否外链 （0是 1否）
        menuName: null, // 菜单名称
        menuType: "M", // 菜单类型（M目录 C菜单 F按钮）
        orderNum: null, // 显示排序
        parentId: params.row.menuId, // 上级菜单
        path: null, // 路由地址
        perms: null, // 权限标识
        query: null, // 路由参数
        routeName: null, // 路由名称
        status: "0", // 菜单状态（0正常 1停用）
        systemCode: params.row.systemCode, // 系统编码
        url: null, // 网关URL
        urlmatch: null, // 网关权限
        visible: "0" // 显示状态（0显示 1隐藏）
      };
      state.isCreate = true;
      state.dialogVisible = true;
    },
    directives: [[perms, "system:menu:add"]]
  },
  {
    // 删除
    text: "删除",
    code: "delete",
    // props v0.1.16 版本新增计算属性支持
    props: computed(() => ({ type: "danger" })),
    confirm: {
      options: {
        draggable: true,
        message: "确定删除此数据吗？"
      }
    },
    onConfirm: async params => {
      try {
        let res = await deleteMenu(params.row.menuId);
        if (res.code === 200) {
          ElMessage.success("删除成功");
          refresh();
        } else {
          ElMessage.error(res.msg);
        }
      } catch (e) {
        ElMessage.error("删除失败");
      }
    },
    directives: [[perms, "system:menu:remove"]]
  }
];

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