Merge branch 'master' of https://gitee.com/youlaiorg/vue3-element-admin
This commit is contained in:
@@ -1,6 +1,3 @@
|
|||||||
## 开发环境
|
|
||||||
NODE_ENV='development'
|
|
||||||
|
|
||||||
# 应用端口
|
# 应用端口
|
||||||
VITE_APP_PORT = 3000
|
VITE_APP_PORT = 3000
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
## 生产环境
|
|
||||||
NODE_ENV='production'
|
|
||||||
|
|
||||||
# 代理前缀
|
# 代理前缀
|
||||||
VITE_APP_BASE_API = '/prod-api'
|
VITE_APP_BASE_API = '/prod-api'
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://img.shields.io/badge/Vue-3.4.21-brightgreen.svg"/>
|
<img src="https://img.shields.io/badge/Vue-3.4.26-brightgreen.svg"/>
|
||||||
<img src="https://img.shields.io/badge/Vite-5.1.5-green.svg"/>
|
<img src="https://img.shields.io/badge/Vite-5.2.11-green.svg"/>
|
||||||
<img src="https://img.shields.io/badge/Element Plus-2.6.0-blue.svg"/>
|
<img src="https://img.shields.io/badge/Element Plus-2.7.2-blue.svg"/>
|
||||||
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
|
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
|
||||||
<a href="https://gitee.com/youlaiorg" target="_blank">
|
<a href="https://gitee.com/youlaiorg" target="_blank">
|
||||||
<img src="https://img.shields.io/badge/Author-Youlai Open Source Organization-orange.svg"/>
|
<img src="https://img.shields.io/badge/Author-Youlai Open Source Organization-orange.svg"/>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
- **Essential Infrastructure**: Dynamic routing, button permissions, internationalization, code style, Git commit conventions, and common component encapsulation.
|
- **Essential Infrastructure**: Dynamic routing, button permissions, internationalization, code style, Git commit conventions, and common component encapsulation.
|
||||||
|
|
||||||
- **Continuous Updates**: Continuously updated for 3 years since 2021, keeping up with the latest technologies and tools.
|
- **Continuous Updates**: Since 2021, the project has maintained an open-source status with continuous updates, integrating new tools and dependencies in real time, and has accumulated a broad user base.
|
||||||
|
|
||||||
## Project Preview
|
## Project Preview
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ pnpm run dev
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build the project
|
# Build the project
|
||||||
pnpm run build:prod
|
pnpm run build
|
||||||
|
|
||||||
# Upload files to the remote server
|
# Upload files to the remote server
|
||||||
Copy the files generated in the `dist` directory to the `/usr/share/nginx/html` directory.
|
Copy the files generated in the `dist` directory to the `/usr/share/nginx/html` directory.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://img.shields.io/badge/Vue-3.4.26-brightgreen.svg"/>
|
<img src="https://img.shields.io/badge/Vue-3.4.26-brightgreen.svg"/>
|
||||||
<img src="https://img.shields.io/badge/Vite-5.2.11-green.svg"/>
|
<img src="https://img.shields.io/badge/Vite-5.2.11-green.svg"/>
|
||||||
<img src="https://img.shields.io/badge/Element Plus-2.7.0-blue.svg"/>
|
<img src="https://img.shields.io/badge/Element Plus-2.7.2-blue.svg"/>
|
||||||
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
|
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
|
||||||
<a href="https://gitee.com/youlaiorg" target="_blank">
|
<a href="https://gitee.com/youlaiorg" target="_blank">
|
||||||
<img src="https://img.shields.io/badge/Author-有来开源组织-orange.svg"/>
|
<img src="https://img.shields.io/badge/Author-有来开源组织-orange.svg"/>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
- **基础设施**:动态路由、按钮权限、国际化、代码规范、Git 提交规范、常用组件封装。
|
- **基础设施**:动态路由、按钮权限、国际化、代码规范、Git 提交规范、常用组件封装。
|
||||||
|
|
||||||
- **持续更新**:2021年至今持续更新3年,及时跟进最新的技术和工具。
|
- **持续更新**:自2021年起,该项目持续开源更新,实时更新工具和依赖,积累了广泛的用户群体。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ pnpm run dev
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 项目打包
|
# 项目打包
|
||||||
pnpm run build:prod
|
pnpm run build
|
||||||
|
|
||||||
# 上传文件至远程服务器
|
# 上传文件至远程服务器
|
||||||
将打包生成在 `dist` 目录下的文件拷贝至 `/usr/share/nginx/html` 目录
|
将打包生成在 `dist` 目录下的文件拷贝至 `/usr/share/nginx/html` 目录
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -4,14 +4,17 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"dev": "vite",
|
||||||
"dev": "vite serve --mode development",
|
"build": "vue-tsc --noEmit & vite build",
|
||||||
"build:prod": "vite build --mode production && vue-tsc --noEmit",
|
"preview": "vite preview",
|
||||||
"prepare": "husky",
|
"build-only": "vite build",
|
||||||
|
"type-check": "vue-tsc --noEmit",
|
||||||
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ",
|
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ",
|
||||||
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
|
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
|
||||||
"lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix",
|
"lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix",
|
||||||
"lint:lint-staged": "lint-staged",
|
"lint:lint-staged": "lint-staged",
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
"prepare": "husky",
|
||||||
"commit": "git-cz"
|
"commit": "git-cz"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card shadow="never" class="table-container">
|
<el-card shadow="never" class="table-container">
|
||||||
<template #header>
|
<div class="flex-x-between mb-[10px]">
|
||||||
|
<div>
|
||||||
<!-- 表格左上方工具栏 -->
|
<!-- 表格左上方工具栏 -->
|
||||||
<template v-for="item in contentConfig.toolbar" :key="item">
|
<template v-for="item in contentConfig.toolbar" :key="item">
|
||||||
<template v-if="typeof item === 'string'">
|
<template v-if="typeof item === 'string'">
|
||||||
<!-- 刷新 -->
|
|
||||||
<template v-if="item === 'refresh'">
|
|
||||||
<el-button
|
|
||||||
type="info"
|
|
||||||
icon="refresh"
|
|
||||||
@click="handleToolbar(item)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<!-- 新增 -->
|
<!-- 新增 -->
|
||||||
<template v-else-if="item === 'add'">
|
<template v-if="item === 'add'">
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
v-hasPerm="[`${contentConfig.pageName}:${item}`]"
|
||||||
type="success"
|
type="success"
|
||||||
@@ -70,7 +63,45 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格右上方工具栏 -->
|
||||||
|
<div>
|
||||||
|
<el-icon class="cursor-pointer" @click="handleToolbar('refresh')">
|
||||||
|
<i-ep-refresh />
|
||||||
|
</el-icon>
|
||||||
|
|
||||||
|
<!-- 列设置 -->
|
||||||
|
<el-popover placement="bottom" trigger="click">
|
||||||
|
<template #reference>
|
||||||
|
<el-icon class="cursor-pointer ml-2">
|
||||||
|
<i-ep-setting />
|
||||||
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<el-checkbox
|
||||||
|
v-model="columnSetting.checkAll"
|
||||||
|
:indeterminate="columnSetting.isIndeterminate"
|
||||||
|
@change="handleCheckAllChange"
|
||||||
|
>
|
||||||
|
全选
|
||||||
|
</el-checkbox>
|
||||||
|
|
||||||
|
<el-checkbox-group
|
||||||
|
v-model="columnSetting.checkedCols"
|
||||||
|
@change="handleCheckedColumnsChange"
|
||||||
|
>
|
||||||
|
<div v-for="col in contentConfig.cols" :key="col.label">
|
||||||
|
<el-checkbox
|
||||||
|
v-if="col.label"
|
||||||
|
:value="col.label"
|
||||||
|
:label="col.label"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
@@ -78,9 +109,38 @@
|
|||||||
:data="pageData"
|
:data="pageData"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<template v-for="col in contentConfig.cols" :key="col.prop">
|
<template v-for="col in displayedColumns" :key="col.prop">
|
||||||
|
<!-- 显示图片 -->
|
||||||
|
<template v-if="col.show && col.templet === 'image'">
|
||||||
|
<el-table-column v-bind="col">
|
||||||
|
<template #default="scope">
|
||||||
|
<template v-if="Array.isArray(scope.row[col.prop])">
|
||||||
|
<template
|
||||||
|
v-for="(item, index) in scope.row[col.prop]"
|
||||||
|
:key="item"
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:src="item"
|
||||||
|
:preview-src-list="scope.row[col.prop]"
|
||||||
|
:initial-index="index"
|
||||||
|
:preview-teleported="true"
|
||||||
|
:style="`width: ${col.imageWidth ?? 40}px; height: ${col.imageHeight ?? 40}px`"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-image
|
||||||
|
:src="scope.row[col.prop]"
|
||||||
|
:preview-src-list="[scope.row[col.prop]]"
|
||||||
|
:preview-teleported="true"
|
||||||
|
:style="`width: ${col.imageWidth ?? 40}px; height: ${col.imageHeight ?? 40}px`"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
<!-- 列操作栏 -->
|
<!-- 列操作栏 -->
|
||||||
<template v-if="col.templet === 'tool'">
|
<template v-else-if="col.show && col.templet === 'tool'">
|
||||||
<el-table-column v-bind="col">
|
<el-table-column v-bind="col">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<template v-for="item in col.operat" :key="item">
|
<template v-for="item in col.operat" :key="item">
|
||||||
@@ -151,7 +211,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
<!-- 自定义 -->
|
<!-- 自定义 -->
|
||||||
<template v-else-if="col.templet === 'custom'">
|
<template v-else-if="col.show && col.templet === 'custom'">
|
||||||
<el-table-column v-bind="col">
|
<el-table-column v-bind="col">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<slot
|
<slot
|
||||||
@@ -164,7 +224,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<!-- 其他 -->
|
<!-- 其他 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-table-column v-bind="col" />
|
<el-table-column v-bind="col" v-if="col.show" />
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -182,7 +242,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from "vue";
|
import { ref, reactive } from "vue";
|
||||||
import Pagination from "@/components/Pagination/index.vue";
|
import Pagination from "@/components/Pagination/index.vue";
|
||||||
import type { TableProps } from "element-plus";
|
import type { TableProps, CheckboxValueType } from "element-plus";
|
||||||
|
|
||||||
// 对象类型
|
// 对象类型
|
||||||
export type IObject = Record<string, any>;
|
export type IObject = Record<string, any>;
|
||||||
@@ -369,6 +429,53 @@ function exportPageData(queryParams: IObject = {}) {
|
|||||||
ElMessage.error("未配置exportAction");
|
ElMessage.error("未配置exportAction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 列设置类型声明
|
||||||
|
interface IColumnSetting {
|
||||||
|
checkAll: boolean;
|
||||||
|
isIndeterminate: boolean;
|
||||||
|
checkedCols: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列设置
|
||||||
|
const columnSetting = ref<IColumnSetting>({
|
||||||
|
checkAll: true,
|
||||||
|
isIndeterminate: false,
|
||||||
|
checkedCols: [],
|
||||||
|
});
|
||||||
|
// 创建一个响应式副本,用于存储最后显示的列配置
|
||||||
|
const displayedColumns = ref<IObject>(props.contentConfig.cols);
|
||||||
|
|
||||||
|
// 全选/取消全选
|
||||||
|
const handleCheckAllChange = (checkAll: CheckboxValueType) => {
|
||||||
|
columnSetting.value.checkedCols = checkAll
|
||||||
|
? props.contentConfig.cols.map((col) => col.label)
|
||||||
|
: [];
|
||||||
|
columnSetting.value.isIndeterminate = false;
|
||||||
|
|
||||||
|
displayedColumns.value = displayedColumns.value.map((col: IObject) => ({
|
||||||
|
...col,
|
||||||
|
show: checkAll,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选中列变化
|
||||||
|
const handleCheckedColumnsChange = (values: CheckboxValueType[]) => {
|
||||||
|
const showColumnsLength = props.contentConfig.cols.length;
|
||||||
|
|
||||||
|
const checkedCount = values.length;
|
||||||
|
columnSetting.value.checkAll = checkedCount === showColumnsLength;
|
||||||
|
columnSetting.value.isIndeterminate =
|
||||||
|
checkedCount > 0 && checkedCount < showColumnsLength;
|
||||||
|
|
||||||
|
displayedColumns.value = displayedColumns.value.map((col: IObject) => ({
|
||||||
|
...col,
|
||||||
|
show: values.includes(col.label),
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化全选状态
|
||||||
|
handleCheckAllChange(columnSetting.value.checkAll);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="search-container" v-hasPerm="[`${searchConfig.pageName}:query`]">
|
<div class="search-container" v-hasPerm="[`${searchConfig.pageName}:query`]">
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams">
|
||||||
<template v-for="item in searchConfig.formItems" :key="item.prop">
|
<el-row :gutter="20">
|
||||||
|
<template
|
||||||
|
v-if="isExpand || searchConfig.formItems.length <= showNumber"
|
||||||
|
>
|
||||||
|
<el-col
|
||||||
|
v-bind="colSpans"
|
||||||
|
v-for="item in searchConfig.formItems"
|
||||||
|
:key="item.prop"
|
||||||
|
>
|
||||||
<el-form-item :label="item.label" :prop="item.prop">
|
<el-form-item :label="item.label" :prop="item.prop">
|
||||||
<!-- Input 输入框 -->
|
<!-- Input 输入框 -->
|
||||||
<template v-if="item.type === 'input'">
|
<template v-if="item.type === 'input'">
|
||||||
@@ -60,13 +68,97 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<el-col
|
||||||
|
v-bind="colSpans"
|
||||||
|
v-for="item in searchConfig.formItems.slice(0, showNumber)"
|
||||||
|
:key="item.prop"
|
||||||
|
>
|
||||||
|
<el-form-item :label="item.label" :prop="item.prop">
|
||||||
|
<!-- Input 输入框 -->
|
||||||
|
<template v-if="item.type === 'input'">
|
||||||
|
<template v-if="item.attrs?.type === 'number'">
|
||||||
|
<el-input
|
||||||
|
v-model.number="queryParams[item.prop]"
|
||||||
|
v-bind="item.attrs"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams[item.prop]"
|
||||||
|
v-bind="item.attrs"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<!-- Select 选择器 -->
|
||||||
|
<template v-else-if="item.type === 'select'">
|
||||||
|
<el-select v-model="queryParams[item.prop]" v-bind="item.attrs">
|
||||||
|
<template v-for="option in item.options" :key="option.value">
|
||||||
|
<el-option :label="option.label" :value="option.value" />
|
||||||
|
</template>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
<!-- TreeSelect 树形选择 -->
|
||||||
|
<template v-else-if="item.type === 'tree-select'">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="queryParams[item.prop]"
|
||||||
|
v-bind="item.attrs"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<!-- DatePicker 日期选择器 -->
|
||||||
|
<template v-else-if="item.type === 'date-picker'">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams[item.prop]"
|
||||||
|
v-bind="item.attrs"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<!-- Input 输入框 -->
|
||||||
|
<template v-else>
|
||||||
|
<template v-if="item.attrs?.type === 'number'">
|
||||||
|
<el-input
|
||||||
|
v-model.number="queryParams[item.prop]"
|
||||||
|
v-bind="item.attrs"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams[item.prop]"
|
||||||
|
v-bind="item.attrs"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="flex flex-auto items-start justify-end pr-5">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="search" @click="handleQuery">
|
<el-button type="primary" icon="search" @click="handleQuery">
|
||||||
搜索
|
搜索
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button icon="refresh" @click="handleReset">重置</el-button>
|
<el-button icon="refresh" @click="handleReset">重置</el-button>
|
||||||
|
|
||||||
|
<el-link
|
||||||
|
v-if="isExpandable && searchConfig.formItems.length > showNumber"
|
||||||
|
@click="isExpand = !isExpand"
|
||||||
|
class="ml-2"
|
||||||
|
type="primary"
|
||||||
|
:underline="false"
|
||||||
|
>
|
||||||
|
{{ isExpand ? "收起" : "展开" }}
|
||||||
|
<i-ep-arrow-up v-if="isExpand" />
|
||||||
|
<i-ep-arrow-down v-else />
|
||||||
|
</el-link>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -96,11 +188,38 @@ export interface ISearchConfig {
|
|||||||
// 可选项(适用于select组件)
|
// 可选项(适用于select组件)
|
||||||
options?: { label: string; value: any }[];
|
options?: { label: string; value: any }[];
|
||||||
}>;
|
}>;
|
||||||
|
// 是否开启展开和收缩
|
||||||
|
isExpandable?: boolean;
|
||||||
|
// 默认展示的表单项数量
|
||||||
|
showNumber?: number;
|
||||||
}
|
}
|
||||||
interface IProps {
|
interface IProps {
|
||||||
searchConfig: ISearchConfig;
|
searchConfig: ISearchConfig;
|
||||||
}
|
}
|
||||||
const props = defineProps<IProps>();
|
const props = defineProps<IProps>();
|
||||||
|
|
||||||
|
// 是否可展开/收缩
|
||||||
|
const isExpandable = ref(props.searchConfig.isExpandable);
|
||||||
|
// 是否展开
|
||||||
|
const isExpand = ref(false);
|
||||||
|
|
||||||
|
// 表单项展示数量,若可展开,超出展示数量的表单项隐藏
|
||||||
|
const showNumber = computed(() => {
|
||||||
|
if (isExpandable.value === true) {
|
||||||
|
return props.searchConfig.showNumber ?? 3;
|
||||||
|
} else {
|
||||||
|
return props.searchConfig.formItems.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 表单项栅格列数配置
|
||||||
|
const colSpans = {
|
||||||
|
xs: 24,
|
||||||
|
sm: 12,
|
||||||
|
md: 8,
|
||||||
|
lg: 6,
|
||||||
|
xl: 4,
|
||||||
|
};
|
||||||
|
|
||||||
// 自定义事件
|
// 自定义事件
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
queryClick: [queryParams: IObject];
|
queryClick: [queryParams: IObject];
|
||||||
|
|||||||
@@ -3,14 +3,15 @@
|
|||||||
v-model="settingsVisible"
|
v-model="settingsVisible"
|
||||||
size="300"
|
size="300"
|
||||||
:title="$t('settings.project')"
|
:title="$t('settings.project')"
|
||||||
|
:lockScroll="false"
|
||||||
>
|
>
|
||||||
<el-divider>{{ $t("settings.theme") }}</el-divider>
|
<el-divider>{{ $t("settings.theme") }}</el-divider>
|
||||||
|
|
||||||
<div class="flex-center">
|
<div class="flex-center">
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="isDark"
|
v-model="isDark"
|
||||||
:active-icon="Moon"
|
active-icon="Moon"
|
||||||
:inactive-icon="Sunny"
|
inactive-icon="Sunny"
|
||||||
@change="changeTheme"
|
@change="changeTheme"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,7 +57,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSettingsStore, usePermissionStore, useAppStore } from "@/store";
|
import { useSettingsStore, usePermissionStore, useAppStore } from "@/store";
|
||||||
import { Sunny, Moon } from "@element-plus/icons-vue";
|
|
||||||
import { LayoutEnum } from "@/enums/LayoutEnum";
|
import { LayoutEnum } from "@/enums/LayoutEnum";
|
||||||
import { ThemeEnum } from "@/enums/ThemeEnum";
|
import { ThemeEnum } from "@/enums/ThemeEnum";
|
||||||
|
|
||||||
|
|||||||
1
src/typings/components.d.ts
vendored
1
src/typings/components.d.ts
vendored
@@ -33,6 +33,7 @@ declare module "vue" {
|
|||||||
ElForm: (typeof import("element-plus/es"))["ElForm"];
|
ElForm: (typeof import("element-plus/es"))["ElForm"];
|
||||||
ElFormItem: (typeof import("element-plus/es"))["ElFormItem"];
|
ElFormItem: (typeof import("element-plus/es"))["ElFormItem"];
|
||||||
ElIcon: (typeof import("element-plus/es"))["ElIcon"];
|
ElIcon: (typeof import("element-plus/es"))["ElIcon"];
|
||||||
|
ElImage: (typeof import("element-plus/es"))["ElImage"];
|
||||||
ElInput: (typeof import("element-plus/es"))["ElInput"];
|
ElInput: (typeof import("element-plus/es"))["ElInput"];
|
||||||
ElInputNumber: (typeof import("element-plus/es"))["ElInputNumber"];
|
ElInputNumber: (typeof import("element-plus/es"))["ElInputNumber"];
|
||||||
ElMenu: (typeof import("element-plus/es"))["ElMenu"];
|
ElMenu: (typeof import("element-plus/es"))["ElMenu"];
|
||||||
|
|||||||
2
src/typings/router.d.ts
vendored
2
src/typings/router.d.ts
vendored
@@ -10,6 +10,8 @@ declare module "vue-router" {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
/** 菜单是否隐藏 */
|
/** 菜单是否隐藏 */
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
/** 只有一个子路由是否始终显示 */
|
||||||
|
alwaysShow?: boolean;
|
||||||
/** 是否固定页签 */
|
/** 是否固定页签 */
|
||||||
affix?: boolean;
|
affix?: boolean;
|
||||||
/** 是否缓存页面 */
|
/** 是否缓存页面 */
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const contentConfig: IContentConfig<UserQuery> = {
|
|||||||
{ type: "selection", width: 50, align: "center" },
|
{ type: "selection", width: 50, align: "center" },
|
||||||
{ label: "编号", align: "center", prop: "id", width: 100 },
|
{ label: "编号", align: "center", prop: "id", width: 100 },
|
||||||
{ label: "用户名", align: "center", prop: "username" },
|
{ label: "用户名", align: "center", prop: "username" },
|
||||||
|
{ label: "头像", align: "center", prop: "avatar", templet: "image" },
|
||||||
{ label: "用户昵称", align: "center", prop: "nickname", width: 120 },
|
{ label: "用户昵称", align: "center", prop: "nickname", width: 120 },
|
||||||
{ label: "性别", align: "center", prop: "genderLabel", width: 100 },
|
{ label: "性别", align: "center", prop: "genderLabel", width: 100 },
|
||||||
{ label: "部门", align: "center", prop: "deptName", width: 120 },
|
{ label: "部门", align: "center", prop: "deptName", width: 120 },
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const searchConfig: ISearchConfig = {
|
|||||||
placeholder: "用户名/昵称/手机号",
|
placeholder: "用户名/昵称/手机号",
|
||||||
clearable: true,
|
clearable: true,
|
||||||
style: {
|
style: {
|
||||||
width: "200px",
|
width: "80%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -42,7 +42,7 @@ const searchConfig: ISearchConfig = {
|
|||||||
"render-after-expand": false,
|
"render-after-expand": false,
|
||||||
clearable: true,
|
clearable: true,
|
||||||
style: {
|
style: {
|
||||||
width: "150px",
|
width: "80%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -54,7 +54,7 @@ const searchConfig: ISearchConfig = {
|
|||||||
placeholder: "全部",
|
placeholder: "全部",
|
||||||
clearable: true,
|
clearable: true,
|
||||||
style: {
|
style: {
|
||||||
width: "100px",
|
width: "60%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
options: [
|
options: [
|
||||||
@@ -73,11 +73,12 @@ const searchConfig: ISearchConfig = {
|
|||||||
"end-placeholder": "截止时间",
|
"end-placeholder": "截止时间",
|
||||||
"value-format": "YYYY-MM-DD",
|
"value-format": "YYYY-MM-DD",
|
||||||
style: {
|
style: {
|
||||||
width: "240px",
|
width: "60%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
isExpandable: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default searchConfig;
|
export default searchConfig;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
<el-switch
|
<el-switch
|
||||||
v-model="isDark"
|
v-model="isDark"
|
||||||
inline-prompt
|
inline-prompt
|
||||||
:active-icon="Moon"
|
active-icon="Moon"
|
||||||
:inactive-icon="Sunny"
|
inactive-icon="Sunny"
|
||||||
@change="toggleTheme"
|
@change="toggleTheme"
|
||||||
/>
|
/>
|
||||||
<lang-select class="ml-2 cursor-pointer" />
|
<lang-select class="ml-2 cursor-pointer" />
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
import { useSettingsStore, useUserStore } from "@/store";
|
import { useSettingsStore, useUserStore } from "@/store";
|
||||||
import AuthAPI from "@/api/auth";
|
import AuthAPI from "@/api/auth";
|
||||||
import { LoginData } from "@/api/auth/model";
|
import { LoginData } from "@/api/auth/model";
|
||||||
import { Sunny, Moon } from "@element-plus/icons-vue";
|
import type { FormInstance } from "element-plus";
|
||||||
import { LocationQuery, LocationQueryValue, useRoute } from "vue-router";
|
import { LocationQuery, LocationQueryValue, useRoute } from "vue-router";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import defaultSettings from "@/settings";
|
import defaultSettings from "@/settings";
|
||||||
@@ -136,7 +136,7 @@ const icpVisible = ref(true);
|
|||||||
const loading = ref(false); // 按钮loading
|
const loading = ref(false); // 按钮loading
|
||||||
const isCapslock = ref(false); // 是否大写锁定
|
const isCapslock = ref(false); // 是否大写锁定
|
||||||
const captchaBase64 = ref(); // 验证码图片Base64字符串
|
const captchaBase64 = ref(); // 验证码图片Base64字符串
|
||||||
const loginFormRef = ref(ElForm); // 登录表单ref
|
const loginFormRef = ref<FormInstance>(); // 登录表单ref
|
||||||
const { height } = useWindowSize();
|
const { height } = useWindowSize();
|
||||||
|
|
||||||
const loginData = ref<LoginData>({
|
const loginData = ref<LoginData>({
|
||||||
@@ -186,7 +186,7 @@ function getCaptcha() {
|
|||||||
/** 登录 */
|
/** 登录 */
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
function handleLogin() {
|
function handleLogin() {
|
||||||
loginFormRef.value.validate((valid: boolean) => {
|
loginFormRef.value?.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
userStore
|
userStore
|
||||||
@@ -285,4 +285,3 @@ html.dark .login-container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@/api/auth/model
|
|
||||||
|
|||||||
@@ -445,8 +445,9 @@ function resetPassword(row: { [key: string]: any }) {
|
|||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
}
|
}
|
||||||
).then(({ value }) => {
|
).then(({ value }) => {
|
||||||
if (!value) {
|
if (!value || value.length < 6) {
|
||||||
ElMessage.warning("请输入新密码");
|
// 检查密码是否为空或少于6位
|
||||||
|
ElMessage.warning("密码至少需要6位字符,请重新输入");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
UserAPI.updatePassword(row.id, value).then(() => {
|
UserAPI.updatePassword(row.id, value).then(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user