Files
vue3-element-admin/src/views/demo/curd-single.vue

588 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container h-full flex flex-1 flex-col">
<div class="mb-10">
<el-link
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/curd-demo.vue"
type="primary"
target="_blank"
>
整合版示例源码 请点击 >>>
</el-link>
</div>
<!-- 搜索 -->
<page-search
ref="searchRef"
:search-config="searchConfig"
@query-click="handleQueryClick"
@reset-click="handleResetClick"
/>
<!-- 列表 -->
<page-content
ref="contentRef"
:content-config="contentConfig"
@add-click="handleAddClick"
@export-click="handleExportClick"
@search-click="handleSearchClick"
@toolbar-click="handleToolbarClick"
@operate-click="handleOperateClick"
@filter-change="handleFilterChange"
>
<template #status="scope">
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
</el-tag>
</template>
<template #gender="scope">
<DictTag v-model="scope.row[scope.prop]" code="gender" />
</template>
<template #mobile="scope">
<el-text>{{ scope.row[scope.prop] }}</el-text>
<copy-button
v-if="scope.row[scope.prop]"
:text="scope.row[scope.prop]"
:style="{ marginLeft: '2px' }"
/>
</template>
</page-content>
<!-- 新增 -->
<page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick">
<template #gender="scope">
<DictSelect v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" />
</template>
</page-modal>
<!-- 编辑 -->
<page-modal
ref="editModalRef"
:modal-config="editModalConfig"
@submit-click="handleSubmitClick"
>
<template #gender="scope">
<DictSelect v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" />
</template>
</page-modal>
</div>
</template>
<script setup lang="ts">
import UserAPI from "@/api/system/user";
import DeptAPI from "@/api/system/dept";
import RoleAPI from "@/api/system/role";
import type { UserForm, UserQueryParams, UserItem } from "@/types/api";
import type { IObject, IModalConfig, IContentConfig, ISearchConfig } from "@/components/CURD/types";
import { DeviceEnum } from "@/enums/settings";
import { useAppStore } from "@/store";
import usePage from "@/components/CURD/usePage";
defineOptions({
name: "CurdDemo",
inheritAttrs: false,
});
// ========================= 选项数据管理 =========================
interface OptionItem {
label: string;
value: any;
[key: string]: any;
}
// 共享选项数据
const deptArr = ref<OptionItem[]>([]);
const roleArr = ref<OptionItem[]>([]);
const stateArr = ref<OptionItem[]>([
{ label: "启用", value: 1 },
{ label: "禁用", value: 0 },
]);
// 初始化选项数据
const initOptions = async () => {
try {
const [dept, roles] = await Promise.all([DeptAPI.getOptions(), RoleAPI.getOptions()]);
deptArr.value = dept;
roleArr.value = roles;
} catch (error) {
console.error("初始化选项失败:", error);
}
};
// ========================= 搜索配置 =========================
const searchConfig: ISearchConfig = reactive({
permPrefix: "sys:user",
formItems: [
{
tips: "支持模糊搜索",
type: "input",
label: "关键字",
prop: "keywords",
attrs: {
placeholder: "用户名/昵称/手机",
clearable: true,
style: { width: "200px" },
},
},
{
type: "tree-select",
label: "部门",
prop: "deptId",
attrs: {
placeholder: "请选择",
data: deptArr,
filterable: true,
"check-strictly": true,
"render-after-expand": false,
clearable: true,
style: { width: "200px" },
},
},
{
type: "select",
label: "状态",
prop: "status",
attrs: {
placeholder: "全部",
clearable: true,
style: { width: "200px" },
},
options: stateArr,
},
{
type: "date-picker",
label: "创建时间",
prop: "createTime",
attrs: {
type: "daterange",
"range-separator": "~",
"start-placeholder": "开始时间",
"end-placeholder": "截止时间",
"value-format": "YYYY-MM-DD",
style: { width: "200px" },
},
},
],
});
// ========================= 内容配置 =========================
const contentConfig: IContentConfig<UserQueryParams, UserItem> = reactive({
permPrefix: "sys:user",
table: {
border: true,
highlightCurrentRow: true,
},
pagination: {
background: true,
layout: "prev,pager,next,jumper,total,sizes",
pageSize: 20,
pageSizes: [10, 20, 30, 50],
},
indexAction(params: any) {
return UserAPI.getPage(params);
},
deleteAction: UserAPI.deleteByIds,
importAction(file: File) {
return UserAPI.import("1", file);
},
exportAction: UserAPI.export,
importTemplate: UserAPI.downloadTemplate,
importsAction(data: any) {
console.log("importsAction", data);
return Promise.resolve();
},
async exportsAction(params: any) {
const res = await UserAPI.getPage(params);
console.log("exportsAction", res.data);
return res.data;
},
pk: "id",
toolbar: [
"add",
"delete",
"import",
"export",
{
name: "custom1",
text: "自定义",
perm: "add",
attrs: { icon: "plus", color: "#626AEF" },
},
],
defaultToolbar: ["refresh", "filter", "imports", "exports", "search"],
cols: [
{ type: "selection", width: 50, align: "center" },
{ label: "编号", align: "center", prop: "id", width: 100, show: false },
{ label: "用户名", align: "center", prop: "username" },
{ label: "头像", align: "center", prop: "avatar", templet: "image" },
{ label: "用户昵称", align: "center", prop: "nickname", width: 120 },
{
label: "性别",
align: "center",
prop: "gender",
width: 100,
templet: "custom",
slotName: "gender",
},
{ label: "部门", align: "center", prop: "deptName", width: 120 },
{
label: "角色",
align: "center",
prop: "roleNames",
width: 120,
columnKey: "roleIds",
filters: [],
filterMultiple: true,
filterJoin: ",",
async initFn(colItem: any) {
const roleOptions = await RoleAPI.getOptions();
colItem.filters = roleOptions.map((item) => {
return { text: item.label, value: item.value };
});
},
},
{
label: "手机号码",
align: "center",
prop: "mobile",
templet: "custom",
slotName: "mobile",
width: 150,
},
{
label: "状态",
align: "center",
prop: "status",
templet: "custom",
slotName: "status",
},
{ label: "创建时间", align: "center", prop: "createTime", width: 180 },
{
label: "操作",
align: "center",
fixed: "right",
width: 280,
templet: "tool",
operat: [
{
name: "detail",
text: "详情",
attrs: { icon: "Document", type: "primary" },
},
{
name: "reset_pwd",
text: "重置密码",
attrs: {
icon: "refresh-left",
style: {
"--el-button-text-color": "#626AEF",
"--el-button-hover-link-text-color": "#9197f4",
},
},
},
"edit",
"delete",
],
},
],
});
// ========================= 新增配置 =========================
const addModalConfig: IModalConfig<UserForm> = reactive({
permPrefix: "sys:user",
dialog: {
title: "新增用户",
width: 800,
draggable: true,
},
form: {
labelWidth: 100,
},
formAction: UserAPI.create,
beforeSubmit(data: any) {
console.log("提交之前处理", data);
},
formItems: [
{
label: "用户名",
prop: "username",
rules: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
type: "input",
attrs: {
placeholder: "请输入用户名",
},
col: {
xs: 24,
sm: 12,
},
},
{
label: "用户昵称",
prop: "nickname",
rules: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
type: "input",
attrs: {
placeholder: "请输入用户昵称",
},
col: {
xs: 24,
sm: 12,
},
},
{
label: "所属部门",
prop: "deptId",
rules: [{ required: true, message: "所属部门不能为空", trigger: "change" }],
type: "tree-select",
attrs: {
placeholder: "请选择所属部门",
data: deptArr,
filterable: true,
"check-strictly": true,
"render-after-expand": false,
},
},
{
type: "custom",
label: "性别",
prop: "gender",
initialValue: 1,
attrs: { style: { width: "100%" } },
},
{
label: "角色",
prop: "roleIds",
rules: [{ required: true, message: "用户角色不能为空", trigger: "change" }],
type: "select",
attrs: {
placeholder: "请选择",
multiple: true,
},
options: roleArr,
initialValue: [],
},
{
type: "input",
label: "手机号码",
prop: "mobile",
rules: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur",
},
],
attrs: {
placeholder: "请输入手机号码",
maxlength: 11,
},
},
{
label: "邮箱",
prop: "email",
rules: [
{
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
message: "请输入正确的邮箱地址",
trigger: "blur",
},
],
type: "input",
attrs: {
placeholder: "请输入邮箱",
maxlength: 50,
},
},
{
label: "状态",
prop: "status",
type: "radio",
options: [
{ label: "正常", value: 1 },
{ label: "禁用", value: 0 },
],
initialValue: 1,
},
],
});
// ========================= 编辑配置 =========================
const editModalConfig: IModalConfig<UserForm> = reactive({
permPrefix: "sys:user",
component: "drawer",
drawer: {
title: "修改用户",
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
},
pk: "id",
beforeSubmit(data: any) {
console.log("beforeSubmit", data);
},
formAction(data: any) {
return UserAPI.update(data.id as string, data);
},
formItems: [
{
label: "用户名",
prop: "username",
rules: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
type: "input",
attrs: {
placeholder: "请输入用户名",
readonly: true,
},
},
{
label: "用户昵称",
prop: "nickname",
rules: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
type: "input",
attrs: {
placeholder: "请输入用户昵称",
},
},
{
label: "所属部门",
prop: "deptId",
rules: [{ required: true, message: "所属部门不能为空", trigger: "blur" }],
type: "tree-select",
attrs: {
placeholder: "请选择所属部门",
data: deptArr,
filterable: true,
"check-strictly": true,
"render-after-expand": false,
},
},
{
type: "custom",
label: "性别",
prop: "gender",
initialValue: 1,
attrs: { style: { width: "100%" } },
},
{
label: "角色",
prop: "roleIds",
rules: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
type: "select",
attrs: {
placeholder: "请选择",
multiple: true,
},
options: roleArr,
initialValue: [],
},
{
type: "input",
label: "手机号码",
prop: "mobile",
rules: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur",
},
],
attrs: {
placeholder: "请输入手机号码",
maxlength: 11,
},
},
{
label: "邮箱",
prop: "email",
rules: [
{
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
message: "请输入正确的邮箱地址",
trigger: "blur",
},
],
type: "input",
attrs: {
placeholder: "请输入邮箱",
maxlength: 50,
},
},
{
label: "状态",
prop: "status",
type: "switch",
attrs: {
inlinePrompt: true,
activeText: "正常",
inactiveText: "禁用",
activeValue: 1,
inactiveValue: 0,
},
},
],
});
// ========================= 页面逻辑 =========================
const {
searchRef,
contentRef,
addModalRef,
editModalRef,
handleQueryClick,
handleResetClick,
handleAddClick,
handleEditClick,
handleViewClick,
handleSubmitClick,
handleExportClick,
handleSearchClick,
handleFilterChange,
} = usePage();
// 其他工具
function handleToolbarClick(name: string) {
console.log(name);
if (name === "custom1") {
ElMessage.success("点击了自定义1按钮");
}
}
// 表格工具
const handleOperateClick = (data: IObject) => {
if (data.name === "detail") {
editModalConfig.drawer = { ...editModalConfig.drawer, title: "查看" };
handleViewClick(data.row, async () => {
return await UserAPI.getFormData(data.row.id);
});
} else if (data.name === "edit") {
editModalConfig.drawer = { ...editModalConfig.drawer, title: "修改" };
handleEditClick(data.row, async () => {
return await UserAPI.getFormData(data.row.id);
});
} else if (data.name === "reset_pwd") {
ElMessageBox.prompt("请输入用户名" + data.row.username + "」的新密码", "重置密码", {
confirmButtonText: "确定",
cancelButtonText: "取消",
})
.then(({ value }: any) => {
if (!value || value.length < 6) {
ElMessage.warning("密码至少需6位字符请重新输入");
return false;
}
UserAPI.resetPassword(data.row.id, value).then(() => {
ElMessage.success("密码重置成功,新密码是:" + value);
});
})
.catch(() => {});
}
};
// 初始化
onMounted(() => {
initOptions();
});
</script>
<style scoped>
.app-container {
padding: 20px;
}
</style>