<!-- setup 无法设置组件名称，组件名称keepAlive必须 -->
<script lang="ts">
export default {
  name: "user"
};
</script>

<script setup lang='ts'>
// Vue依赖
import {
  reactive,
  ref,
  watchEffect,
  onMounted,
  getCurrentInstance,
  toRefs
} from "vue";

// 导入API
import {
  listUsersPage,
  getUserDetail,
  deleteUsers,
  addUser,
  updateUser,
  updateUserPart,
  downloadTemplate,
  exportUser,
  importUser
} from "@/api/system/user";
import { listSelectDepartments } from "@/api/system/dept";
import { listRoles } from "@/api/system/role";

// 组件依赖
import { ElMessage, ElMessageBox, ElTree, ElForm, UploadFile } from "element-plus";
import {
  Search,
  Plus,
  Edit,
  Refresh,
  Delete,
  Lock,
  Download,
  Top,
  UploadFilled
} from "@element-plus/icons-vue";
import {
  UserItem,
  UserQueryParam,
  UserFormData,
  Option,
  RoleItem,
  Dialog,
  UserImportFormData
} from "@/types";

// DOM元素的引用声明定义 ，变量名和DOM的ref属性值一致
const deptTreeRef = ref(ElTree);  // 部门树
const queryFormRef = ref(ElForm); // 部门树
const dataFormRef = ref(ElForm); // 部门树
const importFormRef = ref(ElForm); // 导入

const { proxy }: any = getCurrentInstance();

const state = reactive({
  // 遮罩层
  loading: true,
  // 选中数组
  ids: [],
  // 非单个禁用
  single: true,
  // 非多个禁用
  multiple: true,
  // 总条数
  total: 0,
  // 用户分页数据
  userList: [] as UserItem[],
  // 弹窗属性
  dialog: {
    visible: false,
  } as Dialog,
  deptName: undefined,
  // 部门树选项
  deptOptions: [] as Option[],
  // 部门名称
  // 性别状态字典
  genderOptions: [] as any[],
  // 角色选项
  roleOptions: [] as RoleItem[],
  // 表单参数
  formData: {} as UserFormData,
  // 查询参数
  queryParams: {
    pageNum: 1,
    pageSize: 10,
  } as UserQueryParam,
  // 表单校验
  rules: {
    username: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
    nickname: [
      { required: true, message: "用户昵称不能为空", trigger: "blur" },
    ],
    deptId: [{ required: true, message: "归属部门不能为空", trigger: "blur" }],
    roleIds: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
    email: [
      {
        pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
        message: "请输入正确的邮箱地址",
        trigger: "blur",
      },
    ],
    mobile: [
      {
        pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
        message: "请输入正确的手机号码",
        trigger: "blur",
      },
    ],

  },

  importDialog: {
    title: '用户导出',
    visible: false,
  } as Dialog,
  importFormData: {} as UserImportFormData,
  excelFile: undefined as any,
  excelFilelist: [] as File[]
});

const {
  loading,
  multiple,
  queryParams,
  userList,
  total,
  dialog,
  formData,
  rules,
  deptName,
  deptOptions,
  roleOptions,
  importDialog,
  importFormData,
  excelFilelist
} = toRefs(state);

/**
 * 部门筛选
 */
watchEffect(
  () => {
    deptTreeRef.value.filter(state.deptName);
  },
  {
    flush: "post", // watchEffect会在DOM挂载或者更新之前就会触发，此属性控制在DOM元素更新后运行
  }
);

/**
 * 部门列表筛选
 */
function filterDeptNode(value: string, data: any) {
  if (!value) {
    return true;
  }
  return data.label.indexOf(value) !== -1;
}

/**
 * 部门树节点点击事件
 */
function handleDeptNodeClick(data: { [key: string]: any }) {
  state.queryParams.deptId = data.value;
  handleQuery();
}

/**
 * 加载角色数据
 */
async function loadRoleOptions() {
  listRoles().then((response) => {
    state.roleOptions = response.data;
  });
}

/**
 * 用户状态修改
 */
function handleStatusChange(row: { [key: string]: any }) {
  const text = row.status === 1 ? "启用" : "停用";
  ElMessageBox.confirm(
    "确认要" + text + "" + row.username + "用户吗?",
    "警告",
    {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }
  )
    .then(() => {
      return updateUserPart(row.id, { status: row.status });
    })
    .then(() => {
      ElMessage.success(text + "成功");
    })
    .catch(() => {
      row.status = row.status === 1 ? 0 : 1;
    });
}

/**
 * 用户查询
 **/
function handleQuery() {
  state.loading = true;
  listUsersPage(state.queryParams).then(({ data }) => {
    state.userList = data.list;
    state.total = data.total;
    state.loading = false;
  });
}

/**
 * 重置查询
 */
function resetQuery() {
  queryFormRef.value.resetFields();
  handleQuery();
}

/**
 * 表格行选中事件
 */
function handleSelectionChange(selection: any) {
  state.ids = selection.map((item: any) => item.id);
  state.single = selection.length !== 1;
  state.multiple = !selection.length;
}

/**
 * 密码重置
 */
function resetPassword(row: { [key: string]: any }) {
  ElMessageBox.prompt(
    "请输入用户「" + row.username + "」的新密码",
    "重置密码",
    {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
    }
  )
    .then(({ value }) => {
      if (!value) {
        ElMessage.warning("请输入新密码");
        return false;
      }
      updateUserPart(row.id, {
        password: value,
      }).then(() => {
        ElMessage.success("修改成功，新密码是：" + value);
      });
    })
    .catch(() => {});
}

/**
 * 添加用户
 **/
async function handleAdd() {
  await loadDeptOptions();
  await loadRoleOptions();
  state.dialog = {
    title: "添加用户",
    visible: true,
  };
}

/**
 * 修改用户
 **/
async function handleUpdate(row: { [key: string]: any }) {
  const userId = row.id || state.ids;
  await loadDeptOptions();
  await loadRoleOptions();
  state.dialog = {
    title: "修改用户",
    visible: true,
  };
  getUserDetail(userId).then(({ data }) => {
    state.formData = data;
  });
}

/**
 * 表单提交
 */
function submitForm() {
  dataFormRef.value.validate((valid: any) => {
    if (valid) {
      const userId = state.formData.id;
      if (userId) {
        updateUser(userId, state.formData).then(() => {
          ElMessage.success("修改用户成功");
          cancel()
          handleQuery();
        });
      } else {
        addUser(state.formData).then(() => {
          ElMessage.success("新增用户成功");
          cancel()
          handleQuery();
        });
      }
    }
  });
}

/**
 * 删除用户
 */
function handleDelete(row: { [key: string]: any }) {
  const userIds = row.id || state.ids.join(",");
  ElMessageBox.confirm(
    "是否确认删除用户编号为「" + userIds + "」的数据项?",
    "警告",
    {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }
  )
    .then(function () {
      deleteUsers(userIds).then(() => {
        ElMessage.success("删除成功");
        handleQuery();
      });
    })
    .catch(() => ElMessage.info("已取消删除"));
}

/**
 * 取消
 */
function cancel() {
  state.dialog.visible = false;
  state.formData.id = undefined;
  dataFormRef.value.resetFields();
}

/**
 * 加载部门
 */
async function loadDeptOptions() {
  listSelectDepartments().then((response) => {
    state.deptOptions = response.data;
  });
}

/**
 * 加载性别字典
 */
function loadGenderOptions() {
  proxy.$listDictsByCode("gender").then((response: any) => {
    state.genderOptions = response?.data;
  });
}

/**
 * 下载用户导入模板
 */
function handleDownloadTemplate() {
  downloadTemplate().then((response: any) => {
    const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' })
    const a = document.createElement('a')
    const href = window.URL.createObjectURL(blob) // 下载链接
    a.href = href
    a.download = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); // 获取后台设置的文件名称
    document.body.appendChild(a)
    a.click() // 点击下载
    document.body.removeChild(a) // 下载完成移除元素
    window.URL.revokeObjectURL(href) // 释放掉blob对象
  })
}

/**
 * 导入用户表单弹窗
 */
async function showImportDialog() {
  await loadDeptOptions();
  await loadRoleOptions();
  state.importDialog.visible = true
}

// Excel文件上传
function handleExcelChange(file: UploadFile) {
  if (!/\.(xlsx|xls|XLSX|XLS)$/.test(file.name)) {
    ElMessage.warning('上传Excel只能为xlsx、xls格式');
    state.excelFile = undefined
    state.excelFilelist = []
    return false;
  }
  state.excelFile = file.raw
}

function submitImportForm() {
  importFormRef.value.validate((valid: any) => {
    if (valid) {
      if (!state.excelFile) {
        ElMessage.warning('上传Excel文件不能为空');
        return false
      }

      const deptId = state.importFormData.deptId
      const roleIds = state.importFormData.roleIds.join(',')
      importUser(deptId, roleIds, state.excelFile).then((response) => {
        ElMessage.success(response.data);
        closeImportDialog();
        handleQuery();
      })
    }
  });
}

/**
 * 关闭导入弹窗
 */
function closeImportDialog() {
  state.importDialog.visible = false
  state.excelFile = undefined
  state.excelFilelist = []
  importFormRef.value.resetFields();
}

/**
 * 导出用户
 */
function handleExport() {
  exportUser(queryParams.value).then((response: any) => {
    const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' })
    const a = document.createElement('a')
    const href = window.URL.createObjectURL(blob) // 下载的链接
    a.href = href
    a.download = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); // 获取后台设置的文件名称
    document.body.appendChild(a)
    a.click() // 点击导出
    document.body.removeChild(a) // 下载完成移除元素
    window.URL.revokeObjectURL(href) // 释放掉blob对象
  })
}

/**
 * 初始化数据
 */
function loadData() {
  // 初始化性别字典
  loadGenderOptions();
  // 初始化部门
  loadDeptOptions();
  // 初始化用户列表数据
  handleQuery();
}

onMounted(() => {
  loadData();
});
</script>
<template>
  <div class="app-container">
    <el-row :gutter="20">
      <!-- 部门树 -->
      <el-col :span="4" :xs="24">
        <el-card class="box-card">
          <el-input v-model="deptName" placeholder="部门名称" clearable :prefix-icon="Search" style="margin-bottom: 20px" />
          <el-tree ref="deptTreeRef" :data="deptOptions" :props="{ children: 'children', label: 'label', disabled: '' }"
            :expand-on-click-node="false" :filter-node-method="filterDeptNode" default-expand-all
            @node-click="handleDeptNodeClick"></el-tree>
        </el-card>
      </el-col>

      <!-- 用户数据 -->
      <el-col :span="20" :xs="24">
        <el-card class="box-card">
          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
            <el-row>
              <el-col :span="18" :xs="24" >
                <el-form-item>
                  <el-button type="success" :icon="Plus" @click="handleAdd" v-hasPerm="['sys:user:add']">新增</el-button>
                  <el-button type="danger" :icon="Delete" :disabled="multiple" @click="handleDelete"
                    v-hasPerm="['sys:user:delete']">删除</el-button>
                </el-form-item>

                <el-form-item prop="keywords">
                  <el-input v-model="queryParams.keywords" placeholder="用户名/昵称/手机号" clearable style="width: 200px"
                    @keyup.enter="handleQuery" />
                </el-form-item>

                <el-form-item prop="status">
                  <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 200px">
                    <el-option label="正常" value="1" />
                    <el-option label="停用" value="0" />
                  </el-select>
                </el-form-item>

                <el-form-item>
                  <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
                  <el-button :icon="Refresh" @click="resetQuery">重置</el-button>
                </el-form-item>
              </el-col>

              <el-col :span="6" :xs="24"  style="text-align: right;">
                <el-form-item>
                  <el-dropdown split-button style="margin-left: 12px;">
                    导入
                    <template #dropdown>
                      <el-dropdown-menu>
                        <el-dropdown-item :icon="Download" @click="handleDownloadTemplate">下载模板</el-dropdown-item>
                        <el-dropdown-item :icon="Top" @click="showImportDialog">导入数据</el-dropdown-item>
                      </el-dropdown-menu>
                    </template>
                  </el-dropdown>
                  <el-button :icon="Download" style="margin-left: 12px;" @click="handleExport">导出</el-button>
                </el-form-item>
              </el-col>
            </el-row>
          </el-form>

          <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="50" align="center" />
            <el-table-column key="id" label="用户编号" align="center" prop="id" />
            <el-table-column key="username" label="用户名" align="center" prop="username" />
            <el-table-column label="用户昵称" align="center" prop="nickname" />

            <el-table-column label="性别" align="center" prop="gender" />

            <el-table-column label="部门" align="center" prop="deptName" />
            <el-table-column label="手机号码" align="center" prop="mobile" width="120" />

            <el-table-column label="状态" align="center" prop="status">
              <template #default="scope">
                <el-switch v-model="scope.row.status" :inactive-value="0" :active-value="1"
                  @change="handleStatusChange(scope.row)" />
              </template>
            </el-table-column>
            <el-table-column label="创建时间" align="center" prop="gmtCreate" width="180"></el-table-column>
            <el-table-column label="操作" align="center" width="150">
              <template #default="scope">
                <el-button type="primary" :icon="Edit" circle plain @click="handleUpdate(scope.row)"
                  v-hasPerm="['sys:user:edit']"></el-button>
                <el-button type="danger" :icon="Delete" circle plain @click="handleDelete(scope.row)"
                  v-hasPerm="['sys:user:delete']"></el-button>
                <el-button type="warning" :icon="Lock" circle plain @click="resetPassword(scope.row)"></el-button>
              </template>
            </el-table-column>
          </el-table>

          <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
            v-model:limit="queryParams.pageSize" @pagination="handleQuery" />
        </el-card>
      </el-col>
    </el-row>

    <!-- 添加或修改参数配置对话框 -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="cancel">
      <el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">
        <el-form-item label="用户名" prop="username">
          <el-input :readonly="!!formData.id" v-model="formData.username" placeholder="请输入用户名" />
        </el-form-item>

        <el-form-item label="用户昵称" prop="nickname">
          <el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
        </el-form-item>

        <el-form-item label="所属部门" prop="deptId">
           <el-tree-select v-model="formData.deptId" placeholder="请选择所属部门" :data="deptOptions" filterable check-strictly  />
        </el-form-item>

        <el-form-item label="手机号码" prop="mobile">
          <el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
        </el-form-item>

        <el-form-item label="邮箱" prop="email">
          <el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
        </el-form-item>

        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="formData.status">
            <el-radio :label="1">正常</el-radio>
            <el-radio :label="0">禁用</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="用户性别" prop="gender">
          <el-select v-model="formData.gender" placeholder="请选择">
            <el-option label="未知" :value="0" />
            <el-option label="男" :value="1" />
            <el-option label="女" :value="2" />
          </el-select>
        </el-form-item>

        <el-form-item label="角色" prop="roleIds">
          <el-select v-model="formData.roleIds" multiple placeholder="请选择">
            <el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>

    <el-dialog :title="importDialog.title" v-model="importDialog.visible" width="600px" append-to-body
      @close="closeImportDialog">
      <el-form ref="importFormRef" :model="importFormData" :rules="rules" label-width="80px">
        <el-form-item label="部门" prop="deptId">
         <el-tree-select v-model="formData.deptId" placeholder="请选择部门" :data="deptOptions" filterable check-strictly  />
        </el-form-item>

        <el-form-item label="角色" prop="roleIds">
          <el-select v-model="importFormData.roleIds" multiple placeholder="请选择">
            <el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
          </el-select>
        </el-form-item>

        <el-form-item label="Excel">
          <el-upload class="upload-demo" action="" drag :auto-upload="false"
            accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
            :file-list="excelFilelist" :on-change="handleExcelChange" :limit="1">
            <el-icon class="el-icon--upload">
              <upload-filled />
            </el-icon>
            <div class="el-upload__text">
              将文件拖到此处，或
              <em>点击上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">xls/xlsx files </div>
            </template>
          </el-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitImportForm">确 定</el-button>
          <el-button @click="closeImportDialog">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

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