|
@@ -1,142 +1,249 @@
|
|
|
-<template>
|
|
|
- <fs-page>
|
|
|
- <el-row class="mx-2">
|
|
|
- <el-col xs="24" :sm="8" :md="6" :lg="4" :xl="4" class="p-1">
|
|
|
- <el-card :body-style="{ height: '100%' }">
|
|
|
- <p class="font-mono font-black text-center text-xl pb-5">
|
|
|
- 部门列表
|
|
|
- <el-tooltip effect="dark" :content="content" placement="right">
|
|
|
- <el-icon>
|
|
|
- <QuestionFilled />
|
|
|
- </el-icon>
|
|
|
- </el-tooltip>
|
|
|
- </p>
|
|
|
- <el-input v-model="filterText" :placeholder="placeholder" />
|
|
|
- <el-tree ref="treeRef" class="font-mono font-bold leading-6 text-7xl" :data="data" :props="treeProps"
|
|
|
- :filter-node-method="filterNode" icon="ArrowRightBold" :indent="12" @node-click="onTreeNodeClick">
|
|
|
- <template #default="{ node, data }">
|
|
|
- <span class="text-center font-black font-normal">{{ node.label }}</span>
|
|
|
- </template>
|
|
|
- </el-tree>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- <el-col xs="24" :sm="16" :md="18" :lg="20" :xl="20" class="p-1">
|
|
|
- <el-card :body-style="{ height: '100%' }">
|
|
|
- <fs-crud ref="crudRef" v-bind="crudBinding">
|
|
|
- <template #actionbar-right>
|
|
|
- <importExcel api="api/system/user/">导入 </importExcel>
|
|
|
- </template>
|
|
|
- </fs-crud>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- </fs-page>
|
|
|
-</template>
|
|
|
-
|
|
|
<script lang="ts" setup name="user">
|
|
|
-import { useExpose, useCrud } from '@fast-crud/fast-crud';
|
|
|
+import { useCrud, useExpose } from '@fast-crud/fast-crud';
|
|
|
import { createCrudOptions } from './crud';
|
|
|
import * as api from './api';
|
|
|
+import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
|
|
import { ElTree } from 'element-plus';
|
|
|
-import { ref, onMounted, watch, toRaw } from 'vue';
|
|
|
+import { onMounted, reactive, ref, toRaw, watch } from 'vue';
|
|
|
import XEUtils from 'xe-utils';
|
|
|
-import importExcel from '/@/components/importExcel/index.vue'
|
|
|
+import importExcel from '/@/components/importExcel/index.vue';
|
|
|
+
|
|
|
+const crudRef = ref(); // crud组件的ref
|
|
|
+const crudBinding = ref(); // crud 配置的ref
|
|
|
+const { crudExpose } = useExpose({ crudRef, crudBinding }); // 暴露的方法
|
|
|
+const { crudOptions, dialogVisible, resetId } = createCrudOptions({ crudExpose }); // 你的crud配置
|
|
|
+const { resetCrudOptions } = useCrud({ crudExpose, crudOptions }); // 初始化crud配置
|
|
|
|
|
|
interface Tree {
|
|
|
- id: number;
|
|
|
- name: string;
|
|
|
- status: boolean;
|
|
|
- children?: Tree[];
|
|
|
+ id: number;
|
|
|
+ name: string;
|
|
|
+ status: boolean;
|
|
|
+ children?: Tree[];
|
|
|
}
|
|
|
|
|
|
interface APIResponseData {
|
|
|
- code?: number;
|
|
|
- data: [];
|
|
|
- msg?: string;
|
|
|
+ code?: number;
|
|
|
+ data: [];
|
|
|
+ msg?: string;
|
|
|
}
|
|
|
|
|
|
// 引入组件
|
|
|
const placeholder = ref('请输入部门名称');
|
|
|
const filterText = ref('');
|
|
|
const treeRef = ref<InstanceType<typeof ElTree>>();
|
|
|
-
|
|
|
const treeProps = {
|
|
|
- children: 'children',
|
|
|
- label: 'name',
|
|
|
- icon: 'icon',
|
|
|
+ children: 'children',
|
|
|
+ label: 'name',
|
|
|
+ icon: 'icon',
|
|
|
};
|
|
|
-
|
|
|
-watch(filterText, (val) => {
|
|
|
- treeRef.value!.filter(val);
|
|
|
-});
|
|
|
-
|
|
|
-const filterNode = (value: string, data: Tree) => {
|
|
|
- if (!value) return true;
|
|
|
- return toRaw(data).name.indexOf(value) !== -1;
|
|
|
-};
|
|
|
-
|
|
|
let data = ref([]);
|
|
|
-
|
|
|
const content = `
|
|
|
1.部门信息;
|
|
|
`;
|
|
|
|
|
|
-const getData = () => {
|
|
|
- api.GetDept({}).then((ret: APIResponseData) => {
|
|
|
- const responseData = ret.data;
|
|
|
- const result = XEUtils.toArrayTree(responseData, {
|
|
|
- parentKey: 'parent',
|
|
|
- children: 'children',
|
|
|
- strict: true,
|
|
|
- });
|
|
|
-
|
|
|
- data.value = result;
|
|
|
- });
|
|
|
-};
|
|
|
+function filterNode(value: string, data: Tree) {
|
|
|
+ if (!value) return true;
|
|
|
+ return toRaw(data).name.indexOf(value) !== -1;
|
|
|
+}
|
|
|
|
|
|
-//树形点击事件
|
|
|
-const onTreeNodeClick = (node: any) => {
|
|
|
- const { id } = node;
|
|
|
- crudExpose.doSearch({ form: { dept: id } });
|
|
|
-};
|
|
|
+function getData() {
|
|
|
+ api.GetDept({}).then((ret: APIResponseData) => {
|
|
|
+ const responseData = ret.data;
|
|
|
+ const result = XEUtils.toArrayTree(responseData, {
|
|
|
+ parentKey: 'parent',
|
|
|
+ children: 'children',
|
|
|
+ strict: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ data.value = result;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 树形点击数据
|
|
|
+ * @param node
|
|
|
+ */
|
|
|
+function onTreeNodeClick(node: any) {
|
|
|
+ const { id } = node;
|
|
|
+ crudExpose.doSearch({ form: { dept: id } });
|
|
|
+}
|
|
|
+
|
|
|
+watch(filterText, (val) => {
|
|
|
+ treeRef.value!.filter(val);
|
|
|
+});
|
|
|
|
|
|
// 页面打开后获取列表数据
|
|
|
onMounted(() => {
|
|
|
- getData();
|
|
|
+ getData();
|
|
|
});
|
|
|
|
|
|
-// crud组件的ref
|
|
|
-const crudRef = ref();
|
|
|
-// crud 配置的ref
|
|
|
-const crudBinding = ref();
|
|
|
-// 暴露的方法
|
|
|
-const { crudExpose } = useExpose({ crudRef, crudBinding });
|
|
|
-// 你的crud配置
|
|
|
-const { crudOptions } = createCrudOptions({ crudExpose });
|
|
|
-// 初始化crud配置
|
|
|
-const { resetCrudOptions } = useCrud({ crudExpose, crudOptions });
|
|
|
-
|
|
|
// 页面打开后获取列表数据
|
|
|
onMounted(() => {
|
|
|
- crudExpose.doRefresh();
|
|
|
+ crudExpose.doRefresh();
|
|
|
});
|
|
|
+
|
|
|
+const confirmLoading = ref(false);
|
|
|
+const ruleFormRef = ref<FormInstance>();
|
|
|
+const ruleForm = reactive({
|
|
|
+ pass: '',
|
|
|
+ checkPass: '',
|
|
|
+});
|
|
|
+
|
|
|
+const rules = reactive<FormRules<typeof ruleForm>>({
|
|
|
+ pass: [{ validator: validatePass, trigger: 'blur' }],
|
|
|
+ checkPass: [{ validator: validatePass2, trigger: 'blur' }],
|
|
|
+});
|
|
|
+
|
|
|
+function validatePass(rule: any, value: any, callback: any) {
|
|
|
+ if (value === '') {
|
|
|
+ callback(new Error('Please input the password'));
|
|
|
+ } else {
|
|
|
+ if (ruleForm.checkPass !== '') {
|
|
|
+ if (!ruleFormRef.value) return;
|
|
|
+ ruleFormRef.value.validateField('checkPass');
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function validatePass2(rule: any, value: any, callback: any) {
|
|
|
+ if (value === '') {
|
|
|
+ callback(new Error('Please input the password again'));
|
|
|
+ } else if (value !== ruleForm.pass) {
|
|
|
+ callback(new Error("Two inputs don't match!"));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function submitForm(formEl: FormInstance | undefined) {
|
|
|
+ if (!formEl) return;
|
|
|
+ await formEl.validate((valid, fields) => {
|
|
|
+ if (valid) {
|
|
|
+ submitPwd();
|
|
|
+ } else {
|
|
|
+ console.log('error submit!', fields);
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function resetForm(formEl: FormInstance | undefined) {
|
|
|
+ if (!formEl) return;
|
|
|
+ formEl.resetFields();
|
|
|
+ dialogVisible.value = false;
|
|
|
+}
|
|
|
+
|
|
|
+async function submitPwd() {
|
|
|
+ confirmLoading.value = true;
|
|
|
+ const id = resetId.value;
|
|
|
+ const body = {
|
|
|
+ newPassword: ruleForm.pass,
|
|
|
+ newPassword2: ruleForm.checkPass,
|
|
|
+ };
|
|
|
+ try {
|
|
|
+ const response = await api.postResetPassword(body, id);
|
|
|
+ if (response.code === 2000) {
|
|
|
+ dialogVisible.value = false;
|
|
|
+ empty();
|
|
|
+ ElMessage.success(response.msg);
|
|
|
+ } else {
|
|
|
+ ElMessage.error(response.msg);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log('error:', error);
|
|
|
+ } finally {
|
|
|
+ confirmLoading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 关闭前清空表单, 统一控制器
|
|
|
+ * @param done
|
|
|
+ */
|
|
|
+function handleBeforeClose(done: Function) {
|
|
|
+ empty();
|
|
|
+ done();
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 清空表单
|
|
|
+ */
|
|
|
+function empty() {
|
|
|
+ if (ruleFormRef.value) ruleFormRef.value.resetFields();
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
+<template>
|
|
|
+ <fs-page>
|
|
|
+ <el-row class="mx-2">
|
|
|
+ <el-col xs="24" :sm="8" :md="6" :lg="4" :xl="4" class="p-1">
|
|
|
+ <el-card :body-style="{ height: '100%' }">
|
|
|
+ <p class="font-mono font-black text-center text-xl pb-5">
|
|
|
+ 部门列表
|
|
|
+ <el-tooltip effect="dark" :content="content" placement="right">
|
|
|
+ <el-icon>
|
|
|
+ <QuestionFilled />
|
|
|
+ </el-icon>
|
|
|
+ </el-tooltip>
|
|
|
+ </p>
|
|
|
+ <el-input v-model="filterText" :placeholder="placeholder" />
|
|
|
+ <el-tree
|
|
|
+ ref="treeRef"
|
|
|
+ class="font-mono font-bold leading-6 text-7xl"
|
|
|
+ :data="data"
|
|
|
+ :props="treeProps"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ icon="ArrowRightBold"
|
|
|
+ :indent="12"
|
|
|
+ @node-click="onTreeNodeClick">
|
|
|
+ <template #default="{ node, data }">
|
|
|
+ <span class="text-center font-black font-normal">{{ node.label }}</span>
|
|
|
+ </template>
|
|
|
+ </el-tree>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col xs="24" :sm="16" :md="18" :lg="20" :xl="20" class="p-1">
|
|
|
+ <el-card :body-style="{ height: '100%' }">
|
|
|
+ <fs-crud ref="crudRef" v-bind="crudBinding">
|
|
|
+ <template #actionbar-right>
|
|
|
+ <importExcel api="api/system/user/">导入</importExcel>
|
|
|
+ </template>
|
|
|
+ </fs-crud>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-dialog v-model="dialogVisible" title="修改密码" width="500" :before-close="handleBeforeClose">
|
|
|
+ <el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto" status-icon>
|
|
|
+ <el-form-item label="Password" prop="pass">
|
|
|
+ <el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="Confirm" prop="checkPass">
|
|
|
+ <el-input v-model="ruleForm.checkPass" type="password" autocomplete="off" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="flex-col">
|
|
|
+ <el-button @click="resetForm(ruleFormRef)">取消</el-button>
|
|
|
+ <el-button type="primary" @click="submitForm(ruleFormRef)" :loading="confirmLoading">确认</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-dialog>
|
|
|
+ </fs-page>
|
|
|
+</template>
|
|
|
+
|
|
|
<style lang="scss" scoped>
|
|
|
.el-row {
|
|
|
- height: 100%;
|
|
|
+ height: 100%;
|
|
|
|
|
|
- .el-col {
|
|
|
- height: 100%;
|
|
|
- }
|
|
|
+ .el-col {
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.el-card {
|
|
|
- height: 100%;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
.font-normal {
|
|
|
- font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
|
|
|
+ font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
|
|
|
}
|
|
|
</style>
|