fix: 更新路由为后台配置,修改admim文件名称为admin
This commit is contained in:
537
src/views/admin/system/menu/index.vue
Normal file
537
src/views/admin/system/menu/index.vue
Normal file
@@ -0,0 +1,537 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="search-bar">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="关键字" prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.title"
|
||||
placeholder="菜单名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="refresh" @click="handleResetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-card shadow="never">
|
||||
<div class="mb-10px">
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:add']"
|
||||
type="success"
|
||||
icon="plus"
|
||||
@click="handleOpenDialog('0')"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="menuTableData"
|
||||
highlight-current-row
|
||||
row-key="menuId"
|
||||
:tree-props="{
|
||||
children: 'children',
|
||||
hasChildren: 'hasChildren',
|
||||
}"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table-column label="菜单名称" min-width="100">
|
||||
<template #default="scope">
|
||||
{{ scope.row.title }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="图标" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.icon && scope.row.icon.startsWith('el-icon')">
|
||||
<el-icon style="vertical-align: -0.15em">
|
||||
<component :is="scope.row.icon.replace('el-icon-', '')" />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template v-else-if="scope.row.icon">
|
||||
<svg-icon :icon-class="scope.row.icon" />
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.type === MenuTypeEnum.MENU && scope.row.path.startsWith('/')"
|
||||
type="warning"
|
||||
>
|
||||
目录
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="scope.row.type === MenuTypeEnum.MENU && !scope.row.path.startsWith('/')"
|
||||
type="success"
|
||||
>
|
||||
菜单
|
||||
</el-tag>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.BUTTON" type="danger">按钮</el-tag>
|
||||
<el-tag v-if="scope.row.type === MenuTypeEnum.EXTLINK" type="info">外链</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" align="left" width="150" prop="menuSort" />
|
||||
<el-table-column label="路由路径" align="left" width="250" prop="path" />
|
||||
<el-table-column label="组件路径" align="left" width="250" prop="component" />
|
||||
<el-table-column label="外链" align="left" width="80" prop="iFrame">
|
||||
<template #default="scope">
|
||||
{{ scope.row.iFrame ? "是" : "否" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="缓存" align="left" width="80" prop="cache">
|
||||
<template #default="scope">
|
||||
{{ scope.row.cache ? "是" : "否" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="可见" align="left" width="80" prop="iFrame">
|
||||
<template #default="scope">
|
||||
{{ scope.row.hidden ? "否" : "是" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建日期" align="left" prop="createTime">
|
||||
<template #default="scope">
|
||||
{{ scope.row.createTime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" align="center" label="操作" width="220">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.type == 0"
|
||||
v-hasPerm="['sys:menu:add']"
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
icon="plus"
|
||||
@click.stop="handleOpenDialog(scope.row.menuId)"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:edit']"
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
icon="edit"
|
||||
@click.stop="handleOpenDialog(undefined, scope.row.menuId)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:delete']"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
icon="delete"
|
||||
@click.stop="handleDelete(scope.row.menuId)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-drawer v-model="dialog.visible" :title="dialog.title" size="50%" @close="handleCloseDialog">
|
||||
<el-form ref="editRequestRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="父级菜单" prop="pid">
|
||||
<el-tree-select
|
||||
v-model="formData.pid"
|
||||
placeholder="选择上级菜单"
|
||||
:data="menuOptions"
|
||||
filterable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="菜单名称" prop="title">
|
||||
<el-input v-model="formData.title" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="菜单类型" prop="type">
|
||||
<el-radio-group v-model="formData.type" @change="handleMenuTypeChange">
|
||||
<el-radio :value="0">菜单</el-radio>
|
||||
<el-radio :value="1">按钮</el-radio>
|
||||
<el-radio :value="2">接口</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否外链" prop="path">
|
||||
<el-switch
|
||||
v-model="formData.iFrame"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU" prop="name">
|
||||
<template #label>
|
||||
<div class="flex-y-center">
|
||||
路由名称
|
||||
<el-tooltip placement="bottom" effect="light">
|
||||
<template #content>
|
||||
如果需要开启缓存,需保证页面 defineOptions 中的 name 与此处一致,建议使用驼峰。
|
||||
</template>
|
||||
<el-icon class="ml-1 cursor-pointer">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="formData.name" placeholder="User" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU" prop="path">
|
||||
<template #label>
|
||||
<div class="flex-y-center">
|
||||
路由路径
|
||||
<el-tooltip placement="bottom" effect="light">
|
||||
<template #content>
|
||||
定义应用中不同页面对应的 URL 路径,目录需以 / 开头,菜单项不用。例如:系统管理目录
|
||||
/system,系统管理下的用户管理菜单 user。
|
||||
</template>
|
||||
<el-icon class="ml-1 cursor-pointer">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
v-if="formData.type == MenuTypeEnum.MENU"
|
||||
v-model="formData.path"
|
||||
placeholder="system"
|
||||
/>
|
||||
<el-input v-else v-model="formData.path" placeholder="user" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU" prop="component">
|
||||
<template #label>
|
||||
<div class="flex-y-center">
|
||||
组件路径
|
||||
<el-tooltip placement="bottom" effect="light">
|
||||
<template #content>
|
||||
组件页面完整路径,相对于 src/views/,如 system/user/index,缺省后缀 .vue
|
||||
</template>
|
||||
<el-icon class="ml-1 cursor-pointer">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-input v-model="formData.component" placeholder="system/user/index" style="width: 95%">
|
||||
<template v-if="formData.type == MenuTypeEnum.MENU" #prepend>src/views/</template>
|
||||
<template v-if="formData.type == MenuTypeEnum.MENU" #append>.vue</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type !== MenuTypeEnum.BUTTON" prop="hidden" label="显示状态">
|
||||
<el-radio-group v-model="formData.hidden">
|
||||
<el-radio :value="1">隐藏</el-radio>
|
||||
<el-radio :value="0">显示</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type === MenuTypeEnum.MENU" label="缓存页面">
|
||||
<el-radio-group v-model="formData.cache">
|
||||
<el-radio :value="true">开启</el-radio>
|
||||
<el-radio :value="false">关闭</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="menuSort">
|
||||
<el-input-number
|
||||
v-model="formData.menuSort"
|
||||
style="width: 100px"
|
||||
controls-position="right"
|
||||
:min="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 权限标识 -->
|
||||
<el-form-item
|
||||
v-if="formData.type == MenuTypeEnum.BUTTON"
|
||||
label="权限标识"
|
||||
prop="permission"
|
||||
>
|
||||
<el-input v-model="formData.permission" placeholder="sys:user:add" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formData.type !== MenuTypeEnum.BUTTON" label="图标" prop="icon">
|
||||
<!-- 图标选择器 -->
|
||||
<icon-select v-model="formData.icon" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- <el-form-item v-if="formData.type == MenuTypeEnum.MENU" label="跳转路由">
|
||||
<el-input v-model="formData.redirect" placeholder="跳转路由" />
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
<el-button @click="handleCloseDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "SysMenu",
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import MenuAPI, { getListRequest, MenuVO, editRequest } from "@/api/account/menu";
|
||||
import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
|
||||
|
||||
const queryFormRef = ref();
|
||||
const editRequestRef = ref();
|
||||
|
||||
const loading = ref(false);
|
||||
const dialog = reactive({
|
||||
title: "新增菜单",
|
||||
visible: false,
|
||||
});
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive<getListRequest>({});
|
||||
// 菜单表格数据
|
||||
const menuTableData = ref<MenuVO[]>([]);
|
||||
// 顶级菜单下拉选项
|
||||
const menuOptions = ref<OptionType[]>([]);
|
||||
// 初始菜单表单数据
|
||||
|
||||
const initialeditRequestData = ref<editRequest>({
|
||||
id: "",
|
||||
pid: "0",
|
||||
hidden: 0,
|
||||
menuSort: 1,
|
||||
type: 0, // 默认菜单
|
||||
alwaysShow: false,
|
||||
cache: 0,
|
||||
title: "",
|
||||
icon: "",
|
||||
iFrame: 0,
|
||||
permission: "",
|
||||
path: "",
|
||||
component: "",
|
||||
name: "",
|
||||
});
|
||||
// 菜单表单数据
|
||||
const formData = ref({ ...initialeditRequestData.value });
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
pid: [{ required: false, message: "请选择父级菜单", trigger: "blur" }],
|
||||
title: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
|
||||
type: [{ required: true, message: "请选择菜单类型", trigger: "blur" }],
|
||||
name: [{ required: false, message: "请输入路由名称", trigger: "blur" }],
|
||||
path: [{ required: true, message: "请输入路由路径", trigger: "blur" }],
|
||||
component: [{ required: false, message: "请输入组件路径", trigger: "blur" }],
|
||||
hidden: [{ required: true, message: "请选择显示状态", trigger: "change" }],
|
||||
});
|
||||
|
||||
// 选择表格的行菜单ID
|
||||
const selectedMenuId = ref<string | undefined>();
|
||||
|
||||
// 查询菜单
|
||||
function handleQuery() {
|
||||
loading.value = true;
|
||||
MenuAPI.getList(queryParams)
|
||||
.then((data) => {
|
||||
menuTableData.value = data;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
function handleResetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
// 行点击事件
|
||||
function handleRowClick(row: MenuVO) {
|
||||
selectedMenuId.value = row.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回格式化后的menus菜单数据
|
||||
*/
|
||||
function returnFilterMenuData(menus: MenuVO[]): OptionType[] {
|
||||
return menus.map((menu) => {
|
||||
const { title, menuId, children, ...rest } = menu;
|
||||
return {
|
||||
value: menuId,
|
||||
label: title,
|
||||
children: children && returnFilterMenuData(children),
|
||||
...rest,
|
||||
} as OptionType;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开表单弹窗
|
||||
*
|
||||
* @param pid 父菜单ID
|
||||
* @param menuId 菜单ID
|
||||
*/
|
||||
function handleOpenDialog(pid?: string, menuId?: string) {
|
||||
MenuAPI.getList({})
|
||||
.then((data) => {
|
||||
menuOptions.value = [{ value: "0", label: "顶级菜单", children: returnFilterMenuData(data) }];
|
||||
})
|
||||
.then(() => {
|
||||
dialog.visible = true;
|
||||
if (menuId) {
|
||||
console.log(menuId);
|
||||
dialog.title = "编辑菜单";
|
||||
MenuAPI.get(menuId).then((data) => {
|
||||
console.log(data);
|
||||
data.iFrame;
|
||||
formData.value = {
|
||||
...data,
|
||||
id: data.id || "",
|
||||
pid: data.pid || "0",
|
||||
cache: data.cache ? 1 : 0,
|
||||
hidden: data.hidden ? 1 : 0,
|
||||
component: data.component || "",
|
||||
icon: data.icon || "",
|
||||
iFrame: data.iFrame ? 1 : 0,
|
||||
menuSort: data.menuSort ?? 0, // Ensure menuSort is always a number
|
||||
name: data.name || "", // Ensure name is always a string
|
||||
path: data.path || "", // Ensure path is always a string
|
||||
title: data.title || "", // Ensure title is always a string
|
||||
type: data.type ?? 0, // Ensure type is always a number
|
||||
};
|
||||
});
|
||||
} else {
|
||||
dialog.title = "新增菜单";
|
||||
formData.value.pid = pid ? pid : "0";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 菜单类型切换
|
||||
function handleMenuTypeChange() {
|
||||
// 如果菜单类型改变
|
||||
if (formData.value.type !== initialeditRequestData.value.type) {
|
||||
if (formData.value.type === MenuTypeEnum.MENU) {
|
||||
// 目录切换到菜单时,清空组件路径
|
||||
if (initialeditRequestData.value.type === MenuTypeEnum.MENU) {
|
||||
formData.value.component = "";
|
||||
} else {
|
||||
// 其他情况,保留原有的组件路径
|
||||
formData.value.path = initialeditRequestData.value.path;
|
||||
formData.value.component = initialeditRequestData.value.component;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交表单
|
||||
*/
|
||||
function handleSubmit() {
|
||||
editRequestRef.value.validate((isValid: boolean) => {
|
||||
if (isValid) {
|
||||
const menuId = formData.value.menuId;
|
||||
const submitFormData = {
|
||||
...formData.value,
|
||||
cache: formData.value.cache ? 1 : 0,
|
||||
hidden: formData.value.hidden ? 1 : 0,
|
||||
pid: formData.value.pid == 0 ? undefined : String(formData.value.pid),
|
||||
};
|
||||
if (menuId) {
|
||||
//修改时父级菜单不能为当前菜单
|
||||
if (formData.value.pid == menuId) {
|
||||
ElMessage.error("父级菜单不能为当前菜单");
|
||||
return;
|
||||
}
|
||||
MenuAPI.edit(menuId, submitFormData).then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
MenuAPI.add(submitFormData).then(() => {
|
||||
ElMessage.success("新增成功");
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 删除菜单
|
||||
function handleDelete(menuId: number) {
|
||||
if (!menuId) {
|
||||
ElMessage.warning("请勾选删除项");
|
||||
return false;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(
|
||||
() => {
|
||||
loading.value = true;
|
||||
MenuAPI.delete(menuId)
|
||||
.then(() => {
|
||||
ElMessage.success("删除成功");
|
||||
handleQuery();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
},
|
||||
() => {
|
||||
ElMessage.info("已取消删除");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
editRequestRef.value.resetFields();
|
||||
editRequestRef.value.clearValidate();
|
||||
formData.value = {
|
||||
id: "",
|
||||
pid: "0",
|
||||
hidden: 0,
|
||||
menuSort: 1,
|
||||
type: 0, // 默认菜单
|
||||
alwaysShow: false,
|
||||
cache: 0,
|
||||
title: "",
|
||||
icon: "",
|
||||
iFrame: 0,
|
||||
permission: "",
|
||||
path: "",
|
||||
component: "",
|
||||
name: "",
|
||||
};
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function handleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
91
src/views/admin/system/miniAppPages/config/add.ts
Normal file
91
src/views/admin/system/miniAppPages/config/add.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import API, { type addRequest } from "@/api/system/miniAppPages";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
|
||||
const modalConfig: IModalConfig<addRequest> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "新增小程序页面",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 140,
|
||||
},
|
||||
formAction: function (data) {
|
||||
if (data.icon) {
|
||||
data.icon = typeof data.icon === "string" ? data.icon : data.icon[0]
|
||||
}
|
||||
return API.add(data);
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
|
||||
{
|
||||
type: "UpImage",
|
||||
label: "图标",
|
||||
prop: "icon",
|
||||
rules: [{ required: false, message: "请上传图标", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请上传图标",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "小程序页面名称",
|
||||
prop: "name",
|
||||
rules: [{ required: true, message: "请输入小程序页面名称", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入小程序页面名称",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "小程序页面路径",
|
||||
prop: "path",
|
||||
rules: [{ required: true, message: "请输入小程序页面路径", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入小程序页面路径",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "页面描述",
|
||||
prop: "description",
|
||||
rules: [{ required: false, message: "请输入页面描述", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入页面描述",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input-number",
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
rules: [{ required: false, message: "请输入排序", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入排序",
|
||||
},
|
||||
initialValue: 0,
|
||||
},
|
||||
{
|
||||
type: "radio-button",
|
||||
label: "小程序页面状态",
|
||||
prop: "status",
|
||||
options: [
|
||||
{
|
||||
label: "启用",
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: "禁用",
|
||||
value: 0,
|
||||
},
|
||||
],
|
||||
initialValue: 1,
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
// 如果有异步数据会修改配置的,推荐用reactive包裹,而纯静态配置的可以直接导出
|
||||
export default reactive(modalConfig);
|
||||
31
src/views/admin/system/miniAppPages/config/config.ts
Normal file
31
src/views/admin/system/miniAppPages/config/config.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { property } from "lodash";
|
||||
|
||||
export const statusOptions: options[] = [
|
||||
{ label: "全部", value: '' },
|
||||
{ label: "启用", value: 1 },
|
||||
{ label: "禁用", value: 0 },
|
||||
];
|
||||
|
||||
|
||||
export type optionsType = "status";
|
||||
|
||||
export function returnOptions(type: optionsType) {
|
||||
if (type === "status") {
|
||||
return statusOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export function returnOptionsLabel(optionsType: optionsType, value: string | number) {
|
||||
const options = returnOptions(optionsType);
|
||||
if (!options) {
|
||||
return "";
|
||||
}
|
||||
const option = options.find((item) => item.value === value);
|
||||
return option ? option.label : "";
|
||||
}
|
||||
|
||||
export interface options {
|
||||
label: string;
|
||||
value: string | number;
|
||||
[property: string]: any;
|
||||
}
|
||||
73
src/views/admin/system/miniAppPages/config/content.ts
Normal file
73
src/views/admin/system/miniAppPages/config/content.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import API, { type editRequest } from "@/api/system/miniAppPages";
|
||||
import type { IContentConfig } from "@/components/CURD/types";
|
||||
|
||||
const contentConfig: IContentConfig<editRequest> = {
|
||||
pageName: "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: function (params) {
|
||||
return API.getList(params);
|
||||
},
|
||||
deleteAction: API.delete,
|
||||
// modifyAction: function (data) {
|
||||
// // return API.edit(data);
|
||||
// },
|
||||
pk: "id",
|
||||
toolbar: ["add"],
|
||||
defaultToolbar: ["refresh", "filter", "search"],
|
||||
cols: [
|
||||
{ type: "selection", width: 50, align: "center" },
|
||||
{
|
||||
label: "小程序页面名称",
|
||||
align: "center",
|
||||
prop: "name",
|
||||
},
|
||||
{
|
||||
label: "图标",
|
||||
align: "center",
|
||||
prop: "icon",
|
||||
templet: "custom",
|
||||
slotName: "icon",
|
||||
},
|
||||
{
|
||||
label: "小程序页面路径",
|
||||
align: "center",
|
||||
prop: "path",
|
||||
},
|
||||
{
|
||||
label: "页面描述",
|
||||
align: "center",
|
||||
prop: "description",
|
||||
},
|
||||
{
|
||||
label: "排序",
|
||||
align: "center",
|
||||
prop: "sort",
|
||||
},
|
||||
{
|
||||
label: "状态",
|
||||
align: "center",
|
||||
prop: "status",
|
||||
templet: "custom",
|
||||
slotName: "status",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 280,
|
||||
templet: "tool",
|
||||
operat: ["edit", "delete"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default contentConfig;
|
||||
91
src/views/admin/system/miniAppPages/config/edit.ts
Normal file
91
src/views/admin/system/miniAppPages/config/edit.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import API, { type editRequest } from "@/api/system/miniAppPages";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
|
||||
const modalConfig: IModalConfig<editRequest> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "编辑小程序页面",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 140,
|
||||
},
|
||||
formAction: function (data) {
|
||||
if (data.icon) {
|
||||
data.icon = typeof data.icon === "string" ? data.icon : data.icon[0]
|
||||
}
|
||||
return API.edit(data);
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
|
||||
{
|
||||
type: "UpImage",
|
||||
label: "图标",
|
||||
prop: "icon",
|
||||
rules: [{ required: false, message: "请上传图标", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请上传图标",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "小程序页面名称",
|
||||
prop: "name",
|
||||
rules: [{ required: true, message: "请输入小程序页面名称", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入小程序页面名称",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "小程序页面路径",
|
||||
prop: "path",
|
||||
rules: [{ required: true, message: "请输入小程序页面路径", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入小程序页面路径",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "页面描述",
|
||||
prop: "description",
|
||||
rules: [{ required: false, message: "请输入页面描述", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入页面描述",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input-number",
|
||||
label: "排序",
|
||||
prop: "sort",
|
||||
rules: [{ required: false, message: "请输入排序", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入排序",
|
||||
},
|
||||
initialValue: 0,
|
||||
},
|
||||
{
|
||||
type: "radio-button",
|
||||
label: "小程序页面状态",
|
||||
prop: "status",
|
||||
options: [
|
||||
{
|
||||
label: "启用",
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: "禁用",
|
||||
value: 0,
|
||||
},
|
||||
],
|
||||
initialValue: 1,
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
// 如果有异步数据会修改配置的,推荐用reactive包裹,而纯静态配置的可以直接导出
|
||||
export default reactive(modalConfig);
|
||||
40
src/views/admin/system/miniAppPages/config/search.ts
Normal file
40
src/views/admin/system/miniAppPages/config/search.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import type { ISearchConfig } from "@/components/CURD/types";
|
||||
import { statusOptions } from './config'
|
||||
const searchConfig: ISearchConfig = {
|
||||
pageName: "sys:user",
|
||||
formItems: [
|
||||
{
|
||||
type: "input",
|
||||
label: "小程序页面路径",
|
||||
prop: "name",
|
||||
attrs: {
|
||||
placeholder: "请输入小程序页面路径",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "200px",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "小程序页面路径",
|
||||
prop: "path",
|
||||
attrs: {
|
||||
placeholder: "请输入小程序页面路径",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "200px",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "radio-button",
|
||||
label: "小程序页面状态",
|
||||
prop: "status",
|
||||
options: statusOptions,
|
||||
initialValue: '',
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
export default searchConfig;
|
||||
124
src/views/admin/system/miniAppPages/index.vue
Normal file
124
src/views/admin/system/miniAppPages/index.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 列表 -->
|
||||
<!-- 搜索 -->
|
||||
<page-search
|
||||
ref="searchRef"
|
||||
:search-config="searchConfig"
|
||||
@query-click="handleQueryClick"
|
||||
@reset-click="handleResetClick"
|
||||
/>
|
||||
<!-- 列表 -->
|
||||
<page-content
|
||||
ref="contentRef"
|
||||
:content-config="contentConfig"
|
||||
@add-click="handleAddClick"
|
||||
@edit-click="handleEditClick"
|
||||
@export-click="handleExportClick"
|
||||
@search-click="handleSearchClick"
|
||||
@toolbar-click="handleToolbarClick"
|
||||
@operat-click="handleOperatClick"
|
||||
@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 #icon="scope">
|
||||
<el-image
|
||||
style="width: 50px; height: 50px"
|
||||
:src="scope.row[scope.prop]"
|
||||
:preview-src-list="[scope.row[scope.prop]]"
|
||||
/>
|
||||
</template>
|
||||
<template #options="scope">
|
||||
{{ returnOptionsLabel(scope.prop, scope.row[scope.prop]) }}
|
||||
</template>
|
||||
<template #gender="scope">
|
||||
<DictLabel 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="margin-left: 2px"
|
||||
/>
|
||||
</template>
|
||||
</page-content>
|
||||
|
||||
<!-- 新增 -->
|
||||
<page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick">
|
||||
<template #url="scope">
|
||||
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
|
||||
<!-- <Dict 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 #url="scope">
|
||||
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
|
||||
<!-- <Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" /> -->
|
||||
</template>
|
||||
</page-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// import Api from "@/api/system/miniProgramVersion";
|
||||
import type { IObject, IOperatData } from "@/components/CURD/types";
|
||||
import usePage from "@/components/CURD/usePage";
|
||||
import addModalConfig from "./config/add";
|
||||
import contentConfig from "./config/content";
|
||||
import editModalConfig from "./config/edit";
|
||||
import searchConfig from "./config/search";
|
||||
import { returnOptionsLabel } from "./config/config";
|
||||
|
||||
const {
|
||||
searchRef,
|
||||
contentRef,
|
||||
addModalRef,
|
||||
editModalRef,
|
||||
handleQueryClick,
|
||||
handleResetClick,
|
||||
// handleAddClick,
|
||||
// handleEditClick,
|
||||
handleSubmitClick,
|
||||
handleExportClick,
|
||||
handleSearchClick,
|
||||
handleFilterChange,
|
||||
} = usePage();
|
||||
|
||||
// 新增
|
||||
async function handleAddClick() {
|
||||
addModalRef.value?.setModalVisible();
|
||||
// addModalConfig.formItems[2]!.attrs!.data =
|
||||
}
|
||||
// 编辑
|
||||
async function handleEditClick(row: IObject) {
|
||||
editModalRef.value?.handleDisabled(false);
|
||||
editModalRef.value?.setModalVisible();
|
||||
// 根据id获取数据进行填充
|
||||
// const data = await Api.getFormData(row.id);
|
||||
console.log({ ...row, icon: row.icon ? [row.icon] : [] });
|
||||
editModalRef.value?.setFormData({ ...row, icon: row.icon ? [row.icon] : [] });
|
||||
}
|
||||
1;
|
||||
// 其他工具栏
|
||||
function handleToolbarClick(name: string) {
|
||||
console.log(name);
|
||||
if (name === "custom1") {
|
||||
ElMessage.success("点击了自定义1按钮");
|
||||
}
|
||||
}
|
||||
// 其他操作列
|
||||
async function handleOperatClick(data: IOperatData) {
|
||||
console.log(data);
|
||||
}
|
||||
</script>
|
||||
66
src/views/admin/system/params/config/add.ts
Normal file
66
src/views/admin/system/params/config/add.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import ParamsApi, { type addRequest } from "@/api/system/params";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
import { paramTypeOptions } from './config'
|
||||
const modalConfig: IModalConfig<addRequest> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "添加系统参数",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 140,
|
||||
},
|
||||
formAction: function (data) {
|
||||
return ParamsApi.add(data);
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
{
|
||||
label: "参数编码",
|
||||
prop: "paramCode",
|
||||
rules: [{ required: true, message: "请输入参数编码", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入参数编码",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "参数值",
|
||||
prop: "paramValue",
|
||||
rules: [{ required: true, message: "请输入参数值", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入参数值",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "参数类型",
|
||||
prop: "paramType",
|
||||
rules: [{ required: true, message: "请选择参数类型", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择参数类型",
|
||||
},
|
||||
col: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
},
|
||||
options: paramTypeOptions,
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "备注",
|
||||
prop: "remark",
|
||||
rules: [{ required: true, message: "请输入备注", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入备注",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 如果有异步数据会修改配置的,推荐用reactive包裹,而纯静态配置的可以直接导出
|
||||
export default reactive(modalConfig);
|
||||
28
src/views/admin/system/params/config/config.ts
Normal file
28
src/views/admin/system/params/config/config.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
export const paramTypeOptions: options[] = [
|
||||
{ label: "系统参数", value: 0 },
|
||||
{ label: "非系统参数", value: 1 },
|
||||
];
|
||||
|
||||
export type optionsType = "paramType" | "";
|
||||
|
||||
export function returnOptions(type: optionsType) {
|
||||
if (type === "paramType") {
|
||||
return paramTypeOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export function returnOptionsLabel(optionsType: optionsType, value: string | number) {
|
||||
const options = returnOptions(optionsType);
|
||||
if (!options) {
|
||||
return "";
|
||||
}
|
||||
const option = options.find((item) => item.value === value);
|
||||
return option ? option.label : "";
|
||||
}
|
||||
|
||||
export interface options {
|
||||
label: string;
|
||||
value: string | number;
|
||||
[property: string]: any;
|
||||
}
|
||||
61
src/views/admin/system/params/config/content.ts
Normal file
61
src/views/admin/system/params/config/content.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import ParamsApi from "@/api/system/params";
|
||||
import type { editRequest } from "@/api/system/params";
|
||||
import type { IContentConfig } from "@/components/CURD/types";
|
||||
|
||||
const contentConfig: IContentConfig<editRequest> = {
|
||||
pageName: "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: function (params) {
|
||||
return ParamsApi.getList(params);
|
||||
},
|
||||
// modifyAction: function (data) {
|
||||
// // return ParamsApi.edit(data);
|
||||
// },
|
||||
pk: "id",
|
||||
toolbar: ["add"],
|
||||
defaultToolbar: ["refresh", "filter", "search"],
|
||||
cols: [
|
||||
{ type: "selection", width: 50, align: "center" },
|
||||
{
|
||||
label: "参数编码",
|
||||
align: "center",
|
||||
prop: "paramCode",
|
||||
},
|
||||
{
|
||||
label: "参数值",
|
||||
align: "center",
|
||||
prop: "paramValue",
|
||||
},
|
||||
{
|
||||
label: "参数类型",
|
||||
align: "center",
|
||||
prop: "paramType",
|
||||
templet: "custom",
|
||||
slotName: "options",
|
||||
},
|
||||
{
|
||||
label: "备注",
|
||||
align: "center",
|
||||
prop: "remark",
|
||||
},
|
||||
|
||||
{
|
||||
label: "操作",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
templet: "tool",
|
||||
operat: ["edit"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default contentConfig;
|
||||
133
src/views/admin/system/params/config/content2.ts
Normal file
133
src/views/admin/system/params/config/content2.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import type { IContentConfig } from "@/components/CURD/types";
|
||||
|
||||
const contentConfig: IContentConfig = {
|
||||
pageName: "sys:user",
|
||||
table: {
|
||||
showOverflowTooltip: true,
|
||||
},
|
||||
toolbar: [],
|
||||
indexAction: function (params) {
|
||||
// 模拟发起网络请求获取列表数据
|
||||
console.log("indexAction:", params);
|
||||
return Promise.resolve({
|
||||
total: 2,
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
username: "tom",
|
||||
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
|
||||
percent: 99,
|
||||
price: 10,
|
||||
url: "https://www.baidu.com",
|
||||
icon: "el-icon-setting",
|
||||
gender: 1,
|
||||
status: 1,
|
||||
status2: 1,
|
||||
sort: 99,
|
||||
createTime: 1715647982437,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: "jerry",
|
||||
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
|
||||
percent: 88,
|
||||
price: 999,
|
||||
url: "https://www.google.com",
|
||||
icon: "el-icon-user",
|
||||
gender: 0,
|
||||
status: 0,
|
||||
status2: 0,
|
||||
sort: 0,
|
||||
createTime: 1715648977426,
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
modifyAction(data) {
|
||||
// 模拟发起网络请求修改字段
|
||||
// console.log("modifyAction:", data);
|
||||
ElMessage.success(JSON.stringify(data));
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
cols: [
|
||||
{ type: "index", width: 50, align: "center" },
|
||||
{ label: "ID", align: "center", prop: "id", show: false },
|
||||
{ label: "文本", align: "center", prop: "username" },
|
||||
{ label: "图片", align: "center", prop: "avatar", templet: "image" },
|
||||
{
|
||||
label: "百分比",
|
||||
align: "center",
|
||||
prop: "percent",
|
||||
templet: "percent",
|
||||
},
|
||||
{
|
||||
label: "货币符",
|
||||
align: "center",
|
||||
prop: "price",
|
||||
templet: "price",
|
||||
priceFormat: "$",
|
||||
},
|
||||
{ label: "链接", align: "center", prop: "url", width: 180, templet: "url" },
|
||||
{ label: "图标", align: "center", prop: "icon", templet: "icon" },
|
||||
{
|
||||
label: "列表值",
|
||||
align: "center",
|
||||
prop: "gender",
|
||||
templet: "list",
|
||||
selectList: { "0": "女", "1": "男" },
|
||||
},
|
||||
{
|
||||
label: "自定义",
|
||||
align: "center",
|
||||
prop: "status",
|
||||
templet: "custom",
|
||||
slotName: "status",
|
||||
},
|
||||
{
|
||||
label: "Switch",
|
||||
align: "center",
|
||||
prop: "status2",
|
||||
templet: "switch",
|
||||
activeValue: 1,
|
||||
inactiveValue: 0,
|
||||
activeText: "启用",
|
||||
inactiveText: "禁用",
|
||||
},
|
||||
{
|
||||
label: "输入框",
|
||||
align: "center",
|
||||
prop: "sort",
|
||||
templet: "input",
|
||||
inputType: "number",
|
||||
},
|
||||
{
|
||||
label: "日期格式化",
|
||||
align: "center",
|
||||
prop: "createTime",
|
||||
minWidth: 120,
|
||||
templet: "date",
|
||||
dateFormat: "YYYY/MM/DD HH:mm:ss",
|
||||
},
|
||||
{
|
||||
label: "操作栏",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 220,
|
||||
templet: "tool",
|
||||
operat: [
|
||||
{
|
||||
name: "reset_pwd",
|
||||
auth: "password:reset",
|
||||
icon: "refresh-left",
|
||||
text: "重置密码",
|
||||
type: "primary",
|
||||
render(row) {
|
||||
return row.id === 1;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default contentConfig;
|
||||
67
src/views/admin/system/params/config/edit.ts
Normal file
67
src/views/admin/system/params/config/edit.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import ParamsApi, { type addRequest } from "@/api/system/params";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
import { paramTypeOptions } from './config'
|
||||
const modalConfig: IModalConfig<addRequest> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "编辑系统参数",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 140,
|
||||
},
|
||||
formAction: function (data) {
|
||||
return ParamsApi.edit(data);
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
{
|
||||
label: "参数编码",
|
||||
prop: "paramCode",
|
||||
rules: [{ required: true, message: "请输入参数编码", trigger: "blur" }],
|
||||
type: "input",
|
||||
disabled: true,
|
||||
attrs: {
|
||||
placeholder: "请输入参数编码",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "参数值",
|
||||
prop: "paramValue",
|
||||
rules: [{ required: true, message: "请输入参数值", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入参数值",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "参数类型",
|
||||
prop: "paramType",
|
||||
rules: [{ required: true, message: "请选择参数类型", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择参数类型",
|
||||
},
|
||||
col: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
},
|
||||
options: paramTypeOptions,
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "备注",
|
||||
prop: "remark",
|
||||
rules: [{ required: true, message: "请输入备注", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入备注",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 如果有异步数据会修改配置的,推荐用reactive包裹,而纯静态配置的可以直接导出
|
||||
export default reactive(modalConfig);
|
||||
24
src/views/admin/system/params/config/search.ts
Normal file
24
src/views/admin/system/params/config/search.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { ISearchConfig } from "@/components/CURD/types";
|
||||
import { paramTypeOptions } from './config'
|
||||
|
||||
const searchConfig: ISearchConfig = {
|
||||
pageName: "sys:user",
|
||||
formItems: [
|
||||
{
|
||||
type: "radio-button",
|
||||
label: "参数类型",
|
||||
prop: "type",
|
||||
attrs: {
|
||||
placeholder: "请选择参数类型",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "200px",
|
||||
},
|
||||
},
|
||||
options: paramTypeOptions,
|
||||
initialValue: paramTypeOptions[0].value
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default searchConfig;
|
||||
143
src/views/admin/system/params/index.vue
Normal file
143
src/views/admin/system/params/index.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 列表 -->
|
||||
<template v-if="isA">
|
||||
<!-- 搜索 -->
|
||||
<page-search
|
||||
ref="searchRef"
|
||||
:search-config="searchConfig"
|
||||
@query-click="handleQueryClick"
|
||||
@reset-click="handleResetClick"
|
||||
/>
|
||||
<!-- 列表 -->
|
||||
<page-content
|
||||
ref="contentRef"
|
||||
:content-config="contentConfig"
|
||||
@add-click="handleAddClick"
|
||||
@edit-click="handleEditClick"
|
||||
@export-click="handleExportClick"
|
||||
@search-click="handleSearchClick"
|
||||
@toolbar-click="handleToolbarClick"
|
||||
@operat-click="handleOperatClick"
|
||||
@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 #options="scope">
|
||||
{{ returnOptionsLabel(scope.prop, scope.row[scope.prop]) }}
|
||||
</template>
|
||||
<template #gender="scope">
|
||||
<DictLabel 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="margin-left: 2px"
|
||||
/>
|
||||
</template>
|
||||
</page-content>
|
||||
|
||||
<!-- 新增 -->
|
||||
<page-modal
|
||||
ref="addModalRef"
|
||||
:modal-config="addModalConfig"
|
||||
@submit-click="handleSubmitClick"
|
||||
>
|
||||
<template #url="scope">
|
||||
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
|
||||
<!-- <Dict 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 #url="scope">
|
||||
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
|
||||
<!-- <Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" /> -->
|
||||
</template>
|
||||
</page-modal>
|
||||
</template>
|
||||
<template v-else>
|
||||
<page-content
|
||||
ref="contentRef"
|
||||
:content-config="contentConfig2"
|
||||
@operat-click="handleOperatClick"
|
||||
>
|
||||
<template #status="scope">
|
||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</page-content>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IObject, IOperatData } from "@/components/CURD/types";
|
||||
import usePage from "@/components/CURD/usePage";
|
||||
import addModalConfig from "./config/add";
|
||||
import contentConfig from "./config/content";
|
||||
import contentConfig2 from "./config/content2";
|
||||
import editModalConfig from "./config/edit";
|
||||
import searchConfig from "./config/search";
|
||||
import { returnOptionsLabel } from "./config/config";
|
||||
|
||||
const {
|
||||
searchRef,
|
||||
contentRef,
|
||||
addModalRef,
|
||||
editModalRef,
|
||||
handleQueryClick,
|
||||
handleResetClick,
|
||||
// handleAddClick,
|
||||
// handleEditClick,
|
||||
handleSubmitClick,
|
||||
handleExportClick,
|
||||
handleSearchClick,
|
||||
handleFilterChange,
|
||||
} = usePage();
|
||||
|
||||
// 新增
|
||||
async function handleAddClick() {
|
||||
addModalRef.value?.setModalVisible();
|
||||
}
|
||||
// 编辑
|
||||
async function handleEditClick(row: IObject) {
|
||||
editModalRef.value?.handleDisabled(false);
|
||||
editModalRef.value?.setModalVisible();
|
||||
// 根据id获取数据进行填充
|
||||
editModalRef.value?.setFormData({ ...row });
|
||||
}
|
||||
1;
|
||||
// 其他工具栏
|
||||
function handleToolbarClick(name: string) {
|
||||
console.log(name);
|
||||
if (name === "custom1") {
|
||||
ElMessage.success("点击了自定义1按钮");
|
||||
}
|
||||
}
|
||||
// 其他操作列
|
||||
async function handleOperatClick(data: IOperatData) {}
|
||||
|
||||
// 切换示例
|
||||
const isA = ref(true);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table td.el-table__cell div) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
134
src/views/admin/system/role/components/menus.vue
Normal file
134
src/views/admin/system/role/components/menus.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div class="flex-x-between">
|
||||
<el-input v-model="permKeywords" clearable class="w-[150px]" placeholder="菜单菜单名称">
|
||||
<template #prefix>
|
||||
<Search />
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<div class="flex-center ml-5">
|
||||
<el-button type="primary" size="small" plain @click="togglePermTree">
|
||||
<template #icon>
|
||||
<Switch />
|
||||
</template>
|
||||
{{ isExpanded ? "收缩" : "展开" }}
|
||||
</el-button>
|
||||
<el-checkbox v-model="parentChildLinked" class="ml-5" @change="handleparentChildLinkedChange">
|
||||
父子联动
|
||||
</el-checkbox>
|
||||
|
||||
<el-tooltip placement="bottom">
|
||||
<template #content>
|
||||
如果只需勾选菜单菜单,不需要勾选子菜单或者按钮菜单,请关闭父子联动
|
||||
</template>
|
||||
<el-icon class="ml-1 color-[--el-color-primary] inline-block cursor-pointer">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tree
|
||||
ref="permTreeRef"
|
||||
node-key="value"
|
||||
show-checkbox
|
||||
:data="menuPermOptions"
|
||||
:filter-node-method="handlePermFilter"
|
||||
:default-expand-all="true"
|
||||
:check-strictly="!parentChildLinked"
|
||||
class="mt-5"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
{{ data.label }}
|
||||
</template>
|
||||
</el-tree>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const shopUser = useUserStore();
|
||||
import MenuAPI from "@/api/account/menu";
|
||||
|
||||
const modelValue = defineModel("modelValue", {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => [],
|
||||
});
|
||||
const permKeywords = ref("");
|
||||
const isExpanded = ref(true);
|
||||
const parentChildLinked = ref(true);
|
||||
const permTreeRef = ref();
|
||||
// 展开/收缩 菜单菜单树
|
||||
function togglePermTree() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
if (permTreeRef.value) {
|
||||
Object.values(permTreeRef.value.store.nodesMap).forEach((node) => {
|
||||
if (isExpanded.value) {
|
||||
node.expand();
|
||||
} else {
|
||||
node.collapse();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function handlePermFilter(value, data) {
|
||||
if (!value) return true;
|
||||
return data.label.includes(value);
|
||||
}
|
||||
|
||||
// 父子菜单节点是否联动
|
||||
function handleparentChildLinkedChange(val) {
|
||||
parentChildLinked.value = val;
|
||||
}
|
||||
|
||||
// 菜单菜单下拉
|
||||
const menuPermOptions = ref([]);
|
||||
|
||||
function returnMenu(menu) {
|
||||
return menu.map((v) => {
|
||||
return {
|
||||
...v,
|
||||
label: v.title,
|
||||
value: v.menuId,
|
||||
children: v.children ? returnMenu(v.children) : [],
|
||||
};
|
||||
});
|
||||
}
|
||||
// 获取所有的菜单
|
||||
async function getMenuPermOptions() {
|
||||
console.log(shopUser.userInfo);
|
||||
let arr =
|
||||
shopUser.userInfo.account === "admin" ? await MenuAPI.getList() : await MenuAPI.getRoutes();
|
||||
menuPermOptions.value = returnMenu(arr);
|
||||
}
|
||||
getMenuPermOptions();
|
||||
|
||||
onMounted(() => {
|
||||
console.log(modelValue.value);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => modelValue.value,
|
||||
(newval) => {}
|
||||
);
|
||||
|
||||
function getPerms() {
|
||||
return permTreeRef.value.getCheckedKeys();
|
||||
}
|
||||
function reset() {
|
||||
console.log("reset");
|
||||
permTreeRef.value.setCheckedKeys([]);
|
||||
}
|
||||
function setChecked(checkedMenuIds) {
|
||||
checkedMenuIds.forEach((menuId) => {
|
||||
console.log(menuId);
|
||||
permTreeRef.value.setChecked(menuId, true, false);
|
||||
});
|
||||
}
|
||||
defineExpose({
|
||||
getPerms,
|
||||
setChecked,
|
||||
reset,
|
||||
});
|
||||
</script>
|
||||
495
src/views/admin/system/role/index.vue
Normal file
495
src/views/admin/system/role/index.vue
Normal file
@@ -0,0 +1,495 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="search-bar">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item prop="keywords" label="关键字">
|
||||
<el-input
|
||||
v-model="queryParams.key"
|
||||
placeholder="角色名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="refresh" @click="handleResetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-card shadow="never">
|
||||
<div class="mb-10px">
|
||||
<el-button type="primary" icon="plus" @click="handleOpenDialog()">新增</el-button>
|
||||
<el-button type="danger" :disabled="ids.length === 0" icon="delete" @click="handleDelete()">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="roleList"
|
||||
highlight-current-row
|
||||
:border="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="角色名称" prop="name" />
|
||||
<el-table-column label="角色级别" prop="level" />
|
||||
<el-table-column label="描述" prop="description" />
|
||||
<el-table-column label="创建日期" prop="createTime" />
|
||||
<el-table-column fixed="right" label="操作" width="220">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
icon="position"
|
||||
@click="handleOpenAssignPermDialog(scope.row)"
|
||||
>
|
||||
分配菜单
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
icon="edit"
|
||||
@click="handleOpenDialog(scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
v-model:total="total"
|
||||
v-model:page="queryParams.page"
|
||||
v-model:limit="queryParams.size"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 角色表单弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialog.visible"
|
||||
:title="dialog.title"
|
||||
width="500px"
|
||||
@close="handleCloseDialog"
|
||||
>
|
||||
<el-form ref="addRequestRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="角色名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入角色名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色等级" prop="level">
|
||||
<el-input-number placeholder="角色等级" v-model="formData.level"></el-input-number>
|
||||
</el-form-item>
|
||||
|
||||
<!-- <el-form-item label="数据菜单" prop="dataScope">
|
||||
<el-select v-model="formData.dataScope">
|
||||
<el-option :key="0" label="全部数据" :value="0" />
|
||||
<el-option :key="1" label="部门及子部门数据" :value="1" />
|
||||
<el-option :key="2" label="本部门数据" :value="2" />
|
||||
<el-option :key="3" label="本人数据" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input type="textarea" v-model="formData.description" placeholder="描述" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="菜单分配" prop="menuIdList">
|
||||
<menuSelect ref="refmenuSelect" v-model="formData.menuIdList"></menuSelect>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
<el-button @click="handleCloseDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 分配菜单弹窗 -->
|
||||
<el-drawer
|
||||
v-model="assignPermDialogVisible"
|
||||
:title="'【' + checkedRole.name + '】菜单分配'"
|
||||
size="500"
|
||||
>
|
||||
<div class="flex-x-between">
|
||||
<el-input v-model="permKeywords" clearable class="w-[150px]" placeholder="菜单菜单名称">
|
||||
<template #prefix>
|
||||
<Search />
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<div class="flex-center ml-5">
|
||||
<el-button type="primary" size="small" plain @click="togglePermTree">
|
||||
<template #icon>
|
||||
<Switch />
|
||||
</template>
|
||||
{{ isExpanded ? "收缩" : "展开" }}
|
||||
</el-button>
|
||||
<el-checkbox
|
||||
v-model="parentChildLinked"
|
||||
class="ml-5"
|
||||
@change="handleparentChildLinkedChange"
|
||||
>
|
||||
父子联动
|
||||
</el-checkbox>
|
||||
|
||||
<el-tooltip placement="bottom">
|
||||
<template #content>
|
||||
如果只需勾选菜单菜单,不需要勾选子菜单或者按钮菜单,请关闭父子联动
|
||||
</template>
|
||||
<el-icon class="ml-1 color-[--el-color-primary] inline-block cursor-pointer">
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tree
|
||||
ref="permTreeRef"
|
||||
node-key="value"
|
||||
show-checkbox
|
||||
:data="menuPermOptions"
|
||||
:filter-node-method="handlePermFilter"
|
||||
:default-expand-all="true"
|
||||
:check-strictly="!parentChildLinked"
|
||||
class="mt-5"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
{{ data.label }}
|
||||
</template>
|
||||
</el-tree>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleAssignPermSubmit">确 定</el-button>
|
||||
<el-button @click="assignPermDialogVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "Role",
|
||||
inheritAttrs: false,
|
||||
});
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const shopUser = useUserStore();
|
||||
import menuSelect from "./components/menus.vue";
|
||||
import RoleApi, { SysRole, addRequest, getListRequest } from "@/api/account/role";
|
||||
import MenuAPI, { type RouteVO } from "@/api/account/menu";
|
||||
|
||||
const queryFormRef = ref();
|
||||
const addRequestRef = ref();
|
||||
const refmenuSelect = ref();
|
||||
const permTreeRef = ref();
|
||||
|
||||
const loading = ref(false);
|
||||
const ids = ref<number[]>([]);
|
||||
const total = ref(0);
|
||||
|
||||
const queryParams = reactive<getListRequest>({
|
||||
page: 1,
|
||||
size: 10,
|
||||
key: "",
|
||||
});
|
||||
|
||||
// 角色表格数据
|
||||
const roleList = ref<SysRole[]>();
|
||||
// 菜单菜单下拉
|
||||
const menuPermOptions = ref<RouteVO[]>([]);
|
||||
|
||||
// 弹窗
|
||||
const dialog = reactive({
|
||||
title: "",
|
||||
visible: false,
|
||||
});
|
||||
// 角色表单
|
||||
const formData = reactive<addRequest>({
|
||||
// sort: 1,
|
||||
// status: 1,
|
||||
id: null,
|
||||
name: "",
|
||||
level: 0,
|
||||
menuIdList: [],
|
||||
description: "",
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
|
||||
level: [{ required: false, message: "请输入角色等级", trigger: "blur" }],
|
||||
});
|
||||
|
||||
// 选中的角色
|
||||
interface CheckedRole {
|
||||
id?: number;
|
||||
name?: string;
|
||||
}
|
||||
const checkedRole = ref<CheckedRole>({});
|
||||
const assignPermDialogVisible = ref(false);
|
||||
|
||||
const permKeywords = ref("");
|
||||
const isExpanded = ref(true);
|
||||
|
||||
const parentChildLinked = ref(true);
|
||||
|
||||
// 查询
|
||||
function handleQuery() {
|
||||
loading.value = true;
|
||||
RoleApi.getList(queryParams)
|
||||
.then((data) => {
|
||||
roleList.value = data.records;
|
||||
total.value = data.totalRow;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
function handleResetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
queryParams.page = 1;
|
||||
queryParams.size = 10;
|
||||
queryParams.key = "";
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
// 行复选框选中
|
||||
function handleSelectionChange(selection: any) {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
}
|
||||
|
||||
// 打开角色弹窗
|
||||
async function handleOpenDialog(row: SysRole) {
|
||||
dialog.visible = true;
|
||||
if (row && row.id) {
|
||||
dialog.title = "修改角色";
|
||||
//获取角色菜单列表
|
||||
const data = await RoleApi.getMenu(row.id);
|
||||
console.log(data);
|
||||
Object.assign(formData, row);
|
||||
formData.menuIdList = data;
|
||||
setTimeout(() => {
|
||||
refmenuSelect.value.setChecked(data);
|
||||
}, 300);
|
||||
console.log(formData);
|
||||
} else {
|
||||
dialog.title = "新增角色";
|
||||
}
|
||||
}
|
||||
|
||||
// 提交角色表单
|
||||
function handleSubmit() {
|
||||
addRequestRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
const checkedMenuIds: number[] = refmenuSelect.value.getPerms();
|
||||
loading.value = true;
|
||||
const roleId = formData.id;
|
||||
if (roleId) {
|
||||
RoleApi.update(roleId, { ...formData, menuIdList: checkedMenuIds })
|
||||
.then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
} else {
|
||||
delete formData.id;
|
||||
|
||||
RoleApi.add({ ...formData, menuIdList: checkedMenuIds })
|
||||
.then(() => {
|
||||
ElMessage.success("新增成功");
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function handleCloseDialog() {
|
||||
addRequestRef.value.resetFields();
|
||||
addRequestRef.value.clearValidate();
|
||||
refmenuSelect.value.reset();
|
||||
formData.id = undefined;
|
||||
formData.sort = 1;
|
||||
formData.status = 1;
|
||||
dialog.visible = false;
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
function handleDelete(roleId?: number) {
|
||||
const roleIds = [roleId || ids.value].join(",");
|
||||
if (!roleIds) {
|
||||
ElMessage.warning("请勾选删除项");
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(
|
||||
() => {
|
||||
loading.value = true;
|
||||
RoleApi.delete({ id: roleId ?? null })
|
||||
.then(() => {
|
||||
ElMessage.success("删除成功");
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
},
|
||||
() => {
|
||||
ElMessage.info("已取消删除");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
interface typeRoute extends RouteVO {
|
||||
label: string | number;
|
||||
value: string | number;
|
||||
children: typeRoute[];
|
||||
}
|
||||
|
||||
function returnMenu(menu) {
|
||||
return menu.map((v) => {
|
||||
return {
|
||||
...v,
|
||||
label: v.title,
|
||||
value: v.menuId,
|
||||
children: v.children ? returnMenu(v.children) : [],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 获取所有的菜单
|
||||
async function getMenuPermOptions() {
|
||||
let arr =
|
||||
shopUser.userInfo.account === "admin" ? await MenuAPI.getList() : await MenuAPI.getRoutes();
|
||||
menuPermOptions.value = returnMenu(arr);
|
||||
}
|
||||
getMenuPermOptions();
|
||||
// 打开分配菜单菜单弹窗
|
||||
async function handleOpenAssignPermDialog(row: SysRole) {
|
||||
const roleId = row.id;
|
||||
if (roleId) {
|
||||
assignPermDialogVisible.value = true;
|
||||
loading.value = true;
|
||||
|
||||
checkedRole.value.id = roleId;
|
||||
checkedRole.value.name = row.name as string;
|
||||
|
||||
// 回显角色已拥有的菜单
|
||||
RoleApi.getMenu(roleId)
|
||||
.then((data) => {
|
||||
const checkedMenuIds = data;
|
||||
checkedMenuIds.forEach((menuId) => permTreeRef.value!.setChecked(menuId, true, false));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 分配菜单菜单提交
|
||||
function handleAssignPermSubmit() {
|
||||
const roleId = checkedRole.value.id;
|
||||
const name = checkedRole.value.name;
|
||||
if (roleId) {
|
||||
const checkedMenuIds: number[] = permTreeRef
|
||||
.value!.getCheckedNodes(false, true)
|
||||
.map((node: any) => node.value);
|
||||
|
||||
loading.value = true;
|
||||
RoleApi.update(roleId, { name, menuIdList: checkedMenuIds })
|
||||
.then(() => {
|
||||
ElMessage.success("分配菜单成功");
|
||||
assignPermDialogVisible.value = false;
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 展开/收缩 菜单菜单树
|
||||
function togglePermTree() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
if (permTreeRef.value) {
|
||||
Object.values(permTreeRef.value.store.nodesMap).forEach((node: any) => {
|
||||
if (isExpanded.value) {
|
||||
node.expand();
|
||||
} else {
|
||||
node.collapse();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function editTogglePermTree() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
if (permTreeRef.value) {
|
||||
Object.values(permTreeRef.value.store.nodesMap).forEach((node: any) => {
|
||||
if (isExpanded.value) {
|
||||
node.expand();
|
||||
} else {
|
||||
node.collapse();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单筛选
|
||||
watch(permKeywords, (val) => {
|
||||
permTreeRef.value!.filter(val);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => assignPermDialogVisible.value,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
permTreeRef.value.setCheckedKeys([]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function handlePermFilter(
|
||||
value: string,
|
||||
data: {
|
||||
[key: string]: any;
|
||||
}
|
||||
) {
|
||||
if (!value) return true;
|
||||
return data.label.includes(value);
|
||||
}
|
||||
|
||||
// 父子菜单节点是否联动
|
||||
function handleparentChildLinkedChange(val: any) {
|
||||
parentChildLinked.value = val;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
1
src/views/admin/system/user/index.vue
Normal file
1
src/views/admin/system/user/index.vue
Normal file
@@ -0,0 +1 @@
|
||||
<template></template>
|
||||
296
src/views/admin/system/version/components/version-file.vue
Normal file
296
src/views/admin/system/version/components/version-file.vue
Normal file
@@ -0,0 +1,296 @@
|
||||
<!-- 文件上传组件 -->
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
v-model:file-list="fileList"
|
||||
:auto-upload="true"
|
||||
:style="props.style"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:http-request="handleUpload"
|
||||
:on-progress="handleProgress"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:accept="props.accept"
|
||||
:limit="props.limit"
|
||||
multiple
|
||||
>
|
||||
<!-- 上传文件按钮 -->
|
||||
<el-button type="primary" :disabled="fileList.length >= props.limit">
|
||||
{{ props.uploadBtnText }}
|
||||
</el-button>
|
||||
|
||||
<!-- 文件列表 -->
|
||||
<template #file="{ file }">
|
||||
<div class="el-upload-list__item-info">
|
||||
<a class="el-upload-list__item-name" @click="handleDownload(file)">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span class="el-upload-list__item-file-name">{{ file.name }}</span>
|
||||
<span class="el-icon--close" @click="handleRemove(file.url!)">
|
||||
<el-icon><Close /></el-icon>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
|
||||
<el-progress
|
||||
:style="{
|
||||
display: showProgress ? 'inline-flex' : 'none',
|
||||
width: '100%',
|
||||
}"
|
||||
:percentage="progressPercent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
UploadRawFile,
|
||||
UploadUserFile,
|
||||
UploadProgressEvent,
|
||||
UploadRequestOptions,
|
||||
} from "element-plus";
|
||||
import VersionApi from "@/api/system/version";
|
||||
import OSS from "@/utils/oss-upload.js";
|
||||
let ossClient: any = null;
|
||||
async function getCredentials() {
|
||||
const res = await VersionApi.getCredentials();
|
||||
ossClient = new OSS({ ...res, stsToken: res.securityToken });
|
||||
console.log(ossClient);
|
||||
}
|
||||
onMounted(() => {
|
||||
getCredentials();
|
||||
});
|
||||
import CommonApi, { FileInfo, uploadResponse } from "@/api/account/common";
|
||||
|
||||
const props = defineProps({
|
||||
version: {
|
||||
type: [Boolean, Number],
|
||||
default: "",
|
||||
},
|
||||
/**
|
||||
* 请求携带的额外参数
|
||||
*/
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
/**
|
||||
* 上传文件的参数名
|
||||
*/
|
||||
name: {
|
||||
type: String,
|
||||
default: "file",
|
||||
},
|
||||
/**
|
||||
* 文件上传数量限制
|
||||
*/
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
/**
|
||||
* 单个文件上传大小限制(单位MB)
|
||||
*/
|
||||
maxFileSize: {
|
||||
type: Number,
|
||||
default: 300,
|
||||
},
|
||||
/**
|
||||
* 上传文件类型
|
||||
*/
|
||||
accept: {
|
||||
type: String,
|
||||
default: "*",
|
||||
},
|
||||
/**
|
||||
* 上传按钮文本
|
||||
*/
|
||||
uploadBtnText: {
|
||||
type: String,
|
||||
default: "上传文件",
|
||||
},
|
||||
|
||||
/**
|
||||
* 样式
|
||||
*/
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
width: "300px",
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const modelValue = defineModel("modelValue", {
|
||||
type: [Array] as PropType<string[]>,
|
||||
required: true,
|
||||
default: () => [],
|
||||
});
|
||||
|
||||
const fileList = ref([] as UploadUserFile[]);
|
||||
|
||||
const showProgress = ref(false);
|
||||
const progressPercent = ref(0);
|
||||
|
||||
// 监听 modelValue 转换用于显示的 fileList
|
||||
watch(
|
||||
modelValue,
|
||||
(value) => {
|
||||
fileList.value = value.map((url) => {
|
||||
const name = url.substring(url.lastIndexOf("/") + 1);
|
||||
return {
|
||||
name: name,
|
||||
url: url,
|
||||
} as UploadUserFile;
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 上传前校验
|
||||
*/
|
||||
function handleBeforeUpload(file: UploadRawFile) {
|
||||
// 限制文件大小
|
||||
if (file.size > props.maxFileSize * 1024 * 1024) {
|
||||
ElMessage.warning("上传图片不能大于" + props.maxFileSize + "M");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 上传文件
|
||||
*/
|
||||
function handleUpload(options: UploadRequestOptions) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = options.file;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append(props.name, file);
|
||||
|
||||
// 处理附加参数
|
||||
Object.keys(props.data).forEach((key) => {
|
||||
formData.append(key, props.data[key]);
|
||||
});
|
||||
const name = file.name;
|
||||
showProgress.value = true;
|
||||
ossClient
|
||||
.partUpload(`/version/${props.version}${name.replace(".apk", "")}`, file, (p: number) => {
|
||||
console.log("进度", p);
|
||||
handleProgress({
|
||||
percent: Math.floor(p * 100),
|
||||
lengthComputable: true,
|
||||
loaded: p * file.size,
|
||||
total: file.size,
|
||||
target: null,
|
||||
timeStamp: Date.now(),
|
||||
type: "",
|
||||
eventPhase: 0,
|
||||
bubbles: false,
|
||||
cancelable: false,
|
||||
defaultPrevented: false,
|
||||
isTrusted: true,
|
||||
returnValue: true,
|
||||
srcElement: null,
|
||||
currentTarget: null,
|
||||
composed: false,
|
||||
cancelBubble: false,
|
||||
NONE: 0,
|
||||
CAPTURING_PHASE: 1,
|
||||
AT_TARGET: 2,
|
||||
BUBBLING_PHASE: 3,
|
||||
composedPath: () => [],
|
||||
initEvent: () => {},
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {},
|
||||
});
|
||||
// 这里可以根据进度做相应的处理,例如更新UI等
|
||||
})
|
||||
.then((data: any) => {
|
||||
console.log(data);
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
// CommonApi.upload(formData)
|
||||
// .then((data) => {
|
||||
// resolve(data);
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// reject(error);
|
||||
// });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传进度
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
const handleProgress = (event: UploadProgressEvent) => {
|
||||
progressPercent.value = event.percent;
|
||||
if (progressPercent.value >= 100) {
|
||||
showProgress.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传成功
|
||||
*/
|
||||
const handleSuccess = (fileInfo: string) => {
|
||||
ElMessage.success("上传成功");
|
||||
modelValue.value = [...modelValue.value, fileInfo];
|
||||
};
|
||||
|
||||
const handleError = (error: any) => {
|
||||
ElMessage.error("上传失败");
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*/
|
||||
function handleRemove(fileUrl: string) {
|
||||
// CommonApi.delete(fileUrl).then(() => {
|
||||
modelValue.value = modelValue.value.filter((url) => url !== fileUrl);
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
function handleDownload(file: UploadUserFile) {
|
||||
// const { url, name } = file;
|
||||
// if (url) {
|
||||
// CommonApi.download(url, name);
|
||||
// }
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-upload-list__item .el-icon--close {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
color: var(--el-text-color-regular);
|
||||
cursor: pointer;
|
||||
opacity: 0.75;
|
||||
transition: opacity var(--el-transition-duration);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
:deep(.el-upload-list) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.el-upload-list__item) {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
91
src/views/admin/system/version/config/add.ts
Normal file
91
src/views/admin/system/version/config/add.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import VersionApi, { type addRequest } from "@/api/system/version";
|
||||
import { sourceOptions, typeOptions, isForceOptions } from "./config";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
|
||||
const modalConfig: IModalConfig<addRequest> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "新增版本",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 140,
|
||||
},
|
||||
formAction: function (data) {
|
||||
return VersionApi.add({ ...data, url: typeof data.url === "string" ? data.url : data.url[0] });
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
{
|
||||
label: "渠道",
|
||||
prop: "source",
|
||||
rules: [{ required: true, message: "请选择渠道", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择渠道",
|
||||
},
|
||||
options: sourceOptions,
|
||||
},
|
||||
{
|
||||
label: "类型",
|
||||
prop: "type",
|
||||
rules: [{ required: true, message: "请选择类型", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择类型",
|
||||
},
|
||||
col: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
},
|
||||
options: typeOptions,
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "版本号",
|
||||
prop: "version",
|
||||
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入版本号",
|
||||
},
|
||||
watch: () => { }
|
||||
},
|
||||
{
|
||||
type: "radio",
|
||||
label: "是否强制更新",
|
||||
prop: "isForce",
|
||||
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入版本号",
|
||||
},
|
||||
initialValue: 0,
|
||||
options: isForceOptions,
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "更新提示内容",
|
||||
prop: "message",
|
||||
rules: [{ required: true, message: "请输入更新提示内容", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入更新提示内容",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "custom",
|
||||
label: "版本文件",
|
||||
prop: "url",
|
||||
rules: [{ required: true, message: "请上传版本文件", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请上传版本文件",
|
||||
},
|
||||
hidden: true,
|
||||
initialValue: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 如果有异步数据会修改配置的,推荐用reactive包裹,而纯静态配置的可以直接导出
|
||||
export default reactive(modalConfig);
|
||||
45
src/views/admin/system/version/config/config.ts
Normal file
45
src/views/admin/system/version/config/config.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { property } from "lodash";
|
||||
|
||||
export const sourceOptions: options[] = [
|
||||
{ label: "桌面端", value: "pc" },
|
||||
{ label: "管理端", value: "manager_app" },
|
||||
{ label: "电话机点餐", value: "phone_book " },
|
||||
];
|
||||
export const typeOptions: options[] = [
|
||||
{ label: "windows", value: "0" },
|
||||
{ label: "安卓", value: "1" },
|
||||
{ label: "IOS", value: "2" },
|
||||
];
|
||||
export const isForceOptions: options[] = [
|
||||
{ label: "不强制更新", value: 0 },
|
||||
{ label: "强制更新", value: 1 },
|
||||
];
|
||||
|
||||
export type optionsType = "source" | "type" | "isForce";
|
||||
|
||||
export function returnOptions(type: optionsType) {
|
||||
if (type === "source") {
|
||||
return sourceOptions;
|
||||
}
|
||||
if (type === "type") {
|
||||
return typeOptions;
|
||||
}
|
||||
if (type === "isForce") {
|
||||
return isForceOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export function returnOptionsLabel(optionsType: optionsType, value: string | number) {
|
||||
const options = returnOptions(optionsType);
|
||||
if (!options) {
|
||||
return "";
|
||||
}
|
||||
const option = options.find((item) => item.value === value);
|
||||
return option ? option.label : "";
|
||||
}
|
||||
|
||||
export interface options {
|
||||
label: string;
|
||||
value: string | number;
|
||||
[property: string]: any;
|
||||
}
|
||||
88
src/views/admin/system/version/config/content.ts
Normal file
88
src/views/admin/system/version/config/content.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import VersionApi from "@/api/system/version";
|
||||
import type { editRequest } from "@/api/system/version";
|
||||
import type { IContentConfig } from "@/components/CURD/types";
|
||||
|
||||
const contentConfig: IContentConfig<editRequest> = {
|
||||
pageName: "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: function (params) {
|
||||
return VersionApi.getList();
|
||||
},
|
||||
modifyAction: function (data: any) {
|
||||
return VersionApi.edit(data);
|
||||
},
|
||||
deleteAction: VersionApi.delete,
|
||||
// modifyAction: function (data) {
|
||||
// // return VersionApi.edit(data);
|
||||
// },
|
||||
pk: "id",
|
||||
toolbar: ["add"],
|
||||
defaultToolbar: ["refresh", "filter", "search"],
|
||||
cols: [
|
||||
{ type: "selection", width: 50, align: "center" },
|
||||
{ label: "id", align: "center", prop: "id", width: 100, show: true },
|
||||
{
|
||||
label: "渠道",
|
||||
align: "center",
|
||||
prop: "source",
|
||||
width: 120,
|
||||
templet: "custom",
|
||||
slotName: "options",
|
||||
},
|
||||
{
|
||||
label: "类型",
|
||||
align: "center",
|
||||
prop: "type",
|
||||
width: 120,
|
||||
templet: "custom",
|
||||
slotName: "options",
|
||||
},
|
||||
{
|
||||
label: "版本号",
|
||||
align: "center",
|
||||
width: 120,
|
||||
prop: "version",
|
||||
},
|
||||
|
||||
{
|
||||
label: "是否强制升级",
|
||||
align: "center",
|
||||
prop: "isForce",
|
||||
width: 120,
|
||||
templet: "switch",
|
||||
slotName: "isForce",
|
||||
},
|
||||
{
|
||||
label: "更新内容",
|
||||
align: "center",
|
||||
prop: "message",
|
||||
width: 240,
|
||||
},
|
||||
{
|
||||
label: "下载地址",
|
||||
align: "center",
|
||||
prop: "url",
|
||||
templet: "url",
|
||||
slotName: "url",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 280,
|
||||
templet: "tool",
|
||||
operat: ["edit", "delete"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default contentConfig;
|
||||
86
src/views/admin/system/version/config/edit.ts
Normal file
86
src/views/admin/system/version/config/edit.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import VersionApi, { type editRequest } from "@/api/system/version";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
import { sourceOptions, typeOptions, isForceOptions } from "./config";
|
||||
|
||||
const modalConfig: IModalConfig<editRequest> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "编辑版本",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
pk: "id",
|
||||
formAction: function (data) {
|
||||
return VersionApi.edit({ ...data, url: typeof data.url === "string" ? data.url : data.url[0] });
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
{
|
||||
label: "渠道",
|
||||
prop: "source",
|
||||
rules: [{ required: true, message: "请选择渠道", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择渠道",
|
||||
},
|
||||
options: sourceOptions,
|
||||
},
|
||||
{
|
||||
label: "类型",
|
||||
prop: "type",
|
||||
rules: [{ required: true, message: "请选择类型", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择类型",
|
||||
},
|
||||
col: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
},
|
||||
options: typeOptions,
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "版本号",
|
||||
prop: "version",
|
||||
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入版本号",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "radio",
|
||||
label: "是否强制更新",
|
||||
prop: "isForce",
|
||||
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入版本号",
|
||||
},
|
||||
initialValue: 0,
|
||||
options: isForceOptions,
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
label: "更新提示内容",
|
||||
prop: "message",
|
||||
rules: [{ required: true, message: "请输入更新提示内容", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请输入更新提示内容",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "custom",
|
||||
label: "版本文件",
|
||||
prop: "url",
|
||||
rules: [{ required: true, message: "请上传版本文件", trigger: "blur" }],
|
||||
attrs: {
|
||||
placeholder: "请上传版本文件",
|
||||
},
|
||||
initialValue: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default reactive(modalConfig);
|
||||
21
src/views/admin/system/version/config/search.ts
Normal file
21
src/views/admin/system/version/config/search.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { ISearchConfig } from "@/components/CURD/types";
|
||||
|
||||
const searchConfig: ISearchConfig = {
|
||||
pageName: "sys:user",
|
||||
formItems: [
|
||||
{
|
||||
type: "input",
|
||||
label: "版本号",
|
||||
prop: "keywords",
|
||||
attrs: {
|
||||
placeholder: "请输入版本号",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "200px",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default searchConfig;
|
||||
142
src/views/admin/system/version/index.vue
Normal file
142
src/views/admin/system/version/index.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 列表 -->
|
||||
<!-- 搜索 -->
|
||||
<page-search
|
||||
ref="searchRef"
|
||||
:search-config="searchConfig"
|
||||
@query-click="handleQueryClick"
|
||||
@reset-click="handleResetClick"
|
||||
/>
|
||||
<!-- 列表 -->
|
||||
<page-content
|
||||
ref="contentRef"
|
||||
:content-config="contentConfig"
|
||||
@add-click="handleAddClick"
|
||||
@edit-click="handleEditClick"
|
||||
@export-click="handleExportClick"
|
||||
@search-click="handleSearchClick"
|
||||
@toolbar-click="handleToolbarClick"
|
||||
@operat-click="handleOperatClick"
|
||||
@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 #options="scope">
|
||||
{{ returnOptionsLabel(scope.prop, scope.row[scope.prop]) }}
|
||||
</template>
|
||||
<template #gender="scope">
|
||||
<DictLabel 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="margin-left: 2px"
|
||||
/>
|
||||
</template>
|
||||
</page-content>
|
||||
|
||||
<!-- 新增 -->
|
||||
<page-modal
|
||||
ref="addModalRef"
|
||||
@form-data-change="handleFormDataChange"
|
||||
:modal-config="addModalConfig"
|
||||
@submit-click="handleSubmitClick"
|
||||
>
|
||||
<template #url="scope">
|
||||
<version-file
|
||||
:version="version"
|
||||
v-model="scope.formData[scope.prop]"
|
||||
v-bind="scope.attrs"
|
||||
></version-file>
|
||||
</template>
|
||||
</page-modal>
|
||||
|
||||
<!-- 编辑 -->
|
||||
<page-modal
|
||||
ref="editModalRef"
|
||||
:modal-config="editModalConfig"
|
||||
@submit-click="handleSubmitClick"
|
||||
>
|
||||
<template #url="scope">
|
||||
<version-file
|
||||
:version="version"
|
||||
v-model="scope.formData[scope.prop]"
|
||||
v-bind="scope.attrs"
|
||||
></version-file>
|
||||
</template>
|
||||
</page-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import versionFile from "./components/version-file.vue";
|
||||
import VersionApi from "@/api/system/version";
|
||||
import type { IObject, IOperatData } from "@/components/CURD/types";
|
||||
import usePage from "@/components/CURD/usePage";
|
||||
import addModalConfig from "./config/add";
|
||||
import contentConfig from "./config/content";
|
||||
import editModalConfig from "./config/edit";
|
||||
import searchConfig from "./config/search";
|
||||
import { returnOptionsLabel } from "./config/config";
|
||||
|
||||
let version = ref<string | number>("");
|
||||
function handleFormDataChange(type: string, value: string | number) {
|
||||
version.value = value;
|
||||
if (type === "version" && value !== "") {
|
||||
addModalConfig.formItems[5].hidden = false;
|
||||
return;
|
||||
}
|
||||
if (type === "version" && value == "") {
|
||||
addModalConfig.formItems[5].hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
const refVersionFile = ref<any>();
|
||||
const {
|
||||
searchRef,
|
||||
contentRef,
|
||||
addModalRef,
|
||||
editModalRef,
|
||||
handleQueryClick,
|
||||
handleResetClick,
|
||||
// handleAddClick,
|
||||
// handleEditClick,
|
||||
handleSubmitClick,
|
||||
handleExportClick,
|
||||
handleSearchClick,
|
||||
handleFilterChange,
|
||||
} = usePage();
|
||||
|
||||
// 新增
|
||||
async function handleAddClick() {
|
||||
addModalRef.value?.setModalVisible();
|
||||
// addModalConfig.formItems[2]!.attrs!.data =
|
||||
}
|
||||
// 编辑
|
||||
async function handleEditClick(row: IObject) {
|
||||
editModalRef.value?.handleDisabled(false);
|
||||
editModalRef.value?.setModalVisible();
|
||||
// 根据id获取数据进行填充
|
||||
// const data = await VersionApi.getFormData(row.id);
|
||||
console.log({ ...row, url: [row.url] });
|
||||
editModalRef.value?.setFormData({ ...row, url: [row.url] });
|
||||
}
|
||||
1;
|
||||
// 其他工具栏
|
||||
function handleToolbarClick(name: string) {
|
||||
console.log(name);
|
||||
if (name === "custom1") {
|
||||
ElMessage.success("点击了自定义1按钮");
|
||||
}
|
||||
}
|
||||
// 其他操作列
|
||||
async function handleOperatClick(data: IOperatData) {
|
||||
console.log(data);
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user