<script setup lang="ts">
import {
  ref,
  unref,
  watch,
  reactive,
  computed,
  onMounted,
  nextTick,
  onUnmounted,
  getCurrentInstance,
  onBeforeMount,
  PropType,
  shallowRef,
} from "vue";

import { Search } from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox, TableColumnCtx } from "element-plus";
import { defineAsyncComponent, AsyncComponentLoader } from "vue";
import {
  ButtonCustomConfig,
  ConditionalType,
  Dialog,
  intTableData,
  TableColumn,
  TableColumnEdit,
  TableColumnSearch,
  TableConfig,
} from "./hTable";
import hTableEdit from "./hTableEdit.vue";
import { hTableAPI } from "@/api/hTable";
import { getenum } from "@/api/enum";
//按钮权限
import { hasPerms } from "@/utils/auth";
const modules = import.meta.glob("/src/views/**/*.{vue,tsx}");
const props = defineProps({
  //** 传入的表单数据 */
  Row: {
    type: Object as PropType<any>,
    default: () => ({}),
  },
  tableConfig: {
    type: Object as PropType<TableConfig>,
    default: () => ({}),
  },
});

const table = ref<TableConfig>(props.tableConfig);
const tableShowColumn = ref<Record<string, TableColumn>>();
onBeforeMount(() => {
  /* 初始化系统配置 */
  nextTick(async () => {
    intdata();
    //过滤无法显示的列
    tableShowColumn.value = Object.fromEntries(
      Object.entries(table.value.column).filter(([_, s]) => s.show)
    );

    Api = new hTableAPI(table.value.apiUrl);
    init.value = true;
    tableShow.value = true;
    await fetchInitData();
    fetchPagedData();
  });
});
onMounted(() => {
  nextTick(async () => {
    // appStyle();
  });
});
onUnmounted(() => {});
// defineExpose({
//   initTable
// });
const tableShow = ref(false);
let Api: hTableAPI = null;

const init = ref(false);
const tableHeight = ref(0);
let defaultOrderBy = null;

const dialog = ref<Dialog>({
  visible: false,
  close: true,
  title: "",
  width: "500px", // 弹出层宽度
  custom: {
    height: "85vh",
    data: [],
    custom: {},
    component: null, //自定义弹窗的路径
    visible: false, // 弹出层是否显示
  },
  edit: {
    id: -1,
    title: "", // 弹出层title
    visible: false, // 弹出层是否显示
  },
});

const appB = ref<HTMLElement>(null);
const appB_S = ref<HTMLElement>(null);
function appStyle() {
  if (tableHeight.value !== 0) return;
  tableHeight.value =
    appB.value.parentElement.parentElement.offsetHeight -
    145 -
    appB_S.value.offsetHeight +
    0;
  return tableHeight;
}

function intdata() {
  intTableData(table.value);
}

function rowKeyFun(row) {
  return row.customId;
}
function execute(obj, scope, btn) {
  if (Object.prototype.toString.call(obj) === "[object Function]") return obj(scope, btn);
  return eval(obj);
}

function getOperationColumnWidth() {
  let hFontSize = getComputedStyle(window.document.documentElement)["font-size"].replace(
    "px",
    ""
  );
  let defWidth = 10 + 2 + 30;

  let width = eval(
    table.value.operationColumnData
      .filter((s) => !s.topBtn && s.show)
      .map((s) => defWidth + s.label.length * (hFontSize || 16))
      .join("+")
  );
  width = width < 100 ? 100 : width;
  width = width > 320 ? 320 : width;
  return width + "px";
}
function getbtnClick(obj, row) {
  row = row ? [row] : table.value.selectRows;
  if (obj.btnType === "add") {
    return handleAdd();
  } else if (obj.btnType === "edit") {
    return handleEdit(obj, row);
  } else if (obj.btnType === "del") {
    return handleDelete(obj, row);
  } else if (obj.btnType === "custom") {
    return handleCustom(obj, row, obj.custom);
  } else {
    return obj.click(obj, row, handleReloadPaged);
  }
}
function handleAdd() {
  dialog.value.edit.id = -1;
  dialog.value.title = "添加";
  dialog.value.custom.visible = false;
  dialog.value.edit.visible = true;
  dialog.value.visible = true;
  dialog.value.width = "500px";

  dialog.value.edit.row = null;
  dialog.value.edit.tagData = null;
}
function handleEdit(obj, row) {
  dialog.value.edit.id = row[0].id;
  dialog.value.edit.row = row[0];
  dialog.value.edit.tagData = obj.tagData;
  dialog.value.title = obj.label || "修改";
  dialog.value.edit.visible = true;
  dialog.value.custom.visible = false;
  dialog.value.visible = true;
  dialog.value.width = "500px";
}
async function handleCustom(obj, row, custom: ButtonCustomConfig) {
  dialog.value.custom.data = row || [];
  dialog.value.custom.custom = custom || [];
  // 异步加载组件
  // dialog.value.custom.component = defineAsyncComponent({
  //   loader: () => import(/* @vite-ignore */ `../../views/${custom.src}.vue`),
  // });
  let r = shallowRef(null);
  const module: any = await modules[`/src/views/${custom.src}.vue`](); //import(`@/views/${custom.src}.vue`);
  r.value = module.default;
  dialog.value.custom.component = r;

  dialog.value.width = custom.width;
  dialog.value.title = custom.title;
  dialog.value.edit.visible = false;
  dialog.value.custom.visible = true;
  if (custom.height !== undefined) {
    dialog.value.custom.height = custom.height;
  } else {
    dialog.value.custom.height = "600px";
  }
  dialog.value.visible = true;
}
// 删除
function handleDelete(obj, row) {
  if (row.length === 0) {
    ElMessage.warning("未勾选记录");
    return;
  }
  const ids: any[] = [];
  row.forEach((it) => {
    ids.push(it.id);
  });
  ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?")
    .then(() => {
      Api.delete(ids).then((res) => {
        if (res.code === 200) {
          handleReloadPaged();
          ElMessage.success("删除成功");
        } else {
          ElMessage.error(res.message);
        }
      });
    })
    .catch(() => {
      ElMessage.info("取消删除");
    });
}
// 页面完成回调
function handleAddCallback() {
  Api.url = table.value.apiUrl;
  dialog.value.visible = false;
  dialog.value.edit.visible = false;
  dialog.value.custom.visible = false;

  handleResetForm();
  handleReloadPaged();
}
function handleResetForm() {
  for (const key in table.value.column) {
    let item = table.value.column[key];
    if (Array.isArray(item.edit.valueE)) {
      item.edit.valueE = [];
    } else if (typeof item.edit.valueE === "number") {
      item.edit.valueE = "";
    } else if (typeof item.edit.valueE === "boolean") {
    } else {
      item.edit.valueE = "";
    }
  }
}
function tableClose() {
  handleAddCallback();
}
function pageSizeChange(o) {
  table.value.search.PageSize = o;
  fetchPagedData();
}
function pageIndexChange(o) {
  table.value.search.PageIndex = o - 1;
  fetchPagedData();
}

/**
 * 排序变化时
 * @param selection
 */
function sortChange(data: { column: TableColumnCtx<any>; prop: string; order: any }) {
  if (data.order == undefined) {
    table.value.search.OrderBy = defaultOrderBy.OrderBy;
    table.value.search.OrderByType = defaultOrderBy.OrderByType;
  } else {
    table.value.search.OrderBy = data.prop;
    table.value.search.OrderByType = data.order === "ascending" ? 1 : 0;
  }
  handleReloadPaged();
}
// 勾选
function handleSelectionChange(selection) {
  console.log("selection-change", selection);

  table.value.selectRows = selection;
}
function searchReload() {
  for (let name in table.value.column) {
    if (
      !table.value.column[name].search ||
      table.value.column[name].search.value === undefined ||
      table.value.column[name].search.value === null ||
      table.value.column[name].search.value === ""
    ) {
      continue;
    }
    table.value.column[name].search.value = "";
  }
}
// 查询
function handleReloadPaged(reload = true) {
  if (defaultOrderBy == null) {
    defaultOrderBy = {
      OrderBy: table.value.search.OrderBy,
      OrderByType: table.value.search.OrderByType,
    };
  }
  if (table.value.search === undefined || table.value.search.PageIndex === undefined) {
    table.value.search.PageIndex = 0;
    table.value.search.PageSize = 20;
  }
  table.value.search.Conditions = [];
  for (let name in table.value.column) {
    if (
      !table.value.column[name].search ||
      table.value.column[name].search.value === undefined ||
      table.value.column[name].search.value === null ||
      table.value.column[name].search.value === ""
    ) {
      continue;
    }
    let data: any = { ConditionalType: 0 };
    if (table.value.column[name].type === "datetime") {
      // data.CSharpTypeName = 'DateTime'
      data.ConditionalType = ConditionalType.LikeLeft; // '2023-10-07%'
    } else if (table.value.column[name].type === "switch") {
      data.CSharpTypeName = "Boolean";
    } else if (table.value.column[name].type === "string") {
      data.ConditionalType = ConditionalType.Like;
    } else data.ConditionalType = ConditionalType.Equal;

    data.FieldName = name.charAt(0).toUpperCase() + name.slice(1);
    data.FieldValue = table.value.column[name].search.value.toString();

    if (table.value.column[name].search.searchType != undefined) {
      let v: number = table.value.column[name].search.searchType || 0;
      data.ConditionalType = v;
    }
    table.value.search.Conditions.push(data);
  }

  if (!reload && table.value.search.Conditions.length > 0) {
    table.value.search.PageIndex = 0;
  }
  if (table.value.searchCallback) {
    table.value.searchCallback(table.value.search);
  }
  fetchPagedData();
}
// 加载前置数据（如查询条件的下拉选择数据）
async function fetchInitData() {
  setTimeout(() => {
    init.value = true;
    appStyle();
  }, 0);
}
function showTips(item, value) {
  if (item.width == undefined) {
    return false;
  }
  return getByteLen(item.custom(value) + "") * 16 < item.width.replace("px", "");
}
function getByteLen(str) {
  let len = 0;
  for (let i = 0; i < str.length; i++) {
    str.charCodeAt(i) < 256 ? (len += 1) : (len += 2);
  }
  return len;
}
// 加载分页数据
function fetchPagedData() {
  for (const iterator of table.value.search.defaultConditions) {
    if (!iterator) continue;
    if (!table.value.search.Conditions.find((s) => s == iterator)) {
      table.value.search.Conditions.push(iterator);
    }
  }
  Api.PageList(table.value.search).then((res) => {
    if (res.code === 200) {
      table.value.data = res.data.data.map((s, i) => {
        return { ...s, customId: i };
      });
      table.value.pageData = res.data;
    }
  });
}
</script>

<template>
  <div v-if="tableShow" ref="appB" class="app-container container-h">
    <div ref="appB_S" class="search-container1">
      <!-- 搜索项目 -->
      <el-form v-if="table.search.show" :inline="true" :model="table.search">
        <el-form-item v-for="(o, n, i) in table.column" v-show="o.search.yes" :key="i">
          <el-date-picker
            v-if="o.type.trim() == 'datetime'"
            v-model="o.search.value as Date"
            type="date"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD"
            :placeholder="o.label"
            style="width: 100%"
          />
          <el-select
            v-else-if="o.type.trim() == 'dropdown'"
            v-model="o.search.value"
            :multiple="o.edit.multiple"
            clearable
            filterable
            :placeholder="o.label"
            style="width: 100%"
          >
            <el-option
              v-for="item in o.setting.datasource"
              :key="item.value"
              autocomplete="off"
              :label="item[o.setting.maplabel]"
              :value="item[o.setting.mapValue]"
            />
          </el-select>
          <el-select
            v-else-if="o.type.trim() == 'switch'"
            v-model="o.search.value"
            clearable
            filterable
            :placeholder="o.label"
            style="width: 100%"
          >
            <el-option autocomplete="off" :label="'启用'" :value="true" />
            <el-option autocomplete="off" :label="'禁用'" :value="false" />
          </el-select>
          <div v-else-if="o.type.trim() == 'img'" v-show="false" />
          <el-input v-else v-model="o.search.value as string" :placeholder="o.label" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" :icon="Search" @click="handleReloadPaged(false)"
            >查询</el-button
          >

          <el-button type="default" @click="searchReload()">重置</el-button>
        </el-form-item>
      </el-form>
    </div>

    <div v-if="table.operationTop" class="toolbar-container">
      <!-- 头部按钮组 -->
      <el-button
        v-for="(e, i) in table.operationColumnData.filter(
          (s) => s.topBtn && hasPerms(s.perms)
        )"
        v-show="execute(e['show'], {}, e)"
        :key="i"
        :type="e.btnStyle || 'info'"
        @click="getbtnClick(e, null)"
        >{{ e.label }}</el-button
      >
    </div>
    <el-table
      v-if="init"
      fit
      :height="tableHeight"
      :data="table.data"
      :border="table.border"
      :highlight-current-row="true"
      :row-key="rowKeyFun"
      @selection-change="handleSelectionChange"
      @sort-change="sortChange"
      @expand-change="table.expandChange"
    >
      <el-table-column v-if="table.selectColumn" type="selection" width="40" />
      <el-table-column
        v-if="
          table.operationColumn &&
          table.operationColumnData.filter((s) => !s.topBtn).length > 0
        "
        :fixed="table.operationColumnFixed"
        label="操作"
        :width="getOperationColumnWidth()"
      >
        <template v-slot="scope">
          <div class="columnTemplate">
            <el-button
              v-for="(e, i) in table.operationColumnData.filter(
                (s) => !s.topBtn && hasPerms(s.perms)
              )"
              v-show="execute(e['show'], scope, e)"
              :key="i"
              class="btn"
              text
              :type="e.btnStyle || 'primary'"
              @click="getbtnClick(e, scope.row)"
            >
              {{ e.label }}</el-button
            >
          </div>
          <!-- 行内按钮组 -->
        </template>
      </el-table-column>

      <!-- 拓展列 -->
      <el-table-column v-if="table.expandColumn" type="expand">
        <template #default="props">
          <slot name="expandSlot" :props="props"></slot>
        </template>
      </el-table-column>

      <el-table-column
        v-for="(item, name, i) of tableShowColumn"
        :key="i"
        :prop="name"
        :label="item.label"
        :width="item.width"
        :fixed="item.fixed"
        :sortable="item.search.sort ? `custom` : false"
      >
        <template v-slot="scope">
          <div class="columnTemplate">
            <!-- 暂未实现 -->
            <div v-if="item.type.trim() == 'math'">
              {{ item.custom(scope.row) }}
            </div>
            <el-image
              v-else-if="item.type.trim() == 'img'"
              style="width: 300px; height: 100px"
              fit="fill"
              :src="item.setting.imgUrl(scope.row[name], scope.row)[0]"
              :preview-src-list="
                Array.from(item.setting.imgUrl(scope.row[name], scope.row))
              "
            >
              <template v-slot:error>
                <div class="image-slot">
                  {{ item.setting.imgUrl(scope.row[name], scope.row) }}
                </div>
              </template>
            </el-image>
            <el-tooltip
              v-else-if="item.type.trim() != 'img'"
              popper-class="maxWidth600px"
              :disabled="showTips(item, scope.row)"
              :content="item.custom(scope.row) + ''"
              placement="top"
              effect="light"
            >
              <div class="tab_tip" :style="{ width: item.width }">
                {{ item.custom(scope.row) }}
              </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <div
      v-if="table.search.showPage"
      style="
        padding-top: 15px;
        display: flex;
        align-items: center;
        justify-content: center;
      "
    >
      <el-pagination
        :current-page="table.search.PageIndex + 1"
        :page-sizes="[20, 40, 80, 100]"
        :page-size="table.search.PageSize"
        layout="prev, pager, next,sizes, total"
        :total="table.pageData.total"
        @size-change="pageSizeChange"
        @current-change="pageIndexChange"
      />
    </div>

    <div class="dialog-container">
      <el-dialog
        v-if="dialog.visible"
        v-model="dialog.visible"
        :class="dialog.title ? '' : 'noHeader'"
        :title="dialog.title"
        :width="dialog.width"
        :close-on-click-modal="false"
        :close-on-press-escape="dialog.close"
        :before-close="tableClose"
        class="max-w-[95vw] overflow-x-auto"
        append-to-body
      >
        <hTableEdit
          v-if="dialog.edit.visible"
          :id="dialog.edit.id"
          :tableData="table"
          :row="dialog.edit.row"
          :tagData="dialog.edit.tagData"
          @handlePagedCallback="handleAddCallback"
        />
        <component
          :is="dialog.custom.component"
          v-if="dialog.custom.visible"
          :style="{ height: 'calc( ' + dialog.custom.height + ' - 84px )' }"
          :iscomponent="true"
          :custom="dialog.custom.custom"
          :CancelCallback="handleAddCallback"
          :data="dialog.custom.data"
          @handlePagedCallback="handleAddCallback"
        />
      </el-dialog>
    </div>
  </div>
</template>

<style scoped>
.columnTemplate .btn {
  margin-left: 0 !important;
}

.columnTemplate {
  display: flex;
  flex-direction: row;
  flex-flow: row wrap;
  gap: 5px;
  place-content: flex-start flex-start;
  align-items: center;
  -webkit-box-orient: horizontal;
  -webkit-box-direction: normal;
}

.sty .tab_tip {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.toolbar-container {
  padding-bottom: 5px;
}

.maxWidth600px {
  max-width: 600px;
}
</style>
