refactor ts

This commit is contained in:
LiuHao
2023-04-02 01:01:56 +08:00
parent 5c87f1cb2c
commit 251d2411f2
264 changed files with 15432 additions and 13015 deletions

View File

@ -1,403 +1,357 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="key键" prop="testKey">
<el-input
v-model="queryParams.testKey"
placeholder="请输入key键"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="值" prop="value">
<el-input
v-model="queryParams.value"
placeholder="请输入值"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="search" @click="handlePage">搜索(自定义分页接口)</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['demo:demo:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['demo:demo:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['demo:demo:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Upload"
@click="handleImport"
v-hasPermi="['demo:demo:import']"
>导入(校验)</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['demo:demo:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键" align="center" prop="id" v-if="columns[0].visible"/>
<el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible"/>
<el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible"/>
<el-table-column label="排序号" align="center" prop="orderNum" v-if="columns[3].visible"/>
<el-table-column label="key键" align="center" prop="testKey" v-if="columns[4].visible"/>
<el-table-column label="值" align="center" prop="value" v-if="columns[5].visible"/>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="createByName" v-if="columns[7].visible" />
<el-table-column label="更新时间" align="center" prop="updateTime" v-if="columns[8].visible" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新人" align="center" prop="updateByName" v-if="columns[9].visible" />
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改测试单表对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="demoRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="部门id" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入部门id" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="form.userId" placeholder="请输入用户id" />
</el-form-item>
<el-form-item label="排序号" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入排序号" />
</el-form-item>
<el-form-item label="key键" prop="testKey">
<el-input v-model="form.testKey" placeholder="请输入key键" />
</el-form-item>
<el-form-item label="值" prop="value">
<el-input v-model="form.value" placeholder="请输入值" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker clearable
v-model="form.createTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择创建时间">
</el-date-picker>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload
ref="uploadRef"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script setup name="Demo">
<script setup name="Demo" lang="ts">
import { listDemo, pageDemo, getDemo, delDemo, addDemo, updateDemo } from "@/api/demo/demo";
import {getToken} from "@/utils/auth";
import { getToken } from "@/utils/auth";
import { ComponentInternalInstance } from "vue";
import { ElUpload, UploadFile, UploadFiles, DateModelType } from 'element-plus';
import { DemoForm, DemoQuery, DemoVO } from "@/api/demo/types";
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const demoList = ref([]);
const open = ref(false);
const demoList = ref<DemoVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([])
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const daterangeCreateTime = ref([]);
const daterangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
/*** 用户导入参数 */
const upload = reactive({
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "demo/demo/importData"
const demoFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const uploadRef = ref(ElUpload);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
/** 用户导入参数 */
const upload = reactive<ImportOption>({
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "demo/demo/importData"
})
// 列显隐信息
const columns = ref([
{ key: 0, label: `主键`, visible: false },
{ key: 1, label: `部门id`, visible: true },
{ key: 2, label: `用户id`, visible: true },
{ key: 3, label: `排序号`, visible: true },
{ key: 4, label: `key键`, visible: true },
{ key: 5, label: ``, visible: true },
{ key: 6, label: `创建时间`, visible: true },
{ key: 7, label: `创建人`, visible: true },
{ key: 8, label: `更新时间`, visible: true },
{ key: 9, label: `更新人`, visible: true }
const columns = ref<FieldOption[]>([
{ key: 0, label: `主键`, visible: false },
{ key: 1, label: `部门id`, visible: true },
{ key: 2, label: `用户id`, visible: true },
{ key: 3, label: `排序号`, visible: true },
{ key: 4, label: `key键`, visible: true },
{ key: 5, label: ``, visible: true },
{ key: 6, label: `创建时间`, visible: true },
{ key: 7, label: `创建人`, visible: true },
{ key: 8, label: `更新时间`, visible: true },
{ key: 9, label: `更新人`, visible: true }
]);
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
testKey: undefined,
value: undefined,
createTime: undefined,
},
rules: {
testKey: [
{ required: true, message: "key键不能为空", trigger: "blur" }
],
value: [
{ required: true, message: "值不能为空", trigger: "blur" }
],
}
const initDataForm: DemoForm = {
id: undefined,
deptId: undefined,
userId: undefined,
orderNum: 0,
testKey: '',
value: '',
version: '',
ossConfigId: undefined,
}
const data = reactive<PageData<DemoForm, DemoQuery>>({
form: { ...initDataForm },
queryParams: {
pageNum: 1,
pageSize: 10,
testKey: '',
value: '',
createTime: '',
},
rules: {
testKey: [{ required: true, message: "key键不能为空", trigger: "blur" }],
value: [{ required: true, message: "值不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询OSS对象存储列表 */
function getList() {
loading.value = true;
listDemo(proxy.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(response => {
demoList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getList = async () => {
loading.value = true;
const res = await listDemo(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime"));
demoList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 自定义分页查询 */
function getPage() {
loading.value = true;
pageDemo(proxy.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(response => {
demoList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getPage = async () => {
loading.value = true;
const res = await pageDemo(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime"));
demoList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
deptId: undefined,
userId: undefined,
orderNum: undefined,
testKey: undefined,
value: undefined,
version: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
delFlag: undefined
};
proxy.resetForm("demoRef");
const reset = () => {
form.value = { ...initDataForm };
demoFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 搜索按钮操作 */
function handlePage() {
queryParams.value.pageNum = 1;
getList();
const handlePage = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
daterangeCreateTime.value = [];
proxy.resetForm("queryRef");
handleQuery();
const resetQuery = () => {
daterangeCreateTime.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
const handleSelectionChange = (selection: DemoVO[]) => {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加测试单表";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加测试单表";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
loading.value = true;
reset();
const ids = row.id || ids.value;
getDemo(ids).then((response) => {
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改测试单表";
});
const handleUpdate = async (row?: DemoVO) => {
loading.value = true;
dialog.visible = true;
dialog.title = "修改测试单表";
const _ids = row?.id || ids.value[0];
const res = await getDemo(_ids);
nextTick(() => {
reset();
Object.assign(form.value, res.data)
loading.value = false;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["demoRef"].validate(valid => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId != null) {
updateDemo(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} else {
addDemo(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
}
}
});
const submitForm = () => {
demoFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId) {
await updateDemo(form.value).finally(() => buttonLoading.value = false);
} else {
await addDemo(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const ids = row.id || ids.value;
proxy.$modal.confirm('是否确认删除测试单表编号为"' + ids + '"的数据项?').then(() => {
loading.value = true;
return delDemo(ids);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).finally(() => {
loading.value = false;
});
const handleDelete = async (row?: DemoVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除测试单表编号为"' + _ids + '"的数据项?');
await delDemo(_ids).finally(() => loading.value = false);
loading.value = false;
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导入按钮操作 */
function handleImport() {
upload.title = "测试导入";
upload.open = true;
const handleImport = () => {
upload.title = "测试导入";
upload.open = true;
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("demo/demo/export", {
...queryParams.value,
},`demo_${new Date().getTime()}.xlsx`);
const handleExport = () => {
proxy?.download("demo/demo/export", {
...queryParams.value,
}, `demo_${new Date().getTime()}.xlsx`);
}
/**文件上传中处理 */
const handleFileUploadProgress = (event, file, fileList) => {
upload.isUploading = true;
const handleFileUploadProgress = () => {
upload.isUploading = true;
}
/** 文件上传成功处理 */
const handleFileSuccess = (response, file, fileList) => {
upload.open = false;
upload.isUploading = false;
proxy.$refs["uploadRef"].clearFiles();
proxy.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
getList();
const handleFileSuccess = (res: any, file: UploadFile, fileList: UploadFiles) => {
upload.open = false;
upload.isUploading = false;
uploadRef.value.clearFiles();
ElMessageBox.alert(res.msg, "导入结果", { dangerouslyUseHTMLString: true });
getList();
}
/** 提交上传文件 */
function submitFileForm() {
proxy.$refs["uploadRef"].submit();
uploadRef.value.submit();
}
getList()
getPage()
onMounted(() => {
getList()
getPage()
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="key键" prop="testKey">
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="值" prop="value">
<el-input v-model="queryParams.value" placeholder="请输入值" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="search" @click="handlePage">搜索(自定义分页接口)</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['demo:demo:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['demo:demo:import']">导入(校验)</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键" align="center" prop="id" v-if="columns[0].visible" />
<el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
<el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
<el-table-column label="排序号" align="center" prop="orderNum" v-if="columns[3].visible" />
<el-table-column label="key键" align="center" prop="testKey" v-if="columns[4].visible" />
<el-table-column label="值" align="center" prop="value" v-if="columns[5].visible" />
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="createByName" v-if="columns[7].visible" />
<el-table-column label="更新时间" align="center" prop="updateTime" v-if="columns[8].visible" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新人" align="center" prop="updateByName" v-if="columns[9].visible" />
<el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改测试单表对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="部门id" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入部门id" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="form.userId" placeholder="请输入用户id" />
</el-form-item>
<el-form-item label="排序号" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入排序号" />
</el-form-item>
<el-form-item label="key键" prop="testKey">
<el-input v-model="form.testKey" placeholder="请输入key键" />
</el-form-item>
<el-form-item label="值" prop="value">
<el-input v-model="form.value" placeholder="请输入值" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker clearable v-model="form.createTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择创建时间">
</el-date-picker>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
<el-upload
ref="uploadRef"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,131 +1,31 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="树节点名" prop="treeName">
<el-input
v-model="queryParams.treeName"
placeholder="请输入树节点名"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<script setup name="Tree" lang="ts">
import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree';
import { DemoTreeVO, DemoTreeForm, DemoTreeOptionsType, DemoTreeQuery } from '@/api/demo/types';
import { ComponentInternalInstance } from 'vue';
import { ElTree, ElForm, ElTable, DateModelType } from 'element-plus';
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['demo:tree:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
<el-table
v-if="refreshTable"
v-loading="loading"
:data="treeList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column label="父id" prop="parentId" v-if="columns[0].visible" />
<el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
<el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
<el-table-column label="树节点名" align="center" prop="treeName" v-if="columns[3].visible" />
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[4].visible" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改测试树表对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="treeRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="父id" prop="parentId">
<treeselect
v-model:value="form.parentId"
:options="treeOptions"
:objMap="{ value: 'id', label: 'true_name', children: 'children' }"
placeholder="请选择父id"
/>
</el-form-item>
<el-form-item label="部门id" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入部门id" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="form.userId" placeholder="请输入用户id" />
</el-form-item>
<el-form-item label="树节点名" prop="treeName">
<el-input v-model="form.treeName" placeholder="请输入树节点名" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Tree">
import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
const { proxy } = getCurrentInstance();
const treeList = ref([]);
const open = ref(false);
const treeList = ref<DemoTreeVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
const treeOptions = ref(undefined);
const daterangeCreateTime = ref([]);
const treeOptions = ref<DemoTreeOptionsType[]>([]);
const daterangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
const treeRef = ref(ElTree);
const qeuryFormRef = ref(ElForm);
const demoTreeTableRef = ref(ElTable)
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
// 列显隐信息
const columns = ref([
const columns = ref<FieldOption[]>([
{ key: 0, label: `父id`, visible: false },
{ key: 1, label: `部门id`, visible: true },
{ key: 2, label: `用户id`, visible: true },
@ -133,128 +33,132 @@ const columns = ref([
{ key: 4, label: `创建时间`, visible: true }
]);
const data = reactive({
const initFormData = {
id: undefined,
parentId: undefined,
deptId: undefined,
userId: undefined,
treeName: ''
}
const data = reactive<PageData<DemoTreeForm, DemoTreeQuery>>({
// 查询参数
queryParams: {
treeName: null,
createTime: null,
treeName: '',
createTime: '',
},
// 表单参数
form: {},
form: {...initFormData},
// 表单校验
rules: {
treeName: [
{ required: true, message: "树节点名不能为空", trigger: "blur" }
],
treeName: [{ required: true, message: "树节点名不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询测试树表列表 */
function getList() {
const getList = () => {
loading.value = true;
listTree(proxy.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(response => {
treeList.value = proxy.handleTree(response.data, "id", "parentId");
total.value = response.total;
listTree(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(res => {
const data = proxy?.handleTree<DemoTreeVO>(res.data, "id", "parentId");
if (data) {
treeList.value = data
}
loading.value = false;
});
}
/** 查询部门下拉树结构 */
async function getTreeselect() {
await listTree().then(response => {
treeOptions.value = [];
const data = { id: 0, treeName: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "id", "parentId");
treeOptions.value.push(data);
const getTreeSelect = async () => {
listTree(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(res => {
const topData: DemoTreeOptionsType = { id: 0, treeName: '顶级节点', children: [] };
topData.children = proxy?.handleTree<DemoTreeOptionsType>(res.data, "id", "parentId");
treeOptions.value.push(topData);
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
parentId: undefined,
deptId: undefined,
userId: undefined,
treeName: undefined,
version: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
delFlag: undefined
};
proxy.resetForm("treeRef");
const reset = () => {
form.value = {...initFormData}
treeRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
daterangeCreateTime.value = [];
proxy.resetForm("queryRef");
const resetQuery = () => {
daterangeCreateTime.value = ['', ''];
qeuryFormRef.value.resetFields();
handleQuery();
}
/** 新增按钮操作 */
async function handleAdd(row) {
reset();
await getTreeselect();
if (row != null && row.id) {
form.value.parentId = row.id;
} else {
form.value.parentId = 0;
}
open.value = true;
title.value = "添加测试树表";
const handleAdd = (row?: DemoTreeVO) => {
dialog.visible = true;
dialog.title = "添加测试树表";
nextTick(() => {
reset();
getTreeSelect();
if (row != null && row.id) {
form.value.parentId = row.id;
} else {
form.value.parentId = 0;
}
})
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
const handleToggleExpandAll = () => {
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
toggleExpandAll(treeList.value, isExpandAll.value)
}
/** 展开/折叠所有 */
const toggleExpandAll = (data: DemoTreeVO[], status: boolean) => {
data.forEach((item) => {
demoTreeTableRef.value.toggleRowExpansion(item, status)
if(item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
}
/** 修改按钮操作 */
async function handleUpdate(row) {
const handleUpdate = async (row: DemoTreeVO) => {
loading.value = true;
reset();
await getTreeselect();
if (row != null) {
form.value.parentId = row.id;
}
getTree(row.id).then((response) => {
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改测试树表";
});
dialog.visible = true;
dialog.title = "修改测试树表";
nextTick(async () => {
reset();
getTreeSelect();
if (row) {
form.value.parentId = row.id;
}
getTree(row.id).then((response) => {
loading.value = false;
form.value = response.data;
});
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["treeRef"].validate(valid => {
const submitForm = () => {
treeRef.value.validate((valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId != null) {
updateTree(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
if (form.value.id != null) {
updateTree(form.value).then(() => {
proxy?.$modal.msgSuccess("修改成功");
dialog.visible = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} else {
addTree(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
addTree(form.value).then(() => {
proxy?.$modal.msgSuccess("新增成功");
dialog.visible = false;
getList();
}).finally(() => {
buttonLoading.value = false;
@ -264,18 +168,126 @@ function submitForm() {
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除测试单表编号为"' + row.id + '"的数据项?').then(() => {
const handleDelete = (row: DemoTreeVO) => {
proxy?.$modal.confirm('是否确认删除测试单表编号为"' + row.id + '"的数据项?').then(() => {
loading.value = true;
return delTree(row.id);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
proxy?.$modal.msgSuccess("删除成功");
}).finally(() => {
loading.value = false;
});
}
getList()
onMounted(() => {
getList()
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="qeuryFormRef" :inline="true" label-width="68px">
<el-form-item label="树节点名" prop="treeName">
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['demo:tree:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar :columns="columns" v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table
v-if="refreshTable"
v-loading="loading"
:data="treeList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
ref="demoTreeTableRef"
>
<el-table-column label="父id" prop="parentId" v-if="columns[0].visible" />
<el-table-column label="部门id" align="center" prop="deptId" v-if="columns[1].visible" />
<el-table-column label="用户id" align="center" prop="userId" v-if="columns[2].visible" />
<el-table-column label="树节点名" align="center" prop="treeName" v-if="columns[3].visible" />
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[4].visible" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']"></el-button>
</el-tooltip>
<el-tooltip content="新增" placement="top">
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 添加或修改测试树表对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="treeRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="父id" prop="parentId">
<el-tree-select
v-model="form.parentId"
:data="treeOptions"
:props="{ value: 'id', label: 'treeName', children: 'children' }"
value-key="id"
check-strictly
placeholder="请选择父id"
/>
</el-form-item>
<el-form-item label="部门id" prop="deptId">
<el-input v-model="form.deptId" placeholder="请输入部门id" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="form.userId" placeholder="请输入用户id" />
</el-form-item>
<el-form-item label="树节点名" prop="treeName">
<el-input v-model="form.treeName" placeholder="请输入树节点名" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,42 +1,37 @@
<template>
<div class="errPage-container">
<el-button icon="arrow-left" class="pan-back-btn" @click="back">
返回
</el-button>
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">
401错误!
</h1>
<h2>您没有访问权限</h2>
<h6>对不起您没有访问权限请不要进行非法操作您可以返回主页面</h6>
<ul class="list-unstyled">
<li class="link-type">
<router-link to="/">
回首页
</router-link>
</li>
</ul>
</el-col>
<el-col :span="12">
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
</el-col>
</el-row>
</div>
<div class="errPage-container">
<el-button icon="arrow-left" class="pan-back-btn" @click="back"> 返回 </el-button>
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">401错误!</h1>
<h2>您没有访问权限</h2>
<h6>对不起您没有访问权限请不要进行非法操作您可以返回主页面</h6>
<ul class="list-unstyled">
<li class="link-type">
<router-link to="/"> 回首页 </router-link>
</li>
</ul>
</el-col>
<el-col :span="12">
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream." />
</el-col>
</el-row>
</div>
</template>
<script setup>
import errImage from "@/assets/401_images/401.gif";
<script setup lang="ts">
import errImage from '@/assets/401_images/401.gif';
import { ComponentInternalInstance } from "vue";
let { proxy } = getCurrentInstance();
let { proxy } = getCurrentInstance() as ComponentInternalInstance;
const errGif = ref(errImage + "?" + +new Date());
function back() {
if (proxy.$route.query.noGoBack) {
if (proxy?.$route.query.noGoBack) {
proxy.$router.push({ path: "/" });
} else {
proxy.$router.go(-1);
proxy?.$router.go(-1);
}
}
</script>

View File

@ -1,31 +1,27 @@
<template>
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-404">
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
</div>
<div class="bullshit">
<div class="bullshit__oops">
404错误!
</div>
<div class="bullshit__headline">
{{ message }}
</div>
<div class="bullshit__info">
对不起您正在寻找的页面不存在尝试检查URL的错误然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容
</div>
<router-link to="/index" class="bullshit__return-home">
返回首页
</router-link>
</div>
</div>
</div>
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-404">
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404" />
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404" />
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404" />
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404" />
</div>
<div class="bullshit">
<div class="bullshit__oops">404错误!</div>
<div class="bullshit__headline">
{{ message }}
</div>
<div class="bullshit__info">
对不起您正在寻找的页面不存在尝试检查URL的错误然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容
</div>
<router-link to="/index" class="bullshit__return-home"> 返回首页 </router-link>
</div>
</div>
</div>
</template>
<script setup>
<script setup lang="ts">
let message = computed(() => {
return '找不到网页!'
})

View File

@ -1,139 +1,103 @@
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>RuoYi-Vue-Plus多租户管理系统</h2>
<p>
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架)
<br/>
* 前端开发框架 Vue3TSElement Plus<br/>
* 后端开发框架 Spring Boot<br/>
* 容器框架 Undertow 基于 Netty 的高性能容器<br/>
* 权限认证框架 Sa-Token 支持多终端认证系统<br/>
* 关系数据库 MySQL 适配 8.X 最低 5.7<br/>
* 缓存数据库 Redis 适配 6.X 最低 4.X<br/>
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br/>
* 数据库框架 p6spy 更强劲的 SQL 分析<br/>
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br/>
* 序列化框架 Jackson 统一使用 jackson 高效可靠<br/>
* Redis客户端 Redisson 性能强劲API丰富<br/>
* 分布式限流 Redisson 全局请求IP集群ID 多种限流<br/>
* 分布式锁 Lock4j 注解锁工具锁 多种多样<br/>
* 分布式幂等 Lock4j 基于分布式锁实现<br/>
* 分布式链路追踪 SkyWalking 支持链路追踪网格分析度量聚合可视化<br/>
* 分布式任务调度 Xxl-Job 高性能 高可靠 易扩展<br/>
* 文件存储 Minio 本地存储<br/>
* 文件存储 七牛阿里腾讯 云存储<br/>
* 监控框架 SpringBoot-Admin 全方位服务监控<br/>
* 校验框架 Validation 增强接口安全性 严谨性<br/>
* Excel框架 Alibaba EasyExcel 性能优异 扩展性强<br/>
* 文档框架 SpringDocjavadoc 无注解零入侵基于java注释<br/>
* 工具类框架 HutoolLombok 减少代码冗余 增加安全性<br/>
* 代码生成器 适配MPSpringDoc规范化代码 一键生成前后端代码<br/>
* 部署方式 Docker 容器编排 一键部署业务集群<br/>
* 国际化 SpringMessage Spring标准国际化方案<br/>
</p>
<p>
<b>当前版本:</b> <span>v5.0.0</span>
</p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')"
>访问码云</el-button
>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')"
>访问GitHub</el-button
>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/changlog')"
>更新日志</el-button
>
</p>
</el-col>
<div class="app-container home">
<el-row :gutter="20">
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>RuoYi-Vue-Plus多租户管理系统</h2>
<p>
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架)
<br />
* 前端开发框架 Vue3TSElement Plus<br />
* 后端开发框架 Spring Boot<br />
* 容器框架 Undertow 基于 Netty 的高性能容器<br />
* 权限认证框架 Sa-Token 支持多终端认证系统<br />
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
* 缓存数据库 Redis 适配 6.X 最低 4.X<br />
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br />
* 数据库框架 p6spy 更强劲的 SQL 分析<br />
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br />
* 序列化框架 Jackson 统一使用 jackson 高效可靠<br />
* Redis客户端 Redisson 性能强劲API丰富<br />
* 分布式限流 Redisson 全局请求IP集群ID 多种限流<br />
* 分布式锁 Lock4j 注解锁工具锁 多种多样<br />
* 分布式幂等 Lock4j 基于分布式锁实现<br />
* 分布式链路追踪 SkyWalking 支持链路追踪网格分析度量聚合可视化<br />
* 分布式任务调度 Xxl-Job 高性能 高可靠 易扩展<br />
* 文件存储 Minio 本地存储<br />
* 文件存储 七牛阿里腾讯 云存储<br />
* 监控框架 SpringBoot-Admin 全方位服务监控<br />
* 校验框架 Validation 增强接口安全性 严谨性<br />
* Excel框架 Alibaba EasyExcel 性能优异 扩展性强<br />
* 文档框架 SpringDocjavadoc 无注解零入侵基于java注释<br />
* 工具类框架 HutoolLombok 减少代码冗余 增加安全性<br />
* 代码生成器 适配MPSpringDoc规范化代码 一键生成前后端代码<br />
* 部署方式 Docker 容器编排 一键部署业务集群<br />
* 国际化 SpringMessage Spring标准国际化方案<br />
</p>
<p><b>当前版本:</b> <span>v5.0.0</span></p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/changlog')"
>更新日志</el-button
>
</p>
</el-col>
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2>
<p>
RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
<br/>
* 前端开发框架 Vue3TSElement UI<br/>
* 后端开发框架 Spring Boot<br/>
* 微服务开发框架 Spring CloudSpring Cloud Alibaba<br/>
* 容器框架 Undertow 基于 XNIO 的高性能容器<br/>
* 权限认证框架 Sa-TokenJwt 支持多终端认证系统<br/>
* 关系数据库 MySQL 适配 8.X 最低 5.7<br/>
* 关系数据库 Oracle 适配 11g 12c<br/>
* 关系数据库 PostgreSQL 适配 13 14<br/>
* 关系数据库 SQLServer 适配 2017 2019<br/>
* 缓存数据库 Redis 适配 6.X 最低 5.X<br/>
* 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br/>
* 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br/>
* 服务网关 Spring Cloud Gateway 响应式高性能网关<br/>
* 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br/>
* RPC远程调用 Apache Dubbo 原生态使用体验高性能<br/>
* 分布式限流熔断 Alibaba Sentinel 无侵入高扩展<br/>
* 分布式事务 Alibaba Seata 无侵入高扩展 支持 四种模式<br/>
* 分布式消息队列 Spring Cloud Stream 门面框架兼容各种MQ集成<br/>
* 分布式消息队列 Apache Kafka 高性能高速度<br/>
* 分布式消息队列 Apache RocketMQ 高可用功能多样<br/>
* 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br/>
* 分布式搜索引擎 ElasticSearch 业界知名<br/>
* 分布式链路追踪 Apache SkyWalking 链路追踪网格分析度量聚合可视化<br/>
* 分布式日志中心 ELK 业界成熟解决方案<br/>
* 分布式监控 PrometheusGrafana 全方位性能监控<br/>
* 其余与 Vue 版本一致<br/>
</p>
<p>
<b>当前版本:</b> <span>v2.0.0</span>
</p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')"
>访问码云</el-button
>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')"
>访问GitHub</el-button
>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://javalionli.gitee.io/plus-doc/#/ruoyi-cloud-plus/changlog')"
>更新日志</el-button
>
</p>
</el-col>
</el-row>
<el-divider />
</div>
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2>
<p>
RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
<br />
* 前端开发框架 Vue3TSElement UI<br />
* 后端开发框架 Spring Boot<br />
* 微服务开发框架 Spring CloudSpring Cloud Alibaba<br />
* 容器框架 Undertow 基于 XNIO 的高性能容器<br />
* 权限认证框架 Sa-TokenJwt 支持多终端认证系统<br />
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
* 关系数据库 Oracle 适配 11g 12c<br />
* 关系数据库 PostgreSQL 适配 13 14<br />
* 关系数据库 SQLServer 适配 2017 2019<br />
* 缓存数据库 Redis 适配 6.X 最低 5.X<br />
* 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
* 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
* 服务网关 Spring Cloud Gateway 响应式高性能网关<br />
* 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br />
* RPC远程调用 Apache Dubbo 原生态使用体验高性能<br />
* 分布式限流熔断 Alibaba Sentinel 无侵入高扩展<br />
* 分布式事务 Alibaba Seata 无侵入高扩展 支持 四种模式<br />
* 分布式消息队列 Spring Cloud Stream 门面框架兼容各种MQ集成<br />
* 分布式消息队列 Apache Kafka 高性能高速度<br />
* 分布式消息队列 Apache RocketMQ 高可用功能多样<br />
* 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br />
* 分布式搜索引擎 ElasticSearch 业界知名<br />
* 分布式链路追踪 Apache SkyWalking 链路追踪网格分析度量聚合可视化<br />
* 分布式日志中心 ELK 业界成熟解决方案<br />
* 分布式监控 PrometheusGrafana 全方位性能监控<br />
* 其余与 Vue 版本一致<br />
</p>
<p><b>当前版本:</b> <span>v2.0.0</span></p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button>
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://javalionli.gitee.io/plus-doc/#/ruoyi-cloud-plus/changlog')"
>更新日志</el-button
>
</p>
</el-col>
</el-row>
<el-divider />
</div>
</template>
<script setup name="Index">
<script setup name="Index" lang="ts">
function goTarget(url) {
function goTarget(url:string) {
window.open(url, '__blank')
}
</script>
@ -201,4 +165,3 @@ function goTarget(url) {
}
}
</style>

View File

@ -1,185 +1,176 @@
<template>
<div class="login">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
<el-form-item prop="tenantId">
<el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
<el-option
v-for="item in tenantList"
:key="item.tenantId"
:label="item.companyName"
:value="item.tenantId">
</el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select>
</el-form-item>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
size="large"
auto-complete="off"
placeholder="账号"
>
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
size="large"
auto-complete="off"
placeholder="密码"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
size="large"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="large"
type="primary"
style="width:100%;"
@click.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script setup lang="ts">
import { getCodeImg, getTenantList } from '@/api/login';
import Cookies from 'js-cookie';
import { encrypt, decrypt } from '@/utils/jsencrypt';
import { useUserStore } from '@/store/modules/user';
import { LoginData, TenantVO } from '@/api/types';
import { FormRules } from 'element-plus';
import { to } from 'await-to-js';
<script setup>
import { getCodeImg, getTenantList } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const userStore = useUserStore();
const router = useRouter();
const { proxy } = getCurrentInstance();
const loginForm = ref({
const loginForm = ref<LoginData>({
tenantId: "000000",
username: "admin",
password: "admin123",
username: 'admin',
password: 'admin123',
rememberMe: false,
code: "",
uuid: ""
code: '',
uuid: ''
});
const loginRules = {
const loginRules: FormRules = {
tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
};
const codeUrl = ref("");
const codeUrl = ref('');
const loading = ref(false);
// 验证码开关
const captchaEnabled = ref(true);
// 租户开关
const tenantEnabled = ref(true);
// 注册开关
const register = ref(false);
const redirect = ref(undefined);
const loginRef = ref(ElForm);
// 租户列表
const tenantList = ref([]);
const tenantList = ref<TenantVO[]>([]);
function handleLogin() {
proxy.$refs.loginRef.validate(valid => {
const handleLogin = () => {
loginRef.value.validate(async (valid:boolean, fields: any) => {
if (valid) {
loading.value = true;
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) {
Cookies.set("tenantId", loginForm.value.tenantId, { expires: 30 });
Cookies.set("username", loginForm.value.username, { expires: 30 });
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 });
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
Cookies.set('username', loginForm.value.username, { expires: 30 });
Cookies.set('password', String(encrypt(loginForm.value.password)), { expires: 30 });
Cookies.set('rememberMe', String(loginForm.value.rememberMe), { expires: 30 });
} else {
// 否则移除
Cookies.remove("tenantId");
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove("rememberMe");
Cookies.remove('username');
Cookies.remove('password');
Cookies.remove('rememberMe');
}
// 调用action的登录方法
userStore.login(loginForm.value).then(() => {
router.push({ path: redirect.value || "/" });
}).catch(() => {
// prittier-ignore
const [err] = await to(userStore.login(loginForm.value));
if (!err) {
await router.push({ path: redirect.value || '/' });
} else {
loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
getCode();
await getCode();
}
});
}
} else {
console.log('error submit!', fields);
}
});
}
};
function getCode() {
getCodeImg().then(res => {
captchaEnabled.value = res.data.captchaEnabled === undefined ? true : res.data.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.data.img;
loginForm.value.uuid = res.data.uuid;
}
});
}
/**
* 获取验证码
*/
const getCode = async () => {
const res = await getCodeImg();
const { data } = res;
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = 'data:image/gif;base64,' + data.img;
loginForm.value.uuid = data.uuid;
}
};
function initTenantList() {
getTenantList().then(res => {
tenantList.value = res.data;
if (tenantList.value != null && tenantList.value.length !== 0) {
loginForm.value.tenantId = tenantList.value[0].tenantId;
}
});
}
function getCookie() {
const getCookie = () => {
const tenantId = Cookies.get("tenantId");
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get("rememberMe");
const username = Cookies.get('username');
const password = Cookies.get('password');
const rememberMe = Cookies.get('rememberMe');
loginForm.value = {
tenantId: tenantId === undefined ? loginForm.value.tenantId : tenantId,
username: username === undefined ? loginForm.value.username : username,
password: password === undefined ? loginForm.value.password : decrypt(password),
password: password === undefined ? loginForm.value.password : (decrypt(password) as string),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
}
getCode();
initTenantList();
getCookie();
/**
* 获取租户列表
*/
const initTenantList = async () => {
const { data } = await getTenantList();
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
if (tenantEnabled.value) {
tenantList.value = data.voList;
if (tenantList.value != null && tenantList.value.length !== 0) {
loginForm.value.tenantId = tenantList.value[0].tenantId;
}
}
}
onMounted(() => {
getCode();
initTenantList();
getCookie();
});
</script>
<style lang='scss' scoped>
<template>
<div class="login">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
<el-form-item prop="tenantId" v-if="tenantEnabled">
<el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select>
</el-form-item>
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" />
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<style lang="scss" scoped>
.login {
display: flex;
justify-content: center;
@ -233,7 +224,7 @@ getCookie();
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-family: Arial,serif;
font-size: 12px;
letter-spacing: 1px;
}

View File

@ -1,13 +1,9 @@
<template>
<div>
<i-frame v-model:src="url"></i-frame>
</div>
<div>
<i-frame v-model:src="url"></i-frame>
</div>
</template>
<script setup>
import iFrame from '@/components/iFrame'
import { ref } from 'vue';
<script setup lang="ts">
const url = ref(import.meta.env.VITE_APP_MONITRO_ADMIN);
</script>

View File

@ -1,129 +1,188 @@
<template>
<div class="app-container">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<template #header><Monitor style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">基本信息</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%">
<tbody>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">Redis版本</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">运行模式</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">端口</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">客户端数</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">运行时间()</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">使用内存</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">使用CPU</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">内存配置</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">AOF是否开启</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">RDB是否成功</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">Key数量</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
<td class="el-table__cell is-leaf"><div class="cell">网络入口/出口</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<template #header><PieChart style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">命令统计</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="commandstats" style="height: 420px" />
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<template #header><Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="usedmemory" style="height: 420px" />
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="Cache">
<script setup name="Cache" lang="ts">
import { getCache } from '@/api/monitor/cache';
import * as echarts from 'echarts';
import { ComponentInternalInstance } from "vue";
const cache = ref([]);
const commandstats = ref(null);
const usedmemory = ref(null);
const { proxy } = getCurrentInstance();
const cache = ref<any>({});
const commandstats = ref();
const usedmemory = ref();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
function getList() {
proxy.$modal.loading("正在加载缓存监控数据,请稍候!");
getCache().then(response => {
proxy.$modal.closeLoading();
cache.value = response.data;
const getList = async () => {
proxy?.$modal.loading("正在加载缓存监控数据,请稍候!");
const res = await getCache();
proxy?.$modal.closeLoading();
cache.value = res.data;
const commandstatsIntance = echarts.init(commandstats.value, "macarons");
commandstatsIntance.setOption({
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
series: [
{
name: "命令",
type: "pie",
roseType: "radius",
radius: [15, 95],
center: ["50%", "38%"],
data: res.data.commandStats,
animationEasing: "cubicInOut",
animationDuration: 1000
}
]
});
const commandstatsIntance = echarts.init(commandstats.value, "macarons");
commandstatsIntance.setOption({
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
series: [
{
name: "命令",
type: "pie",
roseType: "radius",
radius: [15, 95],
center: ["50%", "38%"],
data: response.data.commandStats,
animationEasing: "cubicInOut",
animationDuration: 1000
}
]
});
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
usedmemoryInstance.setOption({
tooltip: {
formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human
},
series: [
{
name: "峰值",
type: "gauge",
min: 0,
max: 1000,
detail: {
formatter: cache.value.info.used_memory_human
},
data: [
{
value: parseFloat(cache.value.info.used_memory_human),
name: "内存消耗"
}
]
}
]
})
})
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
usedmemoryInstance.setOption({
tooltip: {
formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human
},
series: [
{
name: "峰值",
type: "gauge",
min: 0,
max: 1000,
detail: {
formatter: cache.value.info.used_memory_human
},
data: [
{
value: parseFloat(cache.value.info.used_memory_human),
name: "内存消耗"
}
]
}
]
})
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<template #header>
<Monitor style="width: 1em; height: 1em; vertical-align: middle;" />
<span style="vertical-align: middle;">基本信息</span>
</template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table style="width: 100%">
<tbody>
<tr>
<td class="el-table__cell is-leaf">
<div class="cell">Redis版本</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">运行模式</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.redis_mode === "standalone" ? "单机" : "集群" }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">端口</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">客户端数</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div>
</td>
</tr>
<tr>
<td class="el-table__cell is-leaf">
<div class="cell">运行时间()</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">使用内存</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">使用CPU</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">内存配置</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div>
</td>
</tr>
<tr>
<td class="el-table__cell is-leaf">
<div class="cell">AOF是否开启</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.aof_enabled === "0" ? "否" : "是" }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">RDB是否成功</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">Key数量</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.dbSize">{{ cache.dbSize }}</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell">网络入口/出口</div>
</td>
<td class="el-table__cell is-leaf">
<div class="cell" v-if="cache.info">
{{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps
</div>
</td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<template #header>
<PieChart style="width: 1em; height: 1em; vertical-align: middle;" />
<span style="vertical-align: middle;">命令统计</span>
</template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="commandstats" style="height: 420px" />
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<template #header>
<Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span>
</template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="usedmemory" style="height: 420px" />
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>

View File

@ -1,225 +1,197 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="登录状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_common_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="登录时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<script setup name="Logininfor" lang="ts">
import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
import { ComponentInternalInstance } from "vue";
import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types";
import { DateModelType } from 'element-plus';
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:logininfor:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
@click="handleClean"
v-hasPermi="['monitor:logininfor:remove']"
>清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Unlock"
:disabled="single"
@click="handleUnlock"
v-hasPermi="['monitor:logininfor:unlock']"
>解锁</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['monitor:logininfor:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status"));
<el-table ref="logininforRef" v-loading="loading" :data="logininforList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="访问编号" align="center" prop="infoId" />
<el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="地址" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
<el-table-column label="登录状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
<el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script setup name="Logininfor">
import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/monitor/logininfor";
const { proxy } = getCurrentInstance();
const { sys_common_status } = proxy.useDict("sys_common_status");
const logininforList = ref([]);
const loginInfoList = ref<LoginInfoVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const selectName = ref("");
const selectName = ref<Array<string>>([]);
const total = ref(0);
const dateRange = ref([]);
const defaultSort = ref({ prop: "loginTime", order: "descending" });
const dateRange = ref<[DateModelType,DateModelType]>(['', '']);
const defaultSort = ref<any>({ prop: "loginTime", order: "descending" });
const queryFormRef = ref(ElForm);
const loginInfoTableRef = ref(ElTable);
// 查询参数
const queryParams = ref({
const queryParams = ref<LoginInfoQuery>({
pageNum: 1,
pageSize: 10,
ipaddr: undefined,
userName: undefined,
status: undefined,
orderByColumn: undefined,
isAsc: undefined
ipaddr: '',
userName: '',
status: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
});
/** 查询登录日志列表 */
function getList() {
const getList = async () => {
loading.value = true;
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
logininforList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
loginInfoList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
queryParams.value.pageNum = 1;
proxy.$refs["logininforRef"].sort(defaultSort.value.prop, defaultSort.value.order);
loginInfoTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: LoginInfoVO[]) => {
ids.value = selection.map(item => item.infoId);
multiple.value = !selection.length;
single.value = selection.length != 1;
selectName.value = selection.map(item => item.userName);
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
const handleSortChange = (column: any) => {
queryParams.value.orderByColumn = column.prop;
queryParams.value.isAsc = column.order;
getList();
}
/** 删除按钮操作 */
function handleDelete(row) {
const infoIds = row.infoId || ids.value;
proxy.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function () {
return delLogininfor(infoIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: LoginInfoVO) => {
const infoIds = row?.infoId || ids.value;
await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
await delLoginInfo(infoIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有登录日志数据项?").then(function () {
return cleanLogininfor();
}).then(() => {
getList();
proxy.$modal.msgSuccess("清空成功");
}).catch(() => {});
const handleClean = async () => {
await proxy?.$modal.confirm("是否确认清空所有登录日志数据项?");
await cleanLoginInfo();
getList();
proxy?.$modal.msgSuccess("清空成功");
}
/** 解锁按钮操作 */
function handleUnlock() {
const handleUnlock = async () => {
const username = selectName.value;
proxy.$modal.confirm('是否确认解锁用户"' + username + '"数据项?').then(function () {
return unlockLogininfor(username);
}).then(() => {
proxy.$modal.msgSuccess("用户" + username + "解锁成功");
}).catch(() => {});
await proxy?.$modal.confirm('是否确认解锁用户"' + username + '"数据项?');
await unlockLoginInfo(username);
proxy?.$modal.msgSuccess("用户" + username + "解锁成功");
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/logininfor/export", {
const handleExport = () => {
proxy?.download("monitor/logininfor/export", {
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`);
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
<el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="登录时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:logininfor:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock" v-hasPermi="['monitor:logininfor:unlock']">
解锁
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:logininfor:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table
ref="loginInfoTableRef"
v-loading="loading"
:data="loginInfoList"
@selection-change="handleSelectionChange"
:default-sort="defaultSort"
@sort-change="handleSortChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="访问编号" align="center" prop="infoId" />
<el-table-column
label="用户名称"
align="center"
prop="userName"
:show-overflow-tooltip="true"
sortable="custom"
:sort-orders="['descending', 'ascending']"
/>
<el-table-column label="地址" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
<el-table-column label="登录状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
<el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
</div>
</template>

View File

@ -1,106 +1,104 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
:data="onlineList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
style="width: 100%;"
>
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
<el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
<el-table-column label="登录时间" align="center" prop="loginTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']">强退</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
</div>
</template>
<script setup name="Online">
<script setup name="Online" lang="ts">
import { forceLogout, list as initData } from "@/api/monitor/online";
import { ComponentInternalInstance } from "vue";
import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types";
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const onlineList = ref([]);
const onlineList = ref<OnlineVO[]>([]);
const loading = ref(true);
const total = ref(0);
const pageNum = ref(1);
const pageSize = ref(10);
const queryParams = ref({
ipaddr: undefined,
userName: undefined
const queryFormRef = ref(ElForm);
const queryParams = ref<OnlineQuery>({
pageNum: 1,
pageSize: 10,
ipaddr: '',
userName: ''
});
/** 查询登录日志列表 */
function getList() {
loading.value = true;
initData(queryParams.value).then(response => {
onlineList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getList = async () => {
loading.value = true;
const res = await initData(queryParams.value);
onlineList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 搜索按钮操作 */
function handleQuery() {
pageNum.value = 1;
getList();
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
/** 强退按钮操作 */
function handleForceLogout(row) {
proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
return forceLogout(row.tokenId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleForceLogout = async (row: OnlineVO) => {
await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
await forceLogout(row.tokenId);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<div class="search">
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="登录地址" prop="ipaddr">
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="panel">
<el-table
v-loading="loading"
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
style="width: 100%;"
>
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
<el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
<el-table-column label="登录时间" align="center" prop="loginTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="强退" placement="top">
<el-button link type="primary" icon="Delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']">
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
</div>
</div>
</template>

View File

@ -1,291 +1,295 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="系统模块" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入系统模块"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="操作人员" prop="operName">
<el-input
v-model="queryParams.operName"
placeholder="请输入操作人员"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="类型" prop="businessType">
<el-select
v-model="queryParams.businessType"
placeholder="操作类型"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_oper_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="操作状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_common_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="操作时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<script setup name="Operlog" lang="ts">
import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
import { ComponentInternalInstance } from 'vue';
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
import { DateModelType } from 'element-plus';
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:operlog:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
@click="handleClean"
v-hasPermi="['monitor:operlog:remove']"
>清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['monitor:operlog:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type","sys_common_status"));
<el-table ref="operlogRef" v-loading="loading" :data="operlogList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="日志编号" align="center" prop="operId" />
<el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" />
<el-table-column label="操作类型" align="center" prop="businessType">
<template #default="scope">
<dict-tag :options="sys_oper_type" :value="scope.row.businessType" />
</template>
</el-table-column>
<el-table-column label="操作人员" align="center" width="110" prop="operName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
<template #default="scope">
<span>{{ parseTime(scope.row.operTime) }}</span>
</template>
</el-table-column>
<el-table-column label="消耗时间" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']">
<template #default="scope">
<span>{{ scope.row.costTime }}毫秒</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleView(scope.row, scope.index)" v-hasPermi="['monitor:operlog:query']">详细</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 操作日志详细 -->
<el-dialog title="操作日志详细" v-model="open" width="700px" append-to-body>
<el-form :model="form" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
<el-form-item
label="登录信息:"
>{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="操作方法:">{{ form.method }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="操作状态:">
<div v-if="form.status === 0">正常</div>
<div v-else-if="form.status === 1">失败</div>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="消耗时间:">{{ form.costTime }}毫秒</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="open = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Operlog">
import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog";
const { proxy } = getCurrentInstance();
const { sys_oper_type, sys_common_status } = proxy.useDict("sys_oper_type","sys_common_status");
const operlogList = ref([]);
const open = ref(false);
const operlogList = ref<OperLogVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const ids = ref<Array<number | string>>([]);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const defaultSort = ref({ prop: "operTime", order: "descending" });
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
const data = reactive({
form: {},
const operLogTableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const data = reactive<PageData<OperLogForm, OperLogQuery>>({
form: {
operId: undefined,
tenantId: undefined,
title: '',
businessType: 0,
businessTypes: undefined,
method: '',
requestMethod: '',
operatorType: 0,
operName: '',
deptName: '',
operUrl: '',
operIp: '',
operLocation: '',
operParam: '',
jsonResult: '',
status: 0,
errorMsg: '',
operTime: '',
costTime: 0
},
queryParams: {
pageNum: 1,
pageSize: 10,
title: undefined,
operName: undefined,
businessType: undefined,
status: undefined
}
title: '',
operName: '',
businessType: '',
status: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
rules: {}
});
const { queryParams, form } = toRefs(data);
/** 查询登录日志 */
function getList() {
const getList = async () => {
loading.value = true;
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
operlogList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
operlogList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 操作日志类型字典翻译 */
function typeFormat(row, column) {
return proxy.selectDictLabel(sys_oper_type.value, row.businessType);
const typeFormat = (row: OperLogForm) => {
return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
queryParams.value.pageNum = 1;
proxy.$refs["operlogRef"].sort(defaultSort.value.prop, defaultSort.value.order);
operLogTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: OperLogVO[]) => {
ids.value = selection.map(item => item.operId);
multiple.value = !selection.length;
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
const handleSortChange = (column: any) => {
queryParams.value.orderByColumn = column.prop;
queryParams.value.isAsc = column.order;
getList();
}
/** 详细按钮操作 */
function handleView(row) {
open.value = true;
const handleView = (row: OperLogVO) => {
dialog.visible = true;
form.value = row;
}
/** 删除按钮操作 */
function handleDelete(row) {
const operIds = row.operId || ids.value;
proxy.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function () {
return delOperlog(operIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: OperLogVO) => {
const operIds = row?.operId || ids.value;
await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
await delOperlog(operIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有操作日志数据项?").then(function () {
return cleanOperlog();
}).then(() => {
getList();
proxy.$modal.msgSuccess("清空成功");
}).catch(() => {});
const handleClean = async () => {
await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
await cleanOperlog();
getList();
proxy?.$modal.msgSuccess("清空成功");
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/operlog/export",{
const handleExport = () => {
proxy?.download("monitor/operlog/export", {
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`);
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="系统模块" prop="title">
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人员" prop="operName">
<el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px;" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="businessType">
<el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
<el-option v-for="dict in sys_oper_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="操作状态" clearable style="width: 240px">
<el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="操作时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:operlog:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="WarnTriangleFilled" @click="handleClean" v-hasPermi="['monitor:operlog:remove']">清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:operlog:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table
ref="operLogTableRef"
v-loading="loading"
:data="operlogList"
@selection-change="handleSelectionChange"
:default-sort="defaultSort"
@sort-change="handleSortChange"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="日志编号" align="center" prop="operId" />
<el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" />
<el-table-column label="操作类型" align="center" prop="businessType">
<template #default="scope">
<dict-tag :options="sys_oper_type" :value="scope.row.businessType" />
</template>
</el-table-column>
<el-table-column
label="操作人员"
align="center"
width="110"
prop="operName"
:show-overflow-tooltip="true"
sortable="custom"
:sort-orders="['descending', 'ascending']"
/>
<el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
<template #default="scope">
<span>{{ parseTime(scope.row.operTime) }}</span>
</template>
</el-table-column>
<el-table-column
label="消耗时间"
align="center"
prop="costTime"
width="110"
:show-overflow-tooltip="true"
sortable="custom"
:sort-orders="['descending', 'ascending']"
>
<template #default="scope">
<span>{{ scope.row.costTime }}毫秒</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="详细" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:operlog:query']"> </el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 操作日志详细 -->
<el-dialog title="操作日志详细" v-model="dialog.visible" width="700px" append-to-body>
<el-form :model="form" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
<el-form-item label="登录信息:">{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="操作方法:">{{ form.method }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="请求参数:">{{form.operParam}}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="操作状态:">
<div v-if="form.status === 0">正常</div>
<div v-else-if="form.status === 1">失败</div>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="消耗时间:">{{ form.costTime }}毫秒</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialog.visible = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,13 +1,9 @@
<template>
<div>
<i-frame v-model:src="url"></i-frame>
</div>
<div>
<i-frame v-model:src="url"></i-frame>
</div>
</template>
<script setup>
import iFrame from '@/components/iFrame'
import { ref } from 'vue';
<script setup lang="ts">
const url = ref(import.meta.env.VITE_APP_XXL_JOB_ADMIN);
</script>

View File

@ -1,5 +1,5 @@
<template>
<div></div>
<div></div>
</template>
<script setup>
@ -11,4 +11,4 @@ const { params, query } = route
const { path } = params
router.replace({ path: '/' + path, query })
</script>
</script>

View File

@ -1,99 +1,12 @@
<template>
<div class="register">
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
<el-form-item prop="tenantId">
<el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
<el-option
v-for="item in tenantList"
:key="item.tenantId"
:label="item.companyName"
:value="item.tenantId">
</el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select>
</el-form-item>
<el-form-item prop="username">
<el-input
v-model="registerForm.username"
type="text"
size="large"
auto-complete="off"
placeholder="账号"
>
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="registerForm.password"
type="password"
size="large"
auto-complete="off"
placeholder="密码"
@keyup.enter="handleRegister"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
size="large"
auto-complete="off"
placeholder="确认密码"
@keyup.enter="handleRegister"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
size="large"
v-model="registerForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter="handleRegister"
>
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
</el-input>
<div class="register-code">
<img :src="codeUrl" @click="getCode" class="register-code-img"/>
</div>
</el-form-item>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="large"
type="primary"
style="width:100%;"
@click.prevent="handleRegister"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;">
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-register-footer">
<span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script setup>
import { ElMessageBox } from "element-plus";
import { getCodeImg, register, getTenantList } from "@/api/login";
<script setup lang="ts">
import { getCodeImg, register, getTenantList } from '@/api/login';
import { RegisterForm, TenantVO } from '@/api/types';
import { FormRules } from 'element-plus';
import { to } from 'await-to-js';
const router = useRouter();
const { proxy } = getCurrentInstance();
const registerForm = ref({
const registerForm = ref<RegisterForm>({
tenantId: "",
username: "",
password: "",
@ -103,7 +16,11 @@ const registerForm = ref({
userType: "sys_user"
});
const equalToPassword = (rule, value, callback) => {
// 租户开关
const tenantEnabled = ref(true);
const equalToPassword = (rule: any, value: string, callback: any) => {
if (registerForm.value.password !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
@ -111,7 +28,7 @@ const equalToPassword = (rule, value, callback) => {
}
};
const registerRules = {
const registerRules: FormRules = {
tenantId: [
{ required: true, trigger: "blur", message: "请输入您的租户编号" }
],
@ -129,59 +46,119 @@ const registerRules = {
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
};
const codeUrl = ref("");
const loading = ref(false);
const captchaEnabled = ref(true);
const registerRef = ref(ElForm);
// 租户列表
const tenantList = ref([]);
const tenantList = ref<TenantVO[]>([]);
function handleRegister() {
proxy.$refs.registerRef.validate(valid => {
const handleRegister = () => {
registerRef.value.validate(async (valid: boolean) => {
if (valid) {
loading.value = true;
register(registerForm.value).then(res => {
const [err] = await to(register(registerForm.value));
if (!err) {
const username = registerForm.value.username;
ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
dangerouslyUseHTMLString: true,
type: "success",
}).then(() => {
router.push("/login");
}).catch(() => {});
}).catch(() => {
});
await router.push("/login");
} else {
loading.value = false;
if (captchaEnabled) {
getCode();
}
});
}
}
});
}
function getCode() {
getCodeImg().then(res => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
const getCode = async () => {
const { data } = await getCodeImg();
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img;
registerForm.value.uuid = res.uuid;
codeUrl.value = "data:image/gif;base64," + data.img;
registerForm.value.uuid = data.uuid;
}
});
}
function initTenantList() {
getTenantList().then(res => {
tenantList.value = res.data;
if (tenantList.value != null && tenantList.value.length !== 0) {
loginForm.value.tenantId = tenantList.value[0].tenantId;
const initTenantList = async () => {
const { data } = await getTenantList();
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
if (tenantEnabled.value) {
tenantList.value = data.voList;
if (tenantList.value != null && tenantList.value.length !== 0) {
registerForm.value.tenantId = tenantList.value[0].tenantId;
}
}
});
}
getCode();
initTenantList();
onMounted(() => {
getCode();
initTenantList();
})
</script>
<style lang='scss' scoped>
<template>
<div class="register">
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
<el-form-item prop="tenantId" v-if="tenantEnabled">
<el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select>
</el-form-item>
<el-form-item prop="username">
<el-input v-model="registerForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="registerForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleRegister">
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
size="large"
auto-complete="off"
placeholder="确认密码"
@keyup.enter="handleRegister"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input size="large" v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
</el-input>
<div class="register-code">
<img :src="codeUrl" @click="getCode" class="register-code-img" />
</div>
</el-form-item>
<el-form-item style="width:100%;">
<el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleRegister">
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;">
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-register-footer">
<span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<style lang="scss" scoped>
.register {
display: flex;
justify-content: center;
@ -190,8 +167,9 @@ initTenantList();
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
margin: 0 auto 30px auto;
text-align: center;
color: #707070;
}
@ -201,32 +179,39 @@ initTenantList();
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 40px;
input {
height: 40px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 0px;
margin-left: 0;
}
}
.register-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.register-code {
width: 33%;
height: 40px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-register-footer {
height: 40px;
line-height: 40px;
@ -235,10 +220,11 @@ initTenantList();
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-family: Arial, serif;
font-size: 12px;
letter-spacing: 1px;
}
.register-code-img {
height: 40px;
padding-left: 12px;

View File

@ -1,195 +1,43 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="参数名称" prop="configName">
<el-input
v-model="queryParams.configName"
placeholder="请输入参数名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="参数键名" prop="configKey">
<el-input
v-model="queryParams.configKey"
placeholder="请输入参数键名"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
<el-option
v-for="dict in sys_yes_no"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px;">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:config:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:config:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:config:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:config:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Refresh"
@click="handleRefreshCache"
v-hasPermi="['system:config:remove']"
>刷新缓存</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="参数主键" align="center" prop="configId" v-if="false" />
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
<el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
<el-table-column label="系统内置" align="center" prop="configType">
<template #default="scope">
<dict-tag :options="sys_yes_no" :value="scope.row.configType" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:config:edit']" >修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:config:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="configRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="参数名称" prop="configName">
<el-input v-model="form.configName" placeholder="请输入参数名称" />
</el-form-item>
<el-form-item label="参数键名" prop="configKey">
<el-input v-model="form.configKey" placeholder="请输入参数键名" />
</el-form-item>
<el-form-item label="参数键值" prop="configValue">
<el-input v-model="form.configValue" placeholder="请输入参数键值" />
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-radio-group v-model="form.configType">
<el-radio
v-for="dict in sys_yes_no"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Config">
<script setup name="Config" lang="ts">
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
import { ComponentInternalInstance } from "vue";
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance();
const { sys_yes_no } = proxy.useDict("sys_yes_no");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
const configList = ref([]);
const open = ref(false);
const configList = ref<ConfigVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const data = reactive({
form: {},
const queryFormRef = ref(ElForm);
const configFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: ConfigForm = {
configId: undefined,
configName: '',
configKey: '',
configValue: '',
configType: "Y",
remark: ''
}
const data = reactive<PageData<ConfigForm, ConfigQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
configName: undefined,
configKey: undefined,
configType: undefined
configName: '',
configKey: '',
configType: '',
},
rules: {
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
@ -201,106 +49,213 @@ const data = reactive({
const { queryParams, form, rules } = toRefs(data);
/** 查询参数列表 */
function getList() {
const getList = async () => {
loading.value = true;
listConfig(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
configList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
configList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
function cancel() {
open.value = false;
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
function reset() {
form.value = {
configId: undefined,
configName: undefined,
configKey: undefined,
configValue: undefined,
configType: "Y",
remark: undefined
};
proxy.resetForm("configRef");
const reset = () => {
form.value = {...initFormData};
configFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: ConfigVO[]) => {
ids.value = selection.map(item => item.configId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加参数";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加参数";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const configId = row.configId || ids.value;
getConfig(configId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改参数";
});
const handleUpdate = (row?: ConfigVO) => {
dialog.visible = true;
dialog.title = "修改参数";
const configId = row?.configId || ids.value[0];
nextTick(async () => {
reset();
const res = await getConfig(configId);
form.value = res.data;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["configRef"].validate(valid => {
if (valid) {
if (form.value.configId != undefined) {
updateConfig(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addConfig(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
const submitForm = () => {
configFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const configIds = row.configId || ids.value;
proxy.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function () {
return delConfig(configIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: ConfigVO) => {
const configIds = row?.configId || ids.value;
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
await delConfig(configIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/config/export", {
const handleExport = () => {
proxy?.download("system/config/export", {
...queryParams.value
}, `config_${new Date().getTime()}.xlsx`);
}
/** 刷新缓存按钮操作 */
function handleRefreshCache() {
refreshCache().then(() => {
proxy.$modal.msgSuccess("刷新缓存成功");
});
const handleRefreshCache = async () => {
await refreshCache();
proxy?.$modal.msgSuccess("刷新缓存成功");
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="参数名称" prop="configName">
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="参数键名" prop="configKey">
<el-input v-model="queryParams.configKey" placeholder="请输入参数键名" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
<el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px;">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:config:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:config:edit']">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:config:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:config:export']">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:config:remove']">刷新缓存</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="参数主键" align="center" prop="configId" v-if="false" />
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
<el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
<el-table-column label="系统内置" align="center" prop="configType">
<template #default="scope">
<dict-tag :options="sys_yes_no" :value="scope.row.configType" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:config:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:config:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="configFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="参数名称" prop="configName">
<el-input v-model="form.configName" placeholder="请输入参数名称" />
</el-form-item>
<el-form-item label="参数键名" prop="configKey">
<el-input v-model="form.configKey" placeholder="请输入参数键名" />
</el-form-item>
<el-form-item label="参数键值" prop="configValue">
<el-input v-model="form.configValue" placeholder="请输入参数键值" />
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-radio-group v-model="form.configType">
<el-radio v-for="dict in sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,163 +1,49 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="部门名称" prop="deptName">
<el-input
v-model="queryParams.deptName"
placeholder="请输入部门名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable style="width: 200px">
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<script setup name="Dept" lang="ts">
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
import { ComponentInternalInstance } from 'vue';
import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types";
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:dept:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
interface DeptOptionsType {
deptId: number | string;
deptName: string;
children: DeptOptionsType[];
<el-table
v-if="refreshTable"
v-loading="loading"
:data="deptList"
row-key="deptId"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']">新增</el-button>
<el-button v-if="scope.row.parentId != 0" link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
}
<!-- 添加或修改部门对话框 -->
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
<el-form ref="deptRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="24" v-if="form.parentId !== 0">
<el-form-item label="上级部门" prop="parentId">
<el-tree-select
v-model="form.parentId"
:data="deptOptions"
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
value-key="deptId"
placeholder="选择上级部门"
check-strictly
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门名称" prop="deptName">
<el-input v-model="form.deptName" placeholder="请输入部门名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="leader">
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
<script setup name="Dept">
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept";
const deptList = ref<DeptVO[]>([])
const loading = ref(true)
const showSearch = ref(true)
const deptOptions = ref<DeptOptionsType[]>([])
const isExpandAll = ref(true)
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const deptList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const deptOptions = ref([]);
const isExpandAll = ref(true);
const refreshTable = ref(true);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const data = reactive({
form: {},
const deptTableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const deptFormRef = ref(ElForm);
const initFormData: DeptForm = {
deptId: undefined,
parentId: undefined,
deptName: undefined,
orderNum: 0,
leader: undefined,
phone: undefined,
email: undefined,
status: "0"
}
const data = reactive<PageData<DeptForm, DeptQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
deptName: undefined,
status: undefined
},
@ -168,111 +54,239 @@ const data = reactive({
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
},
});
})
const { queryParams, form, rules } = toRefs(data);
const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data)
/** 查询部门列表 */
function getList() {
loading.value = true;
listDept(queryParams.value).then(response => {
deptList.value = proxy.handleTree(response.data, "deptId");
loading.value = false;
});
/** 查询菜单列表 */
const getList = async () => {
loading.value = true;
const res = await listDept(queryParams.value);
const data = proxy?.handleTree<DeptVO>(res.data, "deptId")
if (data) {
deptList.value = data
}
loading.value = false
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
reset()
dialog.visible = false
}
/** 表单重置 */
function reset() {
form.value = {
deptId: undefined,
parentId: undefined,
deptName: undefined,
orderNum: 0,
leader: undefined,
phone: undefined,
email: undefined,
status: "0"
};
proxy.resetForm("deptRef");
const reset = () => {
form.value = {...initFormData};
deptFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery()
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
listDept().then(response => {
deptOptions.value = proxy.handleTree(response.data, "deptId");
});
if (row != undefined) {
form.value.parentId = row.deptId;
}
open.value = true;
title.value = "添加部门";
const handleAdd = (row?: DeptVO) => {
listDept().then(res => {
const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
if (data) {
deptOptions.value = data
dialog.visible = true;
dialog.title = "添加部门";
nextTick(() => {
reset();
if (row && row.deptId) {
form.value.parentId = row?.parentId;
}
})
}
})
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
const handleToggleExpandAll = () => {
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
toggleExpandAll(deptList.value, isExpandAll.value)
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
getDept(row.deptId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改部门";
listDeptExcludeChild(row.deptId).then(response => {
deptOptions.value = proxy.handleTree(response.data, "deptId");
if (deptOptions.value.length == 0) {
const noResultsOptions = { deptId: proxy.form.parentId, deptName: proxy.form.parentName, children: [] };
deptOptions.value.push(noResultsOptions);
}
});
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["deptRef"].validate(valid => {
if (valid) {
if (form.value.deptId != undefined) {
updateDept(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addDept(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
return delDept(row.deptId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
/** 展开/折叠所有 */
const toggleExpandAll = (data: DeptVO[], status: boolean) => {
data.forEach((item) => {
deptTableRef.value.toggleRowExpansion(item, status)
if(item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
}
getList();
/** 修改按钮操作 */
const handleUpdate = async (row: DeptVO) => {
const res = await getDept(row.deptId);
dialog.visible = true;
dialog.title = "修改部门";
nextTick(async () => {
reset();
form.value = res.data
const response = await listDeptExcludeChild(row.deptId);
const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
if (data) {
deptOptions.value = data;
if (data.length === 0) {
const noResultsOptions: DeptOptionsType = { deptId: res.data.parentId, deptName: res.data.parentName, children: [] };
deptOptions.value.push(noResultsOptions);
}
}
})
}
/** 提交按钮 */
const submitForm = () => {
deptFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
})
}
/** 删除按钮操作 */
const handleDelete = async (row: DeptVO) => {
await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
await delDept(row.deptId);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
});
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:dept:add']">新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table
v-loading="loading"
:data="deptList"
row-key="deptId"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
ref="deptTableRef"
:default-expand-all="isExpandAll"
>
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
<el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
<el-table-column prop="status" align="center" label="状态" width="100">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" align="center" label="操作">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']" />
</el-tooltip>
<el-tooltip content="新增" placement="top">
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="600px">
<el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="24" v-if="form.parentId !== 0">
<el-form-item label="上级部门" prop="parentId">
<el-tree-select
v-model="form.parentId"
:data="deptOptions"
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
value-key="deptId"
placeholder="选择上级部门"
check-strictly
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门名称" prop="deptName">
<el-input v-model="form.deptName" placeholder="请输入部门名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="leader">
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,350 +1,312 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType" style="width: 200px">
<el-option
v-for="item in typeOptions"
:key="item.dictId"
:label="item.dictName"
:value="item.dictType"
/>
</el-select>
</el-form-item>
<el-form-item label="字典标签" prop="dictLabel">
<el-input
v-model="queryParams.dictLabel"
placeholder="请输入字典标签"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:dict:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:dict:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:dict:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Close"
@click="handleClose"
>关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
<el-table-column label="字典标签" align="center" prop="dictLabel">
<template #default="scope">
<span v-if="scope.row.listClass == '' || scope.row.listClass == 'default'">{{ scope.row.dictLabel }}</span>
<el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel }}</el-tag>
</template>
</el-table-column>
<el-table-column label="字典键值" align="center" prop="dictValue" />
<el-table-column label="字典排序" align="center" prop="dictSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="字典类型">
<el-input v-model="form.dictType" :disabled="true" />
</el-form-item>
<el-form-item label="数据标签" prop="dictLabel">
<el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
</el-form-item>
<el-form-item label="数据键值" prop="dictValue">
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
</el-form-item>
<el-form-item label="样式属性" prop="cssClass">
<el-input v-model="form.cssClass" placeholder="请输入样式属性" />
</el-form-item>
<el-form-item label="显示排序" prop="dictSort">
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="回显样式" prop="listClass">
<el-select v-model="form.listClass">
<el-option
v-for="item in listClassOptions"
:key="item.value"
:label="item.label + '(' + item.value + ')'"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Data">
<script setup name="Data" lang="ts">
import useDictStore from '@/store/modules/dict'
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
import { DictTypeVO } from '@/api/system/dict/type/types';
import { ComponentInternalInstance } from "vue";
import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types";
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
const route = useRoute();
const dataList = ref([]);
const open = ref(false);
const dataList = ref<DictDataVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const defaultDictType = ref("");
const typeOptions = ref([]);
const route = useRoute();
const typeOptions = ref<DictTypeVO[]>([]);
const dataFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
// 数据标签回显样式
const listClassOptions = ref([
{ value: "default", label: "默认" },
{ value: "primary", label: "主要" },
{ value: "success", label: "成功" },
{ value: "info", label: "信息" },
{ value: "warning", label: "警告" },
{ value: "danger", label: "危险" }
const listClassOptions = ref<Array<{ value: string, label: string }>>([
{ value: "default", label: "默认" },
{ value: "primary", label: "主要" },
{ value: "success", label: "成功" },
{ value: "info", label: "信息" },
{ value: "warning", label: "警告" },
{ value: "danger", label: "危险" }
]);
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
status: undefined
},
rules: {
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
}
const initFormData: DictDataForm = {
dictCode: undefined,
dictLabel: '',
dictValue: '',
cssClass: '',
listClass: "default",
dictSort: 0,
status: "0",
remark: ''
}
const data = reactive<PageData<DictDataForm, DictDataQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: '',
dictType: '',
status: '',
dictLabel: ''
},
rules: {
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典类型详细 */
function getTypes(dictId) {
getType(dictId).then(response => {
queryParams.value.dictType = response.data.dictType;
defaultDictType.value = response.data.dictType;
getList();
});
const getTypes = async (dictId: string | number) => {
const { data } = await getType(dictId);
queryParams.value.dictType = data.dictType;
defaultDictType.value = data.dictType;
getList();
}
/** 查询字典类型列表 */
function getTypeList() {
getDictOptionselect().then(response => {
typeOptions.value = response.data;
});
const getTypeList = async () => {
const res = await getDictOptionselect()
typeOptions.value = res.data;
}
/** 查询字典数据列表 */
function getList() {
loading.value = true;
listData(queryParams.value).then(response => {
dataList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getList = async () => {
loading.value = true;
const res = await listData(queryParams.value);
dataList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
dialog.visible = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
dictCode: undefined,
dictLabel: undefined,
dictValue: undefined,
cssClass: undefined,
listClass: "default",
dictSort: 0,
status: "0",
remark: undefined
};
proxy.resetForm("dataRef");
const reset = () => {
form.value = { ...initFormData };
dataFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 返回按钮操作 */
function handleClose() {
const obj = { path: "/system/dict" };
proxy.$tab.closeOpenPage(obj);
const handleClose = () => {
const obj = { path: "/system/dict" };
proxy?.$tab.closeOpenPage(obj);
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
queryParams.value.dictType = defaultDictType;
handleQuery();
const resetQuery = () => {
queryFormRef.value.resetFields();
queryParams.value.dictType = defaultDictType.value;
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加字典数据";
form.value.dictType = queryParams.value.dictType;
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加字典数据";
nextTick(() => {
reset();
form.value.dictType = queryParams.value.dictType;
})
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.dictCode);
single.value = selection.length != 1;
multiple.value = !selection.length;
const handleSelectionChange = (selection: DictDataVO[]) => {
ids.value = selection.map(item => item.dictCode);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const dictCode = row.dictCode || ids.value;
getData(dictCode).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改字典数据";
});
const handleUpdate = (row?: DictDataVO) => {
const dictCode = row?.dictCode || ids.value[0];
dialog.visible = true;
dialog.title = "修改字典数据";
nextTick(async () => {
const res = await getData(dictCode);
reset();
form.value = res.data;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate(valid => {
if (valid) {
if (form.value.dictCode != undefined) {
updateData(form.value).then(response => {
useDictStore().removeDict(queryParams.value.dictType);
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then(response => {
useDictStore().removeDict(queryParams.value.dictType);
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
const submitForm = () => {
dataFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.dictCode ? await updateData(form.value) : await addData(form.value);
useDictStore().removeDict(queryParams.value.dictType);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictCodes = row.dictCode || ids.value;
proxy.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
return delData(dictCodes);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
useDictStore().removeDict(queryParams.value.dictType);
}).catch(() => {});
const handleDelete = async (row?: DictDataVO) => {
const dictCodes = row?.dictCode || ids.value;
await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
await delData(dictCodes);
getList();
proxy?.$modal.msgSuccess("删除成功");
useDictStore().removeDict(queryParams.value.dictType);
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/data/export", {
...queryParams.value
}, `dict_data_${new Date().getTime()}.xlsx`);
const handleExport = () => {
proxy?.download("system/dict/data/export", {
...queryParams.value
}, `dict_data_${new Date().getTime()}.xlsx`);
}
getTypes(route.params && route.params.dictId);
getTypeList();
onMounted(() => {
getTypes(route.params && route.params.dictId as string);
getTypeList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType" style="width: 200px">
<el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" />
</el-select>
</el-form-item>
<el-form-item label="字典标签" prop="dictLabel">
<el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
<el-table-column label="字典标签" align="center" prop="dictLabel">
<template #default="scope">
<span v-if="scope.row.listClass === '' || scope.row.listClass === 'default'">{{ scope.row.dictLabel }}</span>
<el-tag v-else :type="scope.row.listClass === 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="字典键值" align="center" prop="dictValue" />
<el-table-column label="字典排序" align="center" prop="dictSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="字典类型">
<el-input v-model="form.dictType" :disabled="true" />
</el-form-item>
<el-form-item label="数据标签" prop="dictLabel">
<el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
</el-form-item>
<el-form-item label="数据键值" prop="dictValue">
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
</el-form-item>
<el-form-item label="样式属性" prop="cssClass">
<el-input v-model="form.cssClass" placeholder="请输入样式属性" />
</el-form-item>
<el-form-item label="显示排序" prop="dictSort">
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="回显样式" prop="listClass">
<el-select v-model="form.listClass">
<el-option
v-for="item in listClassOptions"
:key="item.value"
:label="item.label + '(' + item.value + ')'"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,203 +1,46 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="字典名称" prop="dictName">
<el-input
v-model="queryParams.dictName"
placeholder="请输入字典名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="字典类型" prop="dictType">
<el-input
v-model="queryParams.dictType"
placeholder="请输入字典类型"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="字典状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:dict:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:dict:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:dict:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Refresh"
@click="handleRefreshCache"
v-hasPermi="['system:dict:remove']"
>刷新缓存</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编号" align="center" prop="dictId" v-if="false" />
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true"/>
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
<span>{{ scope.row.dictType }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="dictRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="字典名称" prop="dictName">
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
</el-form-item>
<el-form-item label="字典类型" prop="dictType">
<el-input v-model="form.dictType" placeholder="请输入字典类型" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Dict">
<script setup name="Dict" lang="ts">
import useDictStore from '@/store/modules/dict'
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
import { ComponentInternalInstance } from "vue";
import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types";
import { DateModelType } from 'element-plus';
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"))
const typeList = ref([]);
const open = ref(false);
const typeList = ref<DictTypeVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const data = reactive({
form: {},
const dictFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: DictTypeForm = {
dictId: undefined,
dictName: '',
dictType: '',
status: "0",
remark: ''
}
const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
status: undefined
dictName: '',
dictType: '',
status: ''
},
rules: {
dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
@ -208,106 +51,216 @@ const data = reactive({
const { queryParams, form, rules } = toRefs(data);
/** 查询字典类型列表 */
function getList() {
const getList = () => {
loading.value = true;
listType(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
typeList.value = response.rows;
total.value = response.total;
listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
typeList.value = res.rows;
total.value = res.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
function reset() {
form.value = {
dictId: undefined,
dictName: undefined,
dictType: undefined,
status: "0",
remark: undefined
};
proxy.resetForm("dictRef");
const reset = () => {
form.value = {...initFormData};
dictFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加字典类型";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加字典类型";
nextTick(() => {
reset();
})
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: DictTypeVO[]) => {
ids.value = selection.map(item => item.dictId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const dictId = row.dictId || ids.value;
getType(dictId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改字典类型";
});
const handleUpdate = (row?: DictTypeVO) => {
dialog.visible = true;
dialog.title = "修改字典类型";
const dictId = row?.dictId || ids.value[0];
nextTick(async () => {
reset();
const res = await getType(dictId);
form.value = res.data;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dictRef"].validate(valid => {
if (valid) {
if (form.value.dictId != undefined) {
updateType(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addType(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
const submitForm = () => {
dictFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.dictId ? await updateType(form.value) : await addType(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.dictId || ids.value;
proxy.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
return delType(dictIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: DictTypeVO) => {
const dictIds = row?.dictId || ids.value;
await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
await delType(dictIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/type/export", {
const handleExport = () => {
proxy?.download("system/dict/type/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
}
/** 刷新缓存按钮操作 */
function handleRefreshCache() {
refreshCache().then(() => {
proxy.$modal.msgSuccess("刷新成功");
useDictStore().cleanDict();
});
const handleRefreshCache = async () => {
await refreshCache();
proxy?.$modal.msgSuccess("刷新成功");
useDictStore().cleanDict();
}
getList();
onMounted(()=>{
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="字典名称" prop="dictName">
<el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="字典类型" prop="dictType">
<el-input v-model="queryParams.dictType" placeholder="请输入字典类型" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:dict:remove']">刷新缓存</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编号" align="center" prop="dictId" v-if="false" />
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
<span>{{ scope.row.dictType }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="字典名称" prop="dictName">
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
</el-form-item>
<el-form-item label="字典类型" prop="dictType">
<el-input v-model="form.dictType" placeholder="请输入字典类型" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,441 +1,417 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="菜单名称" prop="menuName">
<el-input
v-model="queryParams.menuName"
placeholder="请输入菜单名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<script setup name="Menu" lang="ts">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
import { ComponentInternalInstance } from 'vue';
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
import { ElTable, ElForm } from 'element-plus';
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:menu:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
interface MenuOptionsType {
menuId: number;
menuName: string;
children: MenuOptionsType[] | undefined;
}
<el-table
v-if="refreshTable"
v-loading="loading"
:data="menuList"
row-key="menuId"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template #default="scope">
<svg-icon :icon-class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_show_hide", "sys_normal_disable"));
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单">
<el-tree-select
v-model="form.parentId"
:data="menuOptions"
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
value-key="menuId"
placeholder="选择上级菜单"
check-strictly
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单类型" prop="menuType">
<el-radio-group v-model="form.menuType">
<el-radio label="M">目录</el-radio>
<el-radio label="C">菜单</el-radio>
<el-radio label="F">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.menuType != 'F'">
<el-form-item label="菜单图标" prop="icon">
<el-popover
placement="bottom-start"
:width="540"
v-model:visible="showChooseIcon"
trigger="click"
@show="showSelectIcon"
>
<template #reference>
<el-input v-model="form.icon" placeholder="点击选择图标" @blur="showSelectIcon" v-click-outside="hideSelectIcon" readonly>
<template #prefix>
<svg-icon
v-if="form.icon"
:icon-class="form.icon"
class="el-input__icon"
style="height: 32px;width: 16px;"
/>
<el-icon v-else style="height: 32px;width: 16px;"><search /></el-icon>
</template>
</el-input>
</template>
<icon-select ref="iconSelectRef" @selected="selected" />
</el-popover>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>是否外链
</span>
</template>
<el-radio-group v-model="form.isFrame">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item prop="path">
<template #label>
<span>
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由地址
</span>
</template>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="component">
<template #label>
<span>
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
组件路径
</span>
</template>
<el-input v-model="form.component" placeholder="请输入组件路径" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'M'">
<el-form-item>
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@SaCheckPermission('system:user:list')" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
<template #label>
<span>
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由参数
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
是否缓存
</span>
</template>
<el-radio-group v-model="form.isCache">
<el-radio label="0">缓存</el-radio>
<el-radio label="1">不缓存</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
显示状态
</span>
</template>
<el-radio-group v-model="form.visible">
<el-radio
v-for="dict in sys_show_hide"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
菜单状态
</span>
</template>
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
const menuList = ref<MenuVO[]>([])
const loading = ref(true)
const showSearch = ref(true)
const menuOptions = ref<MenuOptionsType[]>([])
const isExpandAll = ref(false)
<script setup name="Menu">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
import SvgIcon from "@/components/SvgIcon";
import IconSelect from "@/components/IconSelect";
import { ClickOutside as vClickOutside } from 'element-plus'
const { proxy } = getCurrentInstance();
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
const menuList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const menuOptions = ref([]);
const isExpandAll = ref(false);
const refreshTable = ref(true);
const showChooseIcon = ref(false);
const iconSelectRef = ref(null);
const data = reactive({
form: {},
queryParams: {
menuName: undefined,
visible: undefined
},
rules: {
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const { queryParams, form, rules } = toRefs(data);
const queryFormRef = ref(ElForm);
const menuFormRef = ref(ElForm);
const initFormData = {
path: '',
menuId: undefined,
parentId: 0,
menuName: '',
icon: '',
menuType: MenuTypeEnum.M,
orderNum: 1,
isFrame: "1",
isCache: "0",
visible: "0",
status: "0"
}
const data = reactive<PageData<MenuForm, MenuQuery>>({
form: { ...initFormData },
queryParams: {
menuName: undefined,
status: undefined
},
rules: {
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
})
const menuTableRef = ref(ElTable);
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
/** 查询菜单列表 */
function getList() {
loading.value = true;
listMenu(queryParams.value).then(response => {
menuList.value = proxy.handleTree(response.data, "menuId");
loading.value = false;
});
const getList = async () => {
loading.value = true
const res = await listMenu(queryParams.value);
const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
if (data) {
menuList.value = data
}
loading.value = false
}
/** 查询菜单下拉树结构 */
function getTreeselect() {
menuOptions.value = [];
listMenu().then(response => {
const menu = { menuId: 0, menuName: "主类目", children: [] };
menu.children = proxy.handleTree(response.data, "menuId");
menuOptions.value.push(menu);
});
const getTreeselect = async () => {
menuOptions.value = []
const response = await listMenu();
const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
menuOptions.value.push(menu)
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
reset()
dialog.visible = false
}
/** 表单重置 */
function reset() {
form.value = {
menuId: undefined,
parentId: 0,
menuName: undefined,
icon: undefined,
menuType: "M",
orderNum: undefined,
isFrame: "1",
isCache: "0",
visible: "0",
status: "0"
};
proxy.resetForm("menuRef");
}
/** 展示下拉图标 */
function showSelectIcon() {
iconSelectRef.value.reset();
showChooseIcon.value = true;
}
/** 选择图标 */
function selected(name) {
form.value.icon = name;
showChooseIcon.value = false;
}
/** 图标外层点击隐藏下拉列表 */
function hideSelectIcon(event) {
var elem = event.relatedTarget || event.srcElement || event.target || event.currentTarget;
var className = elem.className;
if (className !== "el-input__inner") {
showChooseIcon.value = false;
}
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
getTreeselect();
if (row != null && row.menuId) {
form.value.parentId = row.menuId;
} else {
form.value.parentId = 0;
}
open.value = true;
title.value = "添加菜单";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */
async function handleUpdate(row) {
reset();
await getTreeselect();
getMenu(row.menuId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改菜单";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["menuRef"].validate(valid => {
if (valid) {
if (form.value.menuId != undefined) {
updateMenu(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addMenu(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
return delMenu(row.menuId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const reset = () => {
form.value = { ...initFormData };
menuFormRef.value.resetFields();
}
getList();
/** 搜索按钮操作 */
const handleQuery = () => {
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
/** 新增按钮操作 */
const handleAdd = (row?: MenuVO) => {
dialog.visible = true;
dialog.title = "添加菜单";
getTreeselect();
nextTick(() => {
reset();
row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
})
}
/** 展开/折叠操作 */
const handleToggleExpandAll = () => {
isExpandAll.value = !isExpandAll.value;
toggleExpandAll(menuList.value, isExpandAll.value)
}
/** 展开/折叠所有 */
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
data.forEach((item: MenuVO) => {
menuTableRef.value.toggleRowExpansion(item, status)
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
})
}
/** 修改按钮操作 */
const handleUpdate = async (row: MenuVO) => {
await getTreeselect();
dialog.visible = true;
dialog.title = "修改菜单";
await nextTick(async () => {
if (row.menuId) {
const { data } = await getMenu(row.menuId);
reset();
form.value = data;
}
})
}
/** 提交按钮 */
const submitForm = () => {
menuFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
})
}
/** 删除按钮操作 */
const handleDelete = async (row: MenuVO) => {
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
await delMenu(row.menuId);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
getList();
});
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:menu:add']">新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table
v-loading="loading"
:data="menuList"
row-key="menuId"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
border
ref="menuTableRef"
:default-expand-all="isExpandAll"
>
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template #default="scope">
<svg-icon :icon-class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime">
<template #default="scope">
<span>{{ scope.row.createTime }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="180">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']" />
</el-tooltip>
<el-tooltip content="新增" placement="top">
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="750px">
<el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单">
<el-tree-select
v-model="form.parentId"
:data="menuOptions"
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
value-key="menuId"
placeholder="选择上级菜单"
check-strictly
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单类型" prop="menuType">
<el-radio-group v-model="form.menuType">
<el-radio label="M">目录</el-radio>
<el-radio label="C">菜单</el-radio>
<el-radio label="F">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.menuType !== 'F'">
<el-form-item label="菜单图标" prop="icon">
<!-- 图标选择器 -->
<icon-select v-model="form.icon" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType !== 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
<el-icon>
<question-filled />
</el-icon> </el-tooltip
>是否外链
</span>
</template>
<el-radio-group v-model="form.isFrame">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType !== 'F'">
<el-form-item prop="path">
<template #label>
<span>
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
路由地址
</span>
</template>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType === 'C'">
<el-form-item prop="component">
<template #label>
<span>
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
组件路径
</span>
</template>
<el-input v-model="form.component" placeholder="请输入组件路径" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType !== 'M'">
<el-form-item>
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
权限字符
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType === 'C'">
<el-form-item>
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
<template #label>
<span>
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
路由参数
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType === 'C'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
是否缓存
</span>
</template>
<el-radio-group v-model="form.isCache">
<el-radio label="0">缓存</el-radio>
<el-radio label="1">不缓存</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType !== 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
显示状态
</span>
</template>
<el-radio-group v-model="form.visible">
<el-radio v-for="dict in sys_show_hide" :key="dict.value" :label="dict.value">{{ dict.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType !== 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
<el-icon>
<question-filled />
</el-icon>
</el-tooltip>
菜单状态
</span>
</template>
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,283 +1,248 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input
v-model="queryParams.noticeTitle"
placeholder="请输入公告标题"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="操作人员" prop="createByName">
<el-input
v-model="queryParams.createByName"
placeholder="请输入操作人员"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
<el-option
v-for="dict in sys_notice_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:notice:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:notice:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:notice:remove']"
>删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="noticeId" width="100" v-if="false" />
<el-table-column
label="公告标题"
align="center"
prop="noticeTitle"
:show-overflow-tooltip="true"
/>
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
<template #default="scope">
<dict-tag :options="sys_notice_type" :value="scope.row.noticeType" />
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="scope">
<dict-tag :options="sys_notice_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建者" align="center" prop="createByName" width="100" />
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']" >删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改公告对话框 -->
<el-dialog :title="title" v-model="open" width="780px" append-to-body>
<el-form ref="noticeRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="公告类型" prop="noticeType">
<el-select v-model="form.noticeType" placeholder="请选择">
<el-option
v-for="dict in sys_notice_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_notice_status"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="内容">
<editor v-model="form.noticeContent" :min-height="192"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Notice">
<script setup name="Notice" lang="ts">
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
import { ComponentInternalInstance } from "vue";
import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types";
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance();
const { sys_notice_status, sys_notice_type } = proxy.useDict("sys_notice_status", "sys_notice_type");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type"));
const noticeList = ref([]);
const open = ref(false);
const noticeList = ref<NoticeVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
noticeTitle: undefined,
createByName: undefined,
status: undefined
},
rules: {
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
},
const queryFormRef = ref(ElForm);
const noticeFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: NoticeForm = {
noticeId: undefined,
noticeTitle: '',
noticeType: '',
noticeContent: '',
status: "0",
remark: '',
createByName: ''
}
const data = reactive<PageData<NoticeForm, NoticeQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
noticeTitle: '',
createByName: '',
status: '',
noticeType: ''
},
rules: {
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询公告列表 */
function getList() {
loading.value = true;
listNotice(queryParams.value).then(response => {
noticeList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getList = async () => {
loading.value = true;
const res = await listNotice(queryParams.value);
noticeList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
function reset() {
form.value = {
noticeId: undefined,
noticeTitle: undefined,
noticeType: undefined,
noticeContent: undefined,
status: "0"
};
proxy.resetForm("noticeRef");
const reset = () => {
form.value = { ...initFormData };
noticeFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.noticeId);
single.value = selection.length != 1;
multiple.value = !selection.length;
const handleSelectionChange = (selection: NoticeVO[]) => {
ids.value = selection.map(item => item.noticeId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加公告";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加公告";
nextTick(() => {
reset();
})
}
/**修改按钮操作 */
function handleUpdate(row) {
reset();
const noticeId = row.noticeId || ids.value;
getNotice(noticeId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改公告";
});
const handleUpdate = (row?: NoticeVO) => {
dialog.visible = true;
dialog.title = "修改公告";
nextTick(async () => {
const noticeId = row?.noticeId || ids.value[0];
reset();
const { data } = await getNotice(noticeId);
form.value = data;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["noticeRef"].validate(valid => {
if (valid) {
if (form.value.noticeId != undefined) {
updateNotice(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addNotice(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
const submitForm = () => {
noticeFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
proxy?.$modal.msgSuccess("修改成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const noticeIds = row.noticeId || ids.value
proxy.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
return delNotice(noticeIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: NoticeVO) => {
const noticeIds = row?.noticeId || ids.value
await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
await delNotice(noticeIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人员" prop="createByName">
<el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
<el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:notice:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:notice:remove']">
删除
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="noticeId" width="100" v-if="false" />
<el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
<template #default="scope">
<dict-tag :options="sys_notice_type" :value="scope.row.noticeType" />
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="scope">
<dict-tag :options="sys_notice_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建者" align="center" prop="createByName" width="100" />
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改公告对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="780px" append-to-body>
<el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="公告类型" prop="noticeType">
<el-select v-model="form.noticeType" placeholder="请选择">
<el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="内容">
<editor v-model="form.noticeContent" :min-height="192" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,170 +1,4 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="配置key" prop="configKey">
<el-input
v-model="queryParams.configKey"
placeholder="配置key"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input
v-model="queryParams.bucketName"
placeholder="请输入桶名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="是否默认" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
<el-option key="0" label="是" value="0"/>
<el-option key="1" label="否" value="1"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:oss:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:oss:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:oss:remove']"
>删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible"/>
<el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
<el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
<el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
<el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
<el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
<el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
<el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible" >
<template #default="scope">
<el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
<el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
<el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
</template>
</el-table-column>
<el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:oss:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改对象存储配置对话框 -->
<el-dialog :title="title" v-model="open" width="800px" append-to-body>
<el-form ref="ossConfigRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="配置key" prop="configKey">
<el-input v-model="form.configKey" placeholder="请输入配置key" />
</el-form-item>
<el-form-item label="访问站点" prop="endpoint">
<el-input v-model="form.endpoint" placeholder="请输入访问站点" />
</el-form-item>
<el-form-item label="自定义域名" prop="domain">
<el-input v-model="form.domain" placeholder="请输入自定义域名" />
</el-form-item>
<el-form-item label="accessKey" prop="accessKey">
<el-input v-model="form.accessKey" placeholder="请输入accessKey" />
</el-form-item>
<el-form-item label="secretKey" prop="secretKey">
<el-input v-model="form.secretKey" placeholder="请输入秘钥" show-password />
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input v-model="form.bucketName" placeholder="请输入桶名称" />
</el-form-item>
<el-form-item label="前缀" prop="prefix">
<el-input v-model="form.prefix" placeholder="请输入前缀" />
</el-form-item>
<el-form-item label="是否HTTPS">
<el-radio-group v-model="form.isHttps">
<el-radio
v-for="dict in sys_yes_no"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="桶权限类型">
<el-radio-group v-model="form.accessPolicy">
<el-radio label="0">private</el-radio>
<el-radio label="1">public</el-radio>
<el-radio label="2">custom</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="域" prop="region">
<el-input v-model="form.region" placeholder="请输入域" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="OssConfig">
<script setup name="OssConfig" lang="ts">
import {
listOssConfig,
getOssConfig,
@ -173,23 +7,33 @@ import {
updateOssConfig,
changeOssConfigStatus
} from "@/api/system/ossConfig";
import { ComponentInternalInstance } from "vue";
import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types";
import { ElForm } from 'element-plus';
const { proxy } = getCurrentInstance();
const { sys_yes_no } = proxy.useDict("sys_yes_no");
const ossConfigList = ref([]);
const open = ref(false);
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
const ossConfigList = ref<OssConfigVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const queryFormRef = ref(ElForm);
const ossConfigFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
// 列显隐信息
const columns = ref([
const columns = ref<FieldOption[]>([
{ key: 0, label: `主建`, visible: true },
{ key: 1, label: `配置key`, visible: false },
{ key: 2, label: `访问站点`, visible: true },
@ -201,20 +45,34 @@ const columns = ref([
{ key: 8, label: `状态`, visible: true }
]);
const data = reactive({
form: {},
const initFormData: OssConfigForm = {
ossConfigId: undefined,
configKey: '',
accessKey: '',
secretKey: '',
bucketName: '',
prefix: '',
endpoint: '',
domain: '',
isHttps: "N",
accessPolicy: "1",
region: '',
status: "1",
remark: '',
}
const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
configKey: undefined,
bucketName: undefined,
status: undefined,
configKey: '',
bucketName: '',
status: '',
},
rules: {
configKey: [
{ required: true, message: "configKey不能为空", trigger: "blur" },
],
configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
accessKey: [
{ required: true, message: "accessKey不能为空", trigger: "blur" },
{
@ -251,132 +109,238 @@ const data = reactive({
trigger: "blur",
},
],
accessPolicy:[
{ required: true, message: "accessPolicy不能为空", trigger: "blur" }
]
accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询对象存储配置列表 */
function getList() {
const getList = async () => {
loading.value = true;
listOssConfig(queryParams.value).then((response) => {
ossConfigList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await listOssConfig(queryParams.value);
ossConfigList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
function cancel() {
open.value = false;
const cancel = () => {
dialog.visible = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
ossConfigId: undefined,
configKey: undefined,
accessKey: undefined,
secretKey: undefined,
bucketName: undefined,
prefix: undefined,
endpoint: undefined,
domain: undefined,
isHttps: "N",
accessPolicy: "1",
region: undefined,
status: "1",
remark: undefined,
};
proxy.resetForm("ossConfigRef");
const reset = () => {
form.value = { ...initFormData };
ossConfigFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: OssConfigVO[]) => {
ids.value = selection.map(item => item.ossConfigId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加对象存储配置";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加对象存储配置";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
const handleUpdate = (row?: OssConfigVO) => {
loading.value = true;
reset();
const ossConfigId = row.ossConfigId || ids.value;
getOssConfig(ossConfigId).then((response) => {
dialog.visible = true;
dialog.title = "修改对象存储配置";
const ossConfigId = row?.ossConfigId || ids.value[0];
nextTick(async () => {
reset();
const res = await getOssConfig(ossConfigId);
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改对象存储配置";
});
form.value = res.data;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["ossConfigRef"].validate(valid => {
const submitForm = () => {
ossConfigFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.ossConfigId != null) {
updateOssConfig(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
if (form.value.ossConfigId) {
await updateOssConfig(form.value).finally(() => buttonLoading.value = false);
} else {
addOssConfig(this.form).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
await addOssConfig(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("新增成功");
dialog.visible = false;
getList();
}
});
}
/** 用户状态修改 */
function handleStatusChange(row) {
/** 状态修改 */
const handleStatusChange = async (row: OssConfigVO) => {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?').then(() => {
return changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
}).then(() => {
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
getList()
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
proxy?.$modal.msgSuccess(text + "成功");
} catch { return } finally {
row.status = row.status === "0" ? "1" : "0";
});
}
}
/** 删除按钮操作 */
function handleDelete(row) {
const ossConfigIds = row.ossConfigId || ids.value;
proxy.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?').then(() => {
loading.value = true;
return delOssConfig(ossConfigIds);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).finally(() => {
loading.value = false;
});
const handleDelete = async (row?: OssConfigVO) => {
const ossConfigIds = row?.ossConfigId || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
loading.value = true;
await delOssConfig(ossConfigIds).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="配置key" prop="configKey">
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="是否默认" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
<el-option key="0" label="是" value="0" />
<el-option key="1" label="否" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:oss:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:oss:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
删除
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible" />
<el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
<el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
<el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
<el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
<el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
<el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
<el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible">
<template #default="scope">
<el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
<el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
<el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
</template>
</el-table-column>
<el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
<template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:oss:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改对象存储配置对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
<el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="配置key" prop="configKey">
<el-input v-model="form.configKey" placeholder="请输入配置key" />
</el-form-item>
<el-form-item label="访问站点" prop="endpoint">
<el-input v-model="form.endpoint" placeholder="请输入访问站点" />
</el-form-item>
<el-form-item label="自定义域名" prop="domain">
<el-input v-model="form.domain" placeholder="请输入自定义域名" />
</el-form-item>
<el-form-item label="accessKey" prop="accessKey">
<el-input v-model="form.accessKey" placeholder="请输入accessKey" />
</el-form-item>
<el-form-item label="secretKey" prop="secretKey">
<el-input v-model="form.secretKey" placeholder="请输入秘钥" show-password />
</el-form-item>
<el-form-item label="桶名称" prop="bucketName">
<el-input v-model="form.bucketName" placeholder="请输入桶名称" />
</el-form-item>
<el-form-item label="前缀" prop="prefix">
<el-input v-model="form.prefix" placeholder="请输入前缀" />
</el-form-item>
<el-form-item label="是否HTTPS">
<el-radio-group v-model="form.isHttps">
<el-radio v-for="dict in sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="桶权限类型">
<el-radio-group v-model="form.accessPolicy">
<el-radio label="0">private</el-radio>
<el-radio label="1">public</el-radio>
<el-radio label="2">custom</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="域" prop="region">
<el-input v-model="form.region" placeholder="请输入域" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,363 +1,342 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="文件名" prop="fileName">
<el-input
v-model="queryParams.fileName"
placeholder="请输入文件名"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="原名" prop="originalName">
<el-input
v-model="queryParams.originalName"
placeholder="请输入原名"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="文件后缀" prop="fileSuffix">
<el-input
v-model="queryParams.fileSuffix"
placeholder="请输入文件后缀"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item label="服务商" prop="service">
<el-input
v-model="queryParams.service"
placeholder="请输入服务商"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleFile"
v-hasPermi="['system:oss:upload']"
>上传文件</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleImage"
v-hasPermi="['system:oss:upload']"
>上传图片</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:oss:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
:type="previewListResource ? 'danger' : 'warning'"
plain
@click="handlePreviewListResource(!previewListResource)"
v-hasPermi="['system:oss:edit']"
>预览开关 : {{previewListResource ? "禁用" : "启用"}}</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Operation"
@click="handleOssConfig"
v-hasPermi="['system:oss:list']"
>配置管理</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="ossList" @selection-change="handleSelectionChange"
:header-cell-class-name="handleHeaderClass"
@header-click="handleHeaderCLick"
v-if="showTable">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false"/>
<el-table-column label="文件名" align="center" prop="fileName" />
<el-table-column label="原名" align="center" prop="originalName" />
<el-table-column label="文件后缀" align="center" prop="fileSuffix" />
<el-table-column label="文件展示" align="center" prop="url">
<template #default="scope">
<ImagePreview
v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"
:width="100" :height="100"
:src="scope.row.url"
:preview-src-list="[scope.row.url]"/>
<span v-text="scope.row.url"
v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="上传人" align="center" prop="createByName" />
<el-table-column label="服务商" align="center" prop="service" sortable="custom"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改OSS对象存储对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="ossRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文件名">
<fileUpload v-model="form.file" v-if="type === 0"/>
<imageUpload v-model="form.file" v-if="type === 1"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Oss">
<script setup name="Oss" lang="ts">
import { listOss, delOss } from "@/api/system/oss";
import ImagePreview from "@/components/ImagePreview/index.vue";
import { ComponentInternalInstance } from "vue";
import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types";
import { DateModelType } from 'element-plus';
const router = useRouter();
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const ossList = ref([]);
const open = ref(false);
const ossList = ref<OssVO[]>([]);
const showTable = ref(true);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const type = ref(0);
const previewListResource = ref(true);
const daterangeCreateTime = ref([]);
// 默认排序
const defaultSort = ref({prop: 'createTime', order: 'ascending'});
const daterangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
const data = reactive({
form: {},
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
fileName: undefined,
originalName: undefined,
fileSuffix: undefined,
createTime: undefined,
service: undefined
},
rules: {
file: [
{ required: true, message: "文件不能为空", trigger: "blur" }
]
}
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
// 默认排序
const defaultSort = ref({ prop: 'createTime', order: 'ascending' });
const ossFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const initFormData = {
file: undefined,
}
const data = reactive<PageData<OssForm, OssQuery>>({
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
fileName: '',
originalName: '',
fileSuffix: '',
createTime: '',
service: '',
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
rules: {
file: [
{ required: true, message: "文件不能为空", trigger: "blur" }
]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询OSS对象存储列表 */
function getList() {
loading.value = true;
proxy.getConfigKey("sys.oss.previewListResource").then(response => {
previewListResource.value = response.msg === undefined ? true : response.msg === 'true';
});
listOss(proxy.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime")).then(response => {
ossList.value = response.rows;
total.value = response.total;
loading.value = false;
showTable.value = true;
});
const getList = async () => {
loading.value = true;
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
const response = await listOss(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime"));
ossList.value = response.rows;
total.value = response.total;
loading.value = false;
showTable.value = true;
}
function checkFileSuffix(fileSuffix) {
let arr = ["png", "jpg", "jpeg"];
return arr.some(type => {
return fileSuffix.indexOf(type) > -1;
});
function checkFileSuffix(fileSuffix: string[]) {
let arr = ["png", "jpg", "jpeg"];
return arr.some(type => {
return fileSuffix.indexOf(type) > -1;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
dialog.visible = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
file: undefined,
};
proxy.resetForm("ossRef");
form.value = { ...initFormData };
ossFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
showTable.value = false;
daterangeCreateTime.value = [];
proxy.resetForm("queryRef");
queryParams.value.orderByColumn = defaultSort.value.prop;
queryParams.value.isAsc = defaultSort.value.order;
handleQuery();
showTable.value = false;
daterangeCreateTime.value = ['', ''];
queryFormRef.value.resetFields();
queryParams.value.orderByColumn = defaultSort.value.prop;
queryParams.value.isAsc = defaultSort.value.order;
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.ossId);
single.value = selection.length != 1;
multiple.value = !selection.length;
function handleSelectionChange(selection: OssVO[]) {
ids.value = selection.map(item => item.ossId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
// 设置列的排序为我们自定义的排序
function handleHeaderClass({column}) {
column.order = column.multiOrder
/** 设置列的排序为我们自定义的排序 */
const handleHeaderClass = ({ column }: any): any => {
column.order = column.multiOrder
}
// 点击表头进行排序
function handleHeaderCLick(column) {
if (column.sortable !== 'custom') {
return
}
switch (column.multiOrder) {
case 'descending':
column.multiOrder = 'ascending';
break;
case 'ascending':
column.multiOrder = '';
break;
default:
column.multiOrder = 'descending';
break;
}
handleOrderChange(column.property, column.multiOrder)
/** 点击表头进行排序 */
const handleHeaderCLick = (column: any) => {
if (column.sortable !== 'custom') {
return
}
switch (column.multiOrder) {
case 'descending':
column.multiOrder = 'ascending';
break;
case 'ascending':
column.multiOrder = '';
break;
default:
column.multiOrder = 'descending';
break;
}
handleOrderChange(column.property, column.multiOrder)
}
function handleOrderChange(prop, order) {
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
let propIndex = orderByArr.indexOf(prop)
if (propIndex !== -1) {
if (order) {
//排序里已存在 只修改排序
isAscArr[propIndex] = order;
} else {
//如果order为null 则删除排序字段和属性
isAscArr.splice(propIndex, 1);//删除排序
orderByArr.splice(propIndex, 1);//删除属性
}
} else {
//排序里不存在则新增排序
orderByArr.push(prop);
isAscArr.push(order);
}
//合并排序
queryParams.value.orderByColumn = orderByArr.join(",");
queryParams.value.isAsc = isAscArr.join(",");
getList();
const handleOrderChange = (prop: string, order: string) => {
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
let propIndex = orderByArr.indexOf(prop)
if (propIndex !== -1) {
if (order) {
//排序里已存在 只修改排序
isAscArr[propIndex] = order;
} else {
//如果order为null 则删除排序字段和属性
isAscArr.splice(propIndex, 1);//删除排序
orderByArr.splice(propIndex, 1);//删除属性
}
} else {
//排序里不存在则新增排序
orderByArr.push(prop);
isAscArr.push(order);
}
//合并排序
queryParams.value.orderByColumn = orderByArr.join(",");
queryParams.value.isAsc = isAscArr.join(",");
getList();
}
/** 任务日志列表查询 */
function handleOssConfig() {
router.push('/system/oss-config/index')
const handleOssConfig = () => {
router.push('/system/oss-config/index')
}
/** 文件按钮操作 */
function handleFile() {
reset();
open.value = true;
title.value = "上传文件";
type.value = 0;
const handleFile = () => {
dialog.visible = true;
dialog.title = "上传文件";
nextTick(() => {
reset();
type.value = 0;
})
}
/** 图片按钮操作 */
function handleImage() {
reset();
open.value = true;
title.value = "上传图片";
type.value = 1;
const handleImage = () => {
dialog.visible = true;
dialog.title = "上传图片";
nextTick(() => {
reset();
type.value = 1;
})
}
/** 提交按钮 */
function submitForm() {
open.value = false;
getList();
const submitForm = () => {
dialog.visible = false;
getList();
}
/** 下载按钮操作 */
function handleDownload(row) {
proxy.$download.oss(row.ossId)
const handleDownload = (row: OssVO) => {
proxy?.$download.oss(row.ossId)
}
/** 用户状态修改 */
function handlePreviewListResource(previewListResource) {
let text = previewListResource ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?').then(() => {
return proxy.updateConfigByKey("sys.oss.previewListResource", previewListResource);
}).then(() => {
getList()
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
previewListResource.value = previewListResource.value !== true;
});
const handlePreviewListResource = async (preview: boolean) => {
let text = preview ? "启用" : "停用";
try {
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
getList()
proxy?.$modal.msgSuccess(text + "成功");
} catch {
previewListResource.value = previewListResource.value !== true;
}
}
/** 删除按钮操作 */
function handleDelete(row) {
const ossIds = row.ossId || ids.value;
proxy.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?').then(() => {
loading.value = true;
return delOss(ossIds);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).finally(() => {
loading.value = false;
});
const handleDelete = async (row?: OssVO) => {
const ossIds = row?.ossId || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
loading.value = true;
await delOss(ossIds).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="文件名" prop="fileName">
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="原名" prop="originalName">
<el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="文件后缀" prop="fileSuffix">
<el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="daterangeCreateTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item label="服务商" prop="service">
<el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Upload" @click="handleFile" v-hasPermi="['system:oss:upload']">上传文件</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">上传图片</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
:type="previewListResource ? 'danger' : 'warning'"
plain
@click="handlePreviewListResource(!previewListResource)"
v-hasPermi="['system:oss:edit']"
>预览开关 :
{{
previewListResource ? "禁用" : "启用" }}</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">配置管理</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table
v-loading="loading"
:data="ossList"
@selection-change="handleSelectionChange"
:header-cell-class-name="handleHeaderClass"
@header-click="handleHeaderCLick"
v-if="showTable"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false" />
<el-table-column label="文件名" align="center" prop="fileName" />
<el-table-column label="原名" align="center" prop="originalName" />
<el-table-column label="文件后缀" align="center" prop="fileSuffix" />
<el-table-column label="文件展示" align="center" prop="url">
<template #default="scope">
<ImagePreview
v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"
:width="100"
:height="100"
:src="scope.row.url"
:preview-src-list="[scope.row.url]"
/>
<span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="上传人" align="center" prop="createByName" />
<el-table-column label="服务商" align="center" prop="service" sortable="custom" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="下载" placement="top">
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改OSS对象存储对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文件名">
<fileUpload v-model="form.file" v-if="type === 0" />
<imageUpload v-model="form.file" v-if="type === 1" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,277 +1,240 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="岗位编码" prop="postCode">
<el-input
v-model="queryParams.postCode"
placeholder="请输入岗位编码"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="岗位名称" prop="postName">
<el-input
v-model="queryParams.postName"
placeholder="请输入岗位名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:post:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:post:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:post:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:post:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="岗位编号" align="center" prop="postId" v-if="false" />
<el-table-column label="岗位编码" align="center" prop="postCode" />
<el-table-column label="岗位名称" align="center" prop="postName" />
<el-table-column label="岗位排序" align="center" prop="postSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改岗位对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="postRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="岗位名称" prop="postName">
<el-input v-model="form.postName" placeholder="请输入岗位名称" />
</el-form-item>
<el-form-item label="岗位编码" prop="postCode">
<el-input v-model="form.postCode" placeholder="请输入编码名称" />
</el-form-item>
<el-form-item label="岗位顺序" prop="postSort">
<el-input-number v-model="form.postSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="岗位状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Post">
<script setup name="Post" lang="ts">
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
import { PostForm, PostQuery, PostVO } from "@/api/system/post/types";
import { ComponentInternalInstance } from "vue";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
const postList = ref([]);
const open = ref(false);
const postList = ref<PostVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<number | string>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
postCode: undefined,
postName: undefined,
status: undefined
},
rules: {
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
}
const postFormRef = ref(ElForm);
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const { queryParams, form, rules } = toRefs(data);
const initFormData: PostForm = {
postId: undefined,
postCode: '',
postName: '',
postSort: 0,
status: "0",
remark: ''
}
const data = reactive<PageData<PostForm, PostQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
postCode: '',
postName: '',
status: ''
},
rules: {
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs<PageData<PostForm, PostQuery>>(data);
/** 查询岗位列表 */
function getList() {
loading.value = true;
listPost(queryParams.value).then(response => {
postList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getList = async () => {
loading.value = true;
const res = await listPost(queryParams.value);
postList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
function reset() {
form.value = {
postId: undefined,
postCode: undefined,
postName: undefined,
postSort: 0,
status: "0",
remark: undefined
};
proxy.resetForm("postRef");
const reset = () => {
form.value = {...initFormData};
postFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.postId);
single.value = selection.length != 1;
multiple.value = !selection.length;
const handleSelectionChange = (selection: PostVO[]) => {
ids.value = selection.map(item => item.postId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加岗位";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加岗位";
nextTick(() => {
reset();
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const postId = row.postId || ids.value;
getPost(postId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改岗位";
});
const handleUpdate = (row?: PostVO) => {
dialog.visible = true;
dialog.title = "修改岗位";
nextTick(async () => {
reset();
const postId = row?.postId || ids.value[0];
const res = await getPost(postId);
form.value = res.data;
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["postRef"].validate(valid => {
if (valid) {
if (form.value.postId != undefined) {
updatePost(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addPost(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
const submitForm = () => {
postFormRef.value.validate(async (valid: boolean) => {
if (valid) {
form.value.postId ? await updatePost(form.value) : await addPost(form.value);
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const postIds = row.postId || ids.value;
proxy.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
return delPost(postIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: PostVO) => {
const postIds = row?.postId || ids.value;
await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
await delPost(postIds);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/post/export", {
...queryParams.value
}, `post_${new Date().getTime()}.xlsx`);
const handleExport = () => {
proxy?.download("system/post/export", {
...queryParams.value
}, `post_${new Date().getTime()}.xlsx`);
}
getList();
onMounted(() => {
getList();
});
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
<el-form-item label="岗位编码" prop="postCode">
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="岗位名称" prop="postName">
<el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:post:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:post:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:post:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="岗位编号" align="center" prop="postId" v-if="false" />
<el-table-column label="岗位编码" align="center" prop="postCode" />
<el-table-column label="岗位名称" align="center" prop="postName" />
<el-table-column label="岗位排序" align="center" prop="postSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改岗位对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="岗位名称" prop="postName">
<el-input v-model="form.postName" placeholder="请输入岗位名称" />
</el-form-item>
<el-form-item label="岗位编码" prop="postCode">
<el-input v-model="form.postCode" placeholder="请输入编码名称" />
</el-form-item>
<el-form-item label="岗位顺序" prop="postSort">
<el-input-number v-model="form.postSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="岗位状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,172 +1,158 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="openSelectUser"
v-hasPermi="['system:role:add']"
>添加用户</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="CircleClose"
:disabled="multiple"
@click="cancelAuthUserAll"
v-hasPermi="['system:role:remove']"
>批量取消授权</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Close"
@click="handleClose"
>关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']">取消授权</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
</div>
</template>
<script setup name="AuthUser">
import selectUser from "./selectUser";
<script setup name="AuthUser" lang="ts">
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
import { UserQuery } from "@/api/system/user/types";
import { ComponentInternalInstance } from "vue";
import { UserVO } from "@/api/system/user/types";
import SelectUser from "./selectUser.vue";
// import { ElForm, ElSelect} from 'element-plus';
const route = useRoute();
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
const userList = ref([]);
const userList = ref<UserVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const multiple = ref(true);
const total = ref(0);
const userIds = ref([]);
const userIds = ref<Array<string | number>>([]);
const queryParams = reactive({
const queryFormRef = ref(ElForm);
const selectRef = ref(SelectUser);
const queryParams = reactive<UserQuery>({
pageNum: 1,
pageSize: 10,
roleId: route.params.roleId,
roleId: route.params.roleId as string,
userName: undefined,
phonenumber: undefined,
});
/** 查询授权用户列表 */
function getList() {
const getList = async () => {
loading.value = true;
allocatedUserList(queryParams).then(response => {
userList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await allocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
loading.value = false;
}
// 返回按钮
function handleClose() {
const handleClose = () => {
const obj = { path: "/system/role" };
proxy.$tab.closeOpenPage(obj);
proxy?.$tab.closeOpenPage(obj);
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery=() => {
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
const resetQuery=() =>{
queryFormRef.value.resetFields();
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: UserVO[]) =>{
userIds.value = selection.map(item => item.userId);
multiple.value = !selection.length;
}
/** 打开授权用户表弹窗 */
function openSelectUser() {
proxy.$refs["selectRef"].show();
const openSelectUser = () => {
selectRef.value.show();
}
/** 取消授权按钮操作 */
function cancelAuthUser(row) {
proxy.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function () {
return authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
}).then(() => {
getList();
proxy.$modal.msgSuccess("取消授权成功");
}).catch(() => {});
const cancelAuthUser = async (row: UserVO) => {
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
getList();
proxy?.$modal.msgSuccess("取消授权成功");
}
/** 批量取消授权按钮操作 */
function cancelAuthUserAll(row) {
const cancelAuthUserAll = async () => {
const roleId = queryParams.roleId;
const uIds = userIds.value.join(",");
proxy.$modal.confirm("是否取消选中用户授权数据项?").then(function () {
return authUserCancelAll({ roleId: roleId, userIds: uIds });
}).then(() => {
getList();
proxy.$modal.msgSuccess("取消授权成功");
}).catch(() => {});
await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
await authUserCancelAll({ roleId: roleId, userIds: uIds });
getList();
proxy?.$modal.msgSuccess("取消授权成功");
}
getList();
onMounted(() => {
getList();
});
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="openSelectUser" v-hasPermi="['system:role:add']">添加用户</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll" v-hasPermi="['system:role:remove']">
批量取消授权
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :search="true"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ scope.row.createTime }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="取消授权" placement="top">
<el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']"> </el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="handleQuery"
/>
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
</el-card>
</div>
</template>
<style lang="scss" scoped></style>

View File

@ -1,274 +1,30 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
<el-form-item label="角色名称" prop="roleName">
<el-input
v-model="queryParams.roleName"
placeholder="请输入角色名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="权限字符" prop="roleKey">
<el-input
v-model="queryParams.roleKey"
placeholder="请输入权限字符"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="角色状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:role:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:role:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:role:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:role:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 表格数据 -->
<el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="角色编号" prop="roleId" width="120" v-if="false" />
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
<el-table-column label="显示顺序" prop="roleSort" width="100" />
<el-table-column label="状态" align="center" width="100">
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
</el-tooltip>
<el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改角色配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
</el-form-item>
<el-form-item prop="roleKey">
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
</span>
</template>
<el-input v-model="form.roleKey" placeholder="请输入权限字符" />
</el-form-item>
<el-form-item label="角色顺序" prop="roleSort">
<el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单权限">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menuRef"
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 分配角色数据权限对话框 -->
<el-dialog :title="title" v-model="openDataScope" width="500px" append-to-body>
<el-form :model="form" label-width="80px">
<el-form-item label="角色名称">
<el-input v-model="form.roleName" :disabled="true" />
</el-form-item>
<el-form-item label="权限字符">
<el-input v-model="form.roleKey" :disabled="true" />
</el-form-item>
<el-form-item label="权限范围">
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限" v-show="form.dataScope == 2">
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="deptOptions"
show-checkbox
default-expand-all
ref="deptRef"
node-key="id"
:check-strictly="!form.deptCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDataScope"> </el-button>
<el-button @click="cancelDataScope"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Role">
<script setup name="Role" lang="ts">
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu";
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
import { ComponentInternalInstance } from 'vue';
import { ElTree, ElForm, DateModelType } from 'element-plus';
const router = useRouter();
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
const roleList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const dateRange = ref([]);
const menuOptions = ref([]);
const menuExpand = ref(false);
const menuNodeAll = ref(false);
const deptExpand = ref(true);
const deptNodeAll = ref(false);
const deptOptions = ref([]);
const openDataScope = ref(false);
const menuRef = ref(null);
const deptRef = ref(null);
const roleList = ref<RoleVO[]>();
const loading = ref(true)
const showSearch = ref(true)
const ids = ref<Array<string | number>>([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const dateRange = ref<[DateModelType, DateModelType]>(['', ''])
const menuOptions = ref<MenuTreeOption[]>([])
const menuExpand = ref(false)
const menuNodeAll = ref(false)
const deptExpand = ref(true)
const deptNodeAll = ref(false)
const deptOptions = ref<DeptTreeOption[]>([])
const openDataScope = ref(false)
/** 数据范围选项*/
const dataScopeOptions = ref([
@ -277,179 +33,189 @@ const dataScopeOptions = ref([
{ value: "3", label: "本部门数据权限" },
{ value: "4", label: "本部门及以下数据权限" },
{ value: "5", label: "仅本人数据权限" }
]);
])
const data = reactive({
form: {},
const queryFormRef = ref(ElForm);
const roleFormRef = ref(ElForm);
const dataScopeRef = ref(ElForm);
const menuRef = ref(ElTree);
const deptRef = ref(ElTree);
const initForm: RoleForm = {
roleId: undefined,
roleSort: 1,
status: '0',
roleName: '',
roleKey: '',
menuCheckStrictly: true,
deptCheckStrictly: true,
remark: '',
dataScope: 1,
menuIds: [],
deptIds: [],
}
const data = reactive<PageData<RoleForm, RoleQuery>>({
form: {...initForm},
queryParams: {
pageNum: 1,
pageSize: 10,
roleName: undefined,
roleKey: undefined,
status: undefined
roleName: '',
roleKey: '',
status: '',
},
rules: {
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
},
}
})
const { form, queryParams, rules } = toRefs(data)
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const { queryParams, form, rules } = toRefs(data);
/** 查询角色列表 */
function getList() {
loading.value = true;
listRole(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
roleList.value = response.rows;
total.value = response.total;
loading.value = false;
});
/**
* 查询角色列表
*/
const getList = () => {
loading.value = true
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
roleList.value = res.rows
total.value = res.total
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
/**
* 搜索按钮操作
*/
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
/** 重置 */
const resetQuery = () => {
dateRange.value = ['', '']
queryFormRef.value.resetFields();
handleQuery();
}
/** 删除按钮操作 */
function handleDelete(row) {
const roleIds = row.roleId || ids.value;
proxy.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function () {
return delRole(roleIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
/**删除按钮操作 */
const handleDelete = async (row?: RoleVO) => {
const roleids = row?.roleId || ids.value;
await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项');
await delRole(roleids);
getList();
proxy?.$modal.msgSuccess('删除成功');
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/role/export", {
const handleExport = () => {
proxy?.download("system/role/export", {
...queryParams.value,
}, `role_${new Date().getTime()}.xlsx`);
}, `role_${new Date().getTime()}.xlsx`)
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.roleId);
const handleSelectionChange = (selection: RoleVO[]) => {
ids.value = selection.map((item: RoleVO) => item.roleId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 角色状态修改 */
function handleStatusChange(row) {
const handleStatusChange = async (row: RoleVO) => {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
return changeRoleStatus(row.roleId, row.status);
}).then(() => {
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
await changeRoleStatus(row.roleId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch {
row.status = row.status === "0" ? "1" : "0";
});
}
/** 更多操作 */
function handleCommand(command, row) {
switch (command) {
case "handleDataScope":
handleDataScope(row);
break;
case "handleAuthUser":
handleAuthUser(row);
break;
default:
break;
}
}
/** 分配用户 */
function handleAuthUser(row) {
const handleAuthUser = (row: RoleVO) => {
router.push("/system/role-auth/user/" + row.roleId);
}
/** 查询菜单树结构 */
function getMenuTreeselect() {
menuTreeselect().then(response => {
menuOptions.value = response.data;
});
const getMenuTreeselect = async () => {
const res = await menuTreeselect();
menuOptions.value = res.data;
}
/** 所有部门节点数据 */
function getDeptAllCheckedKeys() {
const getDeptAllCheckedKeys = () => {
// 目前被选中的部门节点
let checkedKeys = deptRef.value.getCheckedKeys();
// 半选中的部门节点
let halfCheckedKeys = deptRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
return checkedKeys
}
/** 重置新增的表单以及其他数据 */
function reset() {
if (menuRef.value != undefined) {
menuRef.value.setCheckedKeys([]);
}
menuExpand.value = false;
menuNodeAll.value = false;
deptExpand.value = true;
deptNodeAll.value = false;
form.value = {
roleId: undefined,
roleName: undefined,
roleKey: undefined,
roleSort: 0,
status: "0",
menuIds: [],
deptIds: [],
menuCheckStrictly: true,
deptCheckStrictly: true,
remark: undefined
};
proxy.resetForm("roleRef");
const reset = () => {
menuRef.value.setCheckedKeys([]);
menuExpand.value = false
menuNodeAll.value = false
deptExpand.value = true
deptNodeAll.value = false
form.value = initForm
roleFormRef.value.resetFields();
}
/** 添加角色 */
function handleAdd() {
reset();
getMenuTreeselect();
open.value = true;
title.value = "添加角色";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加角色";
nextTick(() => {
reset();
getMenuTreeselect();
})
}
/** 修改角色 */
function handleUpdate(row) {
reset();
const roleId = row.roleId || ids.value;
const roleMenu = getRoleMenuTreeselect(roleId);
getRole(roleId).then(response => {
form.value = response.data;
const handleUpdate = async (row?: RoleVO) => {
const roleId = row?.roleId || ids.value[0]
const roleMenu = getRoleMenuTreeselect(roleId)
const { data } = await getRole(roleId);
dialog.visible = true;
dialog.title = "修改角色";
nextTick(() => {
reset();
Object.assign(form.value, data);
form.value.roleSort = Number(form.value.roleSort);
open.value = true;
nextTick(() => {
roleMenu.then((res) => {
let checkedKeys = res.data.checkedKeys;
checkedKeys.forEach((v) => {
nextTick(() => {
menuRef.value.setChecked(v, true, false);
});
});
});
});
title.value = "修改角色";
});
nextTick(async () => {
const res = await roleMenu;
let checkedKeys = res.checkedKeys;
checkedKeys.forEach((v) => {
nextTick(() => {
menuRef.value.setChecked(v, true, false);
})
})
})
})
}
/** 根据角色ID查询菜单树结构 */
function getRoleMenuTreeselect(roleId) {
return roleMenuTreeselect(roleId).then(response => {
menuOptions.value = response.data.menus;
return response;
});
const getRoleMenuTreeselect = (roleId: string | number) => {
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
menuOptions.value = res.data.menus;
return res.data;
})
}
/** 根据角色ID查询部门树结构 */
function getDeptTree(roleId) {
return deptTreeSelect(roleId).then(response => {
deptOptions.value = response.data.depts;
return response;
});
const getRoleDeptTreeSelect = async (roleId: string | number) => {
const res = await deptTreeSelect(roleId);
deptOptions.value = res.data.depts;
return res.data;
}
/** 树权限(展开/折叠)*/
function handleCheckedTreeExpand(value, type) {
const handleCheckedTreeExpand = (value: any, type: string) => {
if (type == "menu") {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
@ -463,7 +229,7 @@ function handleCheckedTreeExpand(value, type) {
}
}
/** 树权限(全选/全不选) */
function handleCheckedTreeNodeAll(value, type) {
const handleCheckedTreeNodeAll = (value: any, type: string) => {
if (type == "menu") {
menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
} else if (type == "dept") {
@ -471,15 +237,15 @@ function handleCheckedTreeNodeAll(value, type) {
}
}
/** 树权限(父子联动) */
function handleCheckedTreeConnect(value, type) {
const handleCheckedTreeConnect = (value: any, type: string) => {
if (type == "menu") {
form.value.menuCheckStrictly = value ? true : false;
form.value.menuCheckStrictly = value;
} else if (type == "dept") {
form.value.deptCheckStrictly = value ? true : false;
form.value.deptCheckStrictly = value;
}
}
/** 所有菜单节点数据 */
function getMenuAllCheckedKeys() {
const getMenuAllCheckedKeys = () => {
// 目前被选中的菜单节点
let checkedKeys = menuRef.value.getCheckedKeys();
// 半选中的菜单节点
@ -488,73 +254,255 @@ function getMenuAllCheckedKeys() {
return checkedKeys;
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["roleRef"].validate(valid => {
const submitForm = () => {
roleFormRef.value.validate(async (valid: boolean) => {
if (valid) {
if (form.value.roleId != undefined) {
form.value.menuIds = getMenuAllCheckedKeys();
updateRole(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
form.value.menuIds = getMenuAllCheckedKeys();
addRole(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
form.value.menuIds = getMenuAllCheckedKeys()
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
proxy?.$modal.msgSuccess("操作成功")
dialog.visible = false
getList()
}
});
})
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
const cancel = () => {
reset()
dialog.visible = false;
}
/** 选择角色权限范围触发 */
function dataScopeSelectChange(value) {
const dataScopeSelectChange = (value: string) => {
if (value !== "2") {
deptRef.value.setCheckedKeys([]);
deptRef.value.setCheckedKeys([])
}
}
/** 分配数据权限操作 */
function handleDataScope(row) {
reset();
const deptTreeSelect = getDeptTree(row.roleId);
getRole(row.roleId).then(response => {
form.value = response.data;
openDataScope.value = true;
const handleDataScope = async (row: RoleVO) => {
const roleDeptTreeselect = getRoleDeptTreeSelect(row.roleId);
const response = await getRole(row.roleId);
Object.assign(form.value, response.data);
openDataScope.value = true;
dialog.title = "分配数据权限";
nextTick(async () => {
const res = await roleDeptTreeselect;
nextTick(() => {
deptTreeSelect.then(res => {
nextTick(() => {
if (deptRef.value) {
deptRef.value.setCheckedKeys(res.data.checkedKeys);
}
});
});
});
title.value = "分配数据权限";
});
if (deptRef.value) {
deptRef.value.setCheckedKeys(res.checkedKeys);
}
})
})
}
/** 提交按钮(数据权限) */
function submitDataScope() {
if (form.value.roleId != undefined) {
const submitDataScope = async () => {
if (form.value.roleId) {
form.value.deptIds = getDeptAllCheckedKeys();
dataScope(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
openDataScope.value = false;
getList();
});
await dataScope(form.value);
proxy?.$modal.msgSuccess("修改成功");
openDataScope.value = false;
getList();
}
}
/** 取消按钮(数据权限)*/
function cancelDataScope() {
const cancelDataScope = () => {
dataScopeRef.value.resetFields();
form.value = {...initForm};
openDataScope.value = false;
reset();
}
getList();
onMounted(() => {
getList();
});
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="权限字符" prop="roleKey">
<el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button type="primary" @click="handleAdd()" icon="Plus" v-hasPermi="['system:role:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" @click="handleUpdate()" :disabled="single" icon="Edit" v-hasPermi="['system:role:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" :disabled="ids.length === 0" @click="handleDelete()" v-hasPermi="['system:role:delete']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:role:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="角色编号" prop="roleId" width="120" />
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
<el-table-column label="显示顺序" prop="roleSort" width="100" />
<el-table-column label="状态" align="center" width="100">
<template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="180">
<template #default="scope">
<el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
</el-tooltip>
<el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
<el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-if="total > 0"
v-model:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="handleQuery"
/>
</el-card>
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
</el-form-item>
<el-form-item prop="roleKey">
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
</span>
</template>
<el-input v-model="form.roleKey" placeholder="请输入权限字符" />
</el-form-item>
<el-form-item label="角色顺序" prop="roleSort">
<el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单权限">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menuRef"
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 分配角色数据权限对话框 -->
<el-dialog :title="dialog.title" v-model="openDataScope" width="500px" append-to-body>
<el-form :model="form" label-width="80px" ref="dataScopeRef">
<el-form-item label="角色名称">
<el-input v-model="form.roleName" :disabled="true" />
</el-form-item>
<el-form-item label="权限字符">
<el-input v-model="form.roleKey" :disabled="true" />
</el-form-item>
<el-form-item label="权限范围">
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
<el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限" v-show="form.dataScope === 2">
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="deptOptions"
show-checkbox
default-expand-all
ref="deptRef"
node-key="id"
:check-strictly="!form.deptCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDataScope"> </el-button>
<el-button @click="cancelDataScope"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,140 +1,133 @@
<template>
<!-- 授权用户 -->
<el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row>
<el-table @row-click="clickRow" ref="refTable" :data="userList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSelectUser"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup name="SelectUser">
<script setup name="SelectUser" lang="ts">
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
import { UserVO } from '@/api/system/user/types';
import { UserQuery } from '@/api/system/user/types';
import { ComponentInternalInstance } from 'vue';
import { ElForm, ElTable } from 'element-plus';
const props = defineProps({
roleId: {
type: [Number, String]
}
});
})
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
const userList = ref([]);
const userList = ref<UserVO[]>([]);
const visible = ref(false);
const total = ref(0);
const userIds = ref([]);
const userIds = ref<Array<string | number>>([]);
const queryParams = reactive({
const queryParams = reactive<UserQuery>({
pageNum: 1,
pageSize: 10,
roleId: undefined,
userName: undefined,
phonenumber: undefined
});
})
// 显示弹框
function show() {
const tableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const show = () => {
queryParams.roleId = props.roleId;
getList();
visible.value = true;
}
/**选择行 */
function clickRow(row) {
proxy.$refs["refTable"].toggleRowSelection(row);
/**
* 选择行
*/
const clickRow = (row: any) => {
tableRef.value.toggleRowSelection(row);
}
// 多选框选中数据
function handleSelectionChange(selection) {
userIds.value = selection.map(item => item.userId);
/** 多选框选中数据 */
const handleSelectionChange = (selection: UserVO[]) => {
userIds.value = selection.map((item: UserVO) => item.userId);
}
// 查询表数据
function getList() {
unallocatedUserList(queryParams).then(res => {
userList.value = res.rows;
total.value = res.total;
});
/** 查询数据 */
const getList = async () => {
const res = await unallocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
const emit = defineEmits(["ok"]);
/** 选择授权用户操作 */
function handleSelectUser() {
const roleId = queryParams.roleId;
const uIds = userIds.value.join(",");
if (uIds == "") {
proxy.$modal.msgError("请选择要分配的用户");
return;
}
authUserSelectAll({ roleId: roleId, userIds: uIds }).then(res => {
proxy.$modal.msgSuccess(res.msg);
if (res.code === 200) {
visible.value = false;
emit("ok");
}
});
const resetQuery = () => {
queryFormRef.value.resetFields();
getList();
}
const emit = defineEmits(["ok"]);
/**选择授权用户操作 */
const handleSelectUser = async () => {
const roleId = queryParams.roleId;
const ids = userIds.value.join(',');
if (ids == "") {
proxy?.$modal.msgError('请选择要分配的用户');
return;
}
await authUserSelectAll({ roleId, userIds: ids });
proxy?.$modal.msgSuccess('分配成功');
emit('ok');
visible.value = false;
}
// 暴露
defineExpose({
show,
});
</script>
<template>
<el-row>
<el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" 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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row>
<el-table @row-click="clickRow" ref="tableRef" :data="userList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-if="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSelectUser"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</template>
</el-dialog>
</el-row>
</template>
<style scoped></style>

View File

@ -1,234 +1,66 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="租户编号" prop="tenantId">
<el-input
v-model="queryParams.tenantId"
placeholder="请输入租户编号"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="联系人" prop="contactUserName">
<el-input
v-model="queryParams.contactUserName"
placeholder="请输入联系人"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input
v-model="queryParams.contactPhone"
placeholder="请输入联系电话"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="企业名称" prop="companyName">
<el-input
v-model="queryParams.companyName"
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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<script setup name="Tenant" lang="ts">
import { listTenant, getTenant, delTenant, addTenant, updateTenant, changeTenantStatus, syncTenantPackage} from '@/api/system/tenant';
import { listTenantPackage } from '@/api/system/tenantPackage';
import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
import { TenantPkgVO } from '@/api/system/tenantPackage/types';
import { ComponentInternalInstance } from 'vue';
import to from 'await-to-js';
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:tenant:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:tenant:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:tenant:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:tenant:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="id" align="center" prop="id" v-if="false"/>
<el-table-column label="租户编号" align="center" prop="tenantId" />
<el-table-column label="联系人" align="center" prop="contactUserName" />
<el-table-column label="联系电话" align="center" prop="contactPhone" />
<el-table-column label="企业名称" align="center" prop="companyName" />
<el-table-column label="社会信用代码" align="center" prop="licenseNumber" />
<el-table-column label="过期时间" align="center" prop="expireTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="租户状态" align="center" prop="status">
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']">修改</el-button>
<el-button link type="primary" icon="Edit" @click="handleSyncTenantPackage(scope.row)" v-hasPermi="['system:tenant:edit']">同步套餐</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenant:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改租户对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="tenantRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="form.companyName" placeholder="请输入企业名称" />
</el-form-item>
<el-form-item label="联系人" prop="contactUserName">
<el-input v-model="form.contactUserName" placeholder="请输入联系人" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
</el-form-item>
<el-form-item v-if="form.id == undefined" label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30"/>
</el-form-item>
<el-form-item v-if="form.id == undefined" label="用户密码" prop="password">
<el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20"/>
</el-form-item>
<el-form-item label="租户套餐" prop="packageId">
<el-select v-model="form.packageId" :disabled="form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
<el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId"/>
</el-select>
</el-form-item>
<el-form-item label="过期时间" prop="expireTime">
<el-date-picker clearable
v-model="form.expireTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择过期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="用户数量" prop="accountCount">
<el-input v-model="form.accountCount" placeholder="请输入用户数量" />
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="form.address" placeholder="请输入地址" />
</el-form-item>
<el-form-item label="企业代码" prop="licenseNumber">
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
</el-form-item>
<el-form-item label="企业简介" prop="intro">
<el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script setup name="Tenant">
import { listTenant, getTenant, delTenant, addTenant, updateTenant, changeTenantStatus, syncTenantPackage} from "@/api/system/tenant";
import { listTenantPackage } from "@/api/system/tenantPackage";
const { proxy } = getCurrentInstance();
const tenantList = ref([]);
const packageList = ref([]);
const open = ref(false);
const tenantList = ref<TenantVO[]>([]);
const packageList = ref<TenantPkgVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
packageList: [],
const queryFormRef = ref(ElForm);
const tenantFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: TenantForm = {
id: undefined,
tenantId: undefined,
contactUserName: '',
contactPhone: '',
username: '',
password: '',
companyName: '',
licenseNumber: '',
domain: '',
address: '',
intro: '',
remark: '',
packageId: '',
expireTime: '',
accountCount: 0,
status: '0',
}
const data = reactive<PageData<TenantForm, TenantQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
tenantId: undefined,
contactUserName: undefined,
contactPhone: undefined,
companyName: undefined,
licenseNumber: undefined,
address: undefined,
intro: undefined,
domain: undefined,
packageId: undefined,
expireTime: undefined,
accountCount: undefined,
status: undefined,
tenantId: '',
contactUserName: '',
contactPhone: '',
companyName: ''
},
rules: {
id: [
{ required: true, message: "id不能为空", trigger: "blur" }
],
tenantId: [
{ required: true, message: "租户编号不能为空", trigger: "blur" }
],
contactUserName: [
{ required: true, message: "联系人不能为空", trigger: "blur" }
],
contactPhone: [
{ required: true, message: "联系电话不能为空", trigger: "blur" }
],
companyName: [
{ required: true, message: "企业名称不能为空", trigger: "blur" }
],
id: [{ required: true, message: "id不能为空", trigger: "blur" }],
tenantId: [{ required: true, message: "租户编号不能为空", trigger: "blur" }],
contactUserName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
contactPhone: [{ required: true, message: "联系电话不能为空", trigger: "blur" }],
companyName: [{ required: true, message: "企业名称不能为空", trigger: "blur" }],
username: [
{ required: true, message: "用户名不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
@ -243,166 +75,280 @@ const data = reactive({
const { queryParams, form, rules } = toRefs(data);
/** 查询所有租户套餐 */
function getTenantPackage() {
listTenantPackage().then(res =>{
packageList.value = res.rows;
})
const getTenantPackage = async () => {
const res = await listTenantPackage()
packageList.value = res.rows;
}
/** 查询租户列表 */
function getList() {
const getList = async () => {
loading.value = true;
listTenant(queryParams.value).then(response => {
tenantList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await listTenant(queryParams.value);
tenantList.value = res.rows;
total.value = res.total;
loading.value = false;
}
// 租户套餐状态修改
function handleStatusChange(row) {
const handleStatusChange = async (row: TenantVO) => {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?').then(function() {
return changeTenantStatus(row.id, row.tenantId, row.status);
}).then(() => {
proxy.$modal.msgSuccess(text + "成功");
}).catch(function() {
try {
await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
await changeTenantStatus(row.id, row.tenantId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
} catch {
row.status = row.status === "0" ? "1" : "0";
});
}
}
// 取消按钮
function cancel() {
open.value = false;
const cancel = () => {
reset();
dialog.visible = false;
}
// 表单重置
function reset() {
form.value = {
id: undefined,
tenantId: undefined,
contactUserName: undefined,
contactPhone: undefined,
username: undefined,
password: undefined,
companyName: undefined,
licenseNumber: undefined,
address: undefined,
intro: undefined,
remark: undefined,
packageId: undefined,
expireTime: undefined,
accountCount: undefined,
status: undefined
};
proxy.resetForm("tenantRef");
const reset = () => {
form.value = {...initFormData};
tenantFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: TenantVO[]) => {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
getTenantPackage();
open.value = true;
title.value = "添加租户";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加租户";
nextTick(() => {
reset();
getTenantPackage();
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
loading.value = true
reset();
getTenantPackage();
const _id = row.id || ids.value
getTenant(_id).then(response => {
const handleUpdate = (row?: TenantVO) => {
loading.value = true;
dialog.visible = true;
dialog.title = "修改租户";
nextTick(async () => {
reset();
getTenantPackage();
const _id = row?.id || ids.value[0];
const res = await getTenant(_id);
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改租户";
});
Object.assign(form.value, res.data)
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["tenantRef"].validate(valid => {
const submitForm = () => {
tenantFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id != null) {
updateTenant(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
if (form.value.id) {
await updateTenant(form.value).finally(() => buttonLoading.value = false);
} else {
addTenant(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
await addTenant(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value;
proxy.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?').then(function() {
loading.value = true;
return delTenant(_ids);
}).then(() => {
loading.value = true;
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
});
const handleDelete = async (row?: TenantVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
loading.value = true;
await delTenant(_ids).finally(() => loading.value = false);
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 同步租户套餐按钮操作 */
function handleSyncTenantPackage(row) {
proxy.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?').then(() => {
loading.value = true;
return syncTenantPackage(row.tenantId, row.packageId);
}).then(() => {
const handleSyncTenantPackage = async (row: TenantVO) => {
try {
await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
loading.value = true;
await syncTenantPackage(row.tenantId, row.packageId);
getList();
proxy.$modal.msgSuccess("同步成功");
}).catch(() => {
}).finally(() => {
proxy?.$modal.msgSuccess("同步成功");
} catch {return} finally {
loading.value = false;
});
}
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('system/tenant/export', {
const handleExport = () => {
proxy?.download('system/tenant/export', {
...queryParams.value
}, `tenant_${new Date().getTime()}.xlsx`)
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="租户编号" prop="tenantId">
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系人" prop="contactUserName">
<el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="queryParams.companyName" 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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenant:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenant:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenant:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenant:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="id" align="center" prop="id" v-if="false" />
<el-table-column label="租户编号" align="center" prop="tenantId" />
<el-table-column label="联系人" align="center" prop="contactUserName" />
<el-table-column label="联系电话" align="center" prop="contactPhone" />
<el-table-column label="企业名称" align="center" prop="companyName" />
<el-table-column label="社会信用代码" align="center" prop="licenseNumber" />
<el-table-column label="过期时间" align="center" prop="expireTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="租户状态" align="center" prop="status">
<template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']"></el-button>
</el-tooltip>
<el-tooltip content="同步套餐" placement="top">
<el-button link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)" v-hasPermi="['system:tenant:edit']">
</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenant:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改租户对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="form.companyName" placeholder="请输入企业名称" />
</el-form-item>
<el-form-item label="联系人" prop="contactUserName">
<el-input v-model="form.contactUserName" placeholder="请输入联系人" />
</el-form-item>
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
</el-form-item>
<el-form-item v-if="!form.id" label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
</el-form-item>
<el-form-item v-if="!form.id" label="用户密码" prop="password">
<el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20" />
</el-form-item>
<el-form-item label="租户套餐" prop="packageId">
<el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
<el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId" />
</el-select>
</el-form-item>
<el-form-item label="过期时间" prop="expireTime">
<el-date-picker clearable v-model="form.expireTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="用户数量" prop="accountCount">
<el-input v-model="form.accountCount" placeholder="请输入用户数量" />
</el-form-item>
<el-form-item label="绑定域名" prop="domain">
<el-input v-model="form.domain" placeholder="请输入绑定域名" />
</el-form-item>
<el-form-item label="企业地址" prop="address">
<el-input v-model="form.address" placeholder="请输入企业地址" />
</el-form-item>
<el-form-item label="企业代码" prop="licenseNumber">
<el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
</el-form-item>
<el-form-item label="企业简介" prop="intro">
<el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,362 +1,333 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="套餐名称" prop="packageName">
<el-input
v-model="queryParams.packageName"
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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:tenantPackage:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:tenantPackage:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:tenantPackage:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['system:tenantPackage:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="租户套餐id" align="center" prop="packageId" v-if="false"/>
<el-table-column label="套餐名称" align="center" prop="packageName" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="状态" align="center" prop="status" >
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改租户套餐对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="tenantPackageRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="套餐名称" prop="packageName">
<el-input v-model="form.packageName" placeholder="请输入套餐名称" />
</el-form-item>
<el-form-item label="关联菜单">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menuRef"
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script setup name="TenantPackage">
<script setup name="TenantPackage" lang="ts">
import { listTenantPackage, getTenantPackage, delTenantPackage, addTenantPackage, updateTenantPackage, changePackageStatus } from "@/api/system/tenantPackage";
import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
import { ComponentInternalInstance } from "vue";
import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from "@/api/system/tenantPackage/types";
import { MenuTreeOption } from "@/api/system/menu/types";
import { CheckboxValueType, ElTree, ElForm } from 'element-plus';
import to from "await-to-js";
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const tenantPackageList = ref([]);
const open = ref(false);
const tenantPackageList = ref<TenantPkgVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const menuExpand = ref(false);
const menuNodeAll = ref(false);
const menuOptions = ref([]);
const menuOptions = ref<MenuTreeOption[]>([]);
const data = reactive({
form: {},
const menuTreeRef = ref(ElTree);
const queryFormRef = ref(ElForm);
const tenantPackageFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: TenantPkgForm = {
packageId: undefined,
packageName: '',
menuIds: '',
remark: '',
menuCheckStrictly: true,
status: ''
};
const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
packageName: undefined,
status: undefined,
packageName: '',
status: '',
},
rules: {
packageId: [
{ required: true, message: "租户套餐id不能为空", trigger: "blur" }
],
packageName: [
{ required: true, message: "套餐名称不能为空", trigger: "blur" }
]
packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询菜单树结构 */
function getMenuTreeselect() {
menuTreeselect().then(response => {
menuOptions.value = response.data;
});
const getMenuTreeselect = async() => {
const { data } = await menuTreeselect();
menuOptions.value = data;
}
// 所有菜单节点数据
function getMenuAllCheckedKeys() {
const getMenuAllCheckedKeys = () => {
// 目前被选中的菜单节点
let checkedKeys = proxy.$refs.menuRef.getCheckedKeys();
let checkedKeys = menuTreeRef.value.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = proxy.$refs.menuRef.getHalfCheckedKeys();
let halfCheckedKeys = menuTreeRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
}
/** 根据租户套餐ID查询菜单树结构 */
function getPackageMenuTreeselect(packageId) {
return tenantPackageMenuTreeselect(packageId).then(response => {
menuOptions.value = response.data.menus;
return response;
});
const getPackageMenuTreeselect = async(packageId: string | number) => {
const res = await tenantPackageMenuTreeselect(packageId);
menuOptions.value = res.data.menus;
return Promise.resolve(res);
}
/** 查询租户套餐列表 */
function getList() {
const getList = async () => {
loading.value = true;
listTenantPackage(queryParams.value).then(response => {
tenantPackageList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const res = await listTenantPackage(queryParams.value);
tenantPackageList.value = res.rows;
total.value = res.total;
loading.value = false;
}
// 租户套餐状态修改
function handleStatusChange(row) {
const handleStatusChange = async (row: TenantPkgVO) => {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?').then(function() {
return changePackageStatus(row.packageId, row.status);
}).then(() => {
proxy.$modal.msgSuccess(text + "成功");
}).catch(function() {
const [err] = await to(proxy?.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?') as Promise<any>)
if (err) {
row.status = row.status === "0" ? "1" : "0";
});
} else {
await changePackageStatus(row.packageId, row.status);
proxy?.$modal.msgSuccess(text + "成功");
}
}
// 取消按钮
function cancel() {
open.value = false;
const cancel = () => {
reset();
dialog.visible = false;
}
// 表单重置
function reset() {
if (proxy.$refs.menuRef != undefined) {
proxy.$refs.menuRef.setCheckedKeys([]);
}
const reset = () => {
menuTreeRef.value.setCheckedKeys([]);
menuExpand.value = false;
menuNodeAll.value = false;
form.value = {
packageId: undefined,
packageName: undefined,
menuIds: undefined,
remark: undefined,
menuCheckStrictly: true,
status: undefined
};
proxy.resetForm("tenantPackageRef");
form.value = {...initFormData};
tenantPackageFormRef.value.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: TenantPkgVO[]) => {
ids.value = selection.map(item => item.packageId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
// 树权限(展开/折叠)
function handleCheckedTreeExpand(value, type) {
const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
if (type == 'menu') {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
proxy.$refs.menuRef.store.nodesMap[treeList[i].id].expanded = value;
menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
}
}
// 树权限(全选/全不选)
function handleCheckedTreeNodeAll(value, type) {
const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
if (type == 'menu') {
proxy.$refs.menuRef.setCheckedNodes(value ? this.menuOptions: []);
menuTreeRef.value.setCheckedNodes(value ? menuOptions.value: []);
}
}
// 树权限(父子联动)
function handleCheckedTreeConnect(value, type) {
const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
if (type == 'menu') {
form.value.menuCheckStrictly = value ? true: false;
form.value.menuCheckStrictly = value as boolean;
}
}
/** 新增按钮操作 */
function handleAdd() {
reset();
getMenuTreeselect();
open.value = true;
title.value = "添加租户套餐";
const handleAdd = () => {
dialog.visible = true;
dialog.title = "添加租户套餐";
nextTick(() => {
reset();
getMenuTreeselect();
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
const handleUpdate = (row?: TenantPkgVO) => {
loading.value = true
reset();
const _packageId = row.packageId || ids.value
const packageMenu = getPackageMenuTreeselect(_packageId);
getTenantPackage(_packageId).then(response => {
dialog.visible = true;
dialog.title = "修改租户套餐";
nextTick(async () => {
reset();
const _packageId = row?.packageId || ids.value[0];
const packageMenu = getPackageMenuTreeselect(_packageId);
const response = await getTenantPackage(_packageId);
loading.value = false;
form.value = response.data;
open.value = true;
nextTick(() => {
packageMenu.then(res => {
let checkedKeys = res.data.checkedKeys
nextTick(async () => {
const res = await packageMenu;
let checkedKeys = res.data.checkedKeys
checkedKeys.forEach((v) => {
nextTick(() => {
proxy.$refs.menuRef.setChecked(v, true ,false);
menuTreeRef.value.setChecked(v, true ,false);
})
})
});
});
title.value = "修改租户套餐";
});
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["tenantPackageRef"].validate(valid => {
const submitForm = () => {
tenantPackageFormRef.value.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.menuIds = getMenuAllCheckedKeys();
if (form.value.packageId != null) {
form.value.menuIds = getMenuAllCheckedKeys();
updateTenantPackage(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
} else {
form.value.menuIds = getMenuAllCheckedKeys();
addTenantPackage(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
getList();
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _packageIds = row.packageId || ids.value;
proxy.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').then(function() {
loading.value = true;
return delTenantPackage(_packageIds);
}).then(() => {
loading.value = true;
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
const handleDelete = async (row?: TenantPkgVO) => {
const _packageIds = row?.packageId || ids.value;
await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
loading.value = false;
});
await delTenantPackage(_packageIds);
loading.value = true;
getList();
proxy?.$modal.msgSuccess("删除成功");
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('system/tenantPackage/export', {
const handleExport = () => {
proxy?.download('system/tenantPackage/export', {
...queryParams.value
}, `tenantPackage_${new Date().getTime()}.xlsx`)
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="套餐名称" prop="packageName">
<el-input v-model="queryParams.packageName" 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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="租户套餐id" align="center" prop="packageId" v-if="false" />
<el-table-column label="套餐名称" align="center" prop="packageName" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @click="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"> </el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改租户套餐对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="套餐名称" prop="packageName">
<el-input v-model="form.packageName" placeholder="请输入套餐名称" />
</el-form-item>
<el-form-item label="关联菜单">
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menuTreeRef"
node-key="id"
:check-strictly="!form.menuCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -1,112 +1,127 @@
<template>
<div class="app-container">
<h4 class="form-header h4">基本信息</h4>
<el-form :model="form" label-width="80px">
<el-row>
<el-col :span="8" :offset="2">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
</el-col>
<el-col :span="8" :offset="2">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
<h4 class="form-header h4">角色信息</h4>
<el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="roleRef" @selection-change="handleSelectionChange" :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)">
<el-table-column label="序号" width="55" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
<el-table-column label="角色编号" align="center" prop="roleId" />
<el-table-column label="角色名称" align="center" prop="roleName" />
<el-table-column label="权限字符" align="center" prop="roleKey" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
<el-form label-width="100px">
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</el-form>
</div>
</template>
<script setup name="AuthRole">
import { getAuthRole, updateAuthRole } from "@/api/system/user";
<script setup name="AuthRole" lang="ts">
import { RoleVO } from '@/api/system/role/types';
import { getAuthRole, updateAuthRole } from '@/api/system/user';
import { UserForm } from '@/api/system/user/types';
import { ElTable } from "element-plus";
import { ComponentInternalInstance } from 'vue';
const route = useRoute();
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const loading = ref(true);
const total = ref(0);
const pageNum = ref(1);
const pageSize = ref(10);
const roleIds = ref([]);
const roles = ref([]);
const form = ref({
const roleIds = ref<Array<string | number>>([]);
const roles = ref<RoleVO[]>([]);
const form = ref<Partial<UserForm>>({
nickName: undefined,
userName: undefined,
userName: '',
userId: undefined
});
const tableRef = ref(ElTable)
/** 单击选中行数据 */
function clickRow(row) {
proxy.$refs["roleRef"].toggleRowSelection(row);
const clickRow = (row: RoleVO) => {
tableRef.value.toggleRowSelection(row);
};
/** 多选框选中数据 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: RoleVO[]) => {
roleIds.value = selection.map(item => item.roleId);
};
/** 保存选中的数据编号 */
function getRowKey(row) {
return row.roleId;
const getRowKey = (row: RoleVO): string => {
return String(row.roleId);
};
/** 关闭按钮 */
function close() {
const close = () => {
const obj = { path: "/system/user" };
proxy.$tab.closeOpenPage(obj);
proxy?.$tab.closeOpenPage(obj);
};
/** 提交按钮 */
function submitForm() {
const submitForm = async () => {
const userId = form.value.userId;
const rIds = roleIds.value.join(",");
updateAuthRole({ userId: userId, roleIds: rIds }).then(response => {
proxy.$modal.msgSuccess("授权成功");
close();
});
await updateAuthRole({ userId: userId as string, roleIds: rIds })
proxy?.$modal.msgSuccess("授权成功");
close();
};
(() => {
const getList = async() => {
const userId = route.params && route.params.userId;
if (userId) {
loading.value = true;
getAuthRole(userId).then(response => {
form.value = response.data.user;
roles.value = response.data.roles;
total.value = roles.value.length;
nextTick(() => {
roles.value.forEach(row => {
if (row.flag) {
proxy.$refs["roleRef"].toggleRowSelection(row);
}
});
});
loading.value = false;
});
const res = await getAuthRole(userId as string);
Object.assign(form.value, res.data.user)
Object.assign(roles.value, res.data.roles)
total.value = roles.value.length;
await nextTick(() => {
roles.value.forEach(row => {
if (row?.flag) {
tableRef.value.toggleRowSelection(row);
}
});
});
loading.value = false;
}
})();
}
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<div class="panel">
<h4 class="panel-title">基本信息</h4>
<el-form :model="form" label-width="80px" :inline="true">
<el-row :gutter="10">
<el-col :span="2.5">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
</el-col>
<el-col :span="2.5">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div class="panel">
<h4 class="panel-title">角色信息</h4>
<div>
<el-table
v-loading="loading"
:row-key="getRowKey"
@row-click="clickRow"
ref="tableRef"
@selection-change="handleSelectionChange"
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
>
<el-table-column label="序号" width="55" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
<el-table-column label="角色编号" align="center" prop="roleId" />
<el-table-column label="角色名称" align="center" prop="roleName" />
<el-table-column label="权限字符" align="center" prop="roleKey" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
<div></div>
</div>
</div>
</div>
</template>

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +1,91 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<el-col :span="6" :xs="24">
<el-card class="box-card">
<template v-slot:header>
<div class="clearfix">
<span>个人信息</span>
</div>
</template>
<div>
<div class="text-center">
<userAvatar :user="state.user" />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<svg-icon icon-class="user" />用户名称
<div class="pull-right">{{ state.user.userName }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone" />手机号码
<div class="pull-right">{{ state.user.phonenumber }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="email" />用户邮箱
<div class="pull-right">{{ state.user.email }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="tree" />所属部门
<div class="pull-right" v-if="state.user.dept">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="peoples" />所属角色
<div class="pull-right">{{ state.roleGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="date" />创建日期
<div class="pull-right">{{ state.user.createTime }}</div>
</li>
</ul>
</div>
</el-card>
</el-col>
<el-col :span="18" :xs="24">
<el-card>
<template v-slot:header>
<div class="clearfix">
<span>基本资料</span>
</div>
</template>
<el-tabs v-model="activeTab">
<el-tab-pane label="基本资料" name="userinfo">
<userInfo :user="state.user" />
</el-tab-pane>
<el-tab-pane label="修改密码" name="resetPwd">
<resetPwd />
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="Profile">
import userAvatar from "./userAvatar";
import userInfo from "./userInfo";
import resetPwd from "./resetPwd";
<script setup name="Profile" lang="ts">
import userAvatar from "./userAvatar.vue";
import userInfo from "./userInfo.vue";
import resetPwd from "./resetPwd.vue";
import { getUserProfile } from "@/api/system/user";
const activeTab = ref("userinfo");
const state = reactive({
const state = ref<{ user: any; roleGroup: string; postGroup: string}>({
user: {},
roleGroup: {},
postGroup: {}
roleGroup: '',
postGroup: ''
});
function getUser() {
getUserProfile().then(response => {
state.user = response.data.user;
state.roleGroup = response.data.roleGroup;
state.postGroup = response.data.postGroup;
});
const userForm = ref({});
const getUser = async () => {
const res = await getUserProfile();
state.value.user = res.data.user;
userForm.value = { ...res.data.user }
state.value.roleGroup = res.data.roleGroup;
state.value.postGroup = res.data.postGroup;
};
getUser();
onMounted(() => {
getUser();
})
</script>
<template>
<div class="p-2">
<el-row :gutter="20">
<el-col :span="6" :xs="24">
<el-card class="box-card">
<template v-slot:header>
<div class="clearfix">
<span>个人信息</span>
</div>
</template>
<div>
<div class="text-center">
<userAvatar :user="state.user" />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<svg-icon icon-class="user" />用户名称
<div class="pull-right">{{ state.user.userName }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone" />手机号码
<div class="pull-right">{{ state.user.phonenumber }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="email" />用户邮箱
<div class="pull-right">{{ state.user.email }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="tree" />所属部门
<div class="pull-right" v-if="state.user.dept">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="peoples" />所属角色
<div class="pull-right">{{ state.roleGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="date" />创建日期
<div class="pull-right">{{ state.user.createTime }}</div>
</li>
</ul>
</div>
</el-card>
</el-col>
<el-col :span="18" :xs="24">
<el-card>
<template v-slot:header>
<div class="clearfix">
<span>基本资料</span>
</div>
</template>
<el-tabs v-model="activeTab">
<el-tab-pane label="基本资料" name="userinfo">
<userInfo :user="userForm" />
</el-tab-pane>
<el-tab-pane label="修改密码" name="resetPwd">
<resetPwd />
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
</div>
</template>

View File

@ -1,34 +1,22 @@
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { updateUserPwd } from '@/api/system/user';
import { ComponentInternalInstance } from 'vue';
import { ResetPwdForm } from '@/api/system/user/types'
import { ElForm } from 'element-plus';
<script setup>
import { updateUserPwd } from "@/api/system/user";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { proxy } = getCurrentInstance();
const user = reactive({
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
const pwdRef = ref(ElForm);
const user = ref<ResetPwdForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
const equalToPassword = (rule, value, callback) => {
if (user.newPassword !== value) {
const equalToPassword = (rule: any, value: string, callback: any) => {
if (user.value.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
@ -41,17 +29,34 @@ const rules = ref({
});
/** 提交按钮 */
function submit() {
proxy.$refs.pwdRef.validate(valid => {
const submit = () => {
pwdRef.value.validate(async (valid: boolean) => {
if (valid) {
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
proxy.$modal.msgSuccess("修改成功");
});
await updateUserPwd(user.value.oldPassword, user.value.newPassword)
proxy?.$modal.msgSuccess("修改成功");
}
});
};
/** 关闭按钮 */
function close() {
proxy.$tab.closePage();
const close = () => {
proxy?.$tab.closePage();
};
</script>
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>

View File

@ -1,150 +1,160 @@
<template>
<div class="user-info-head" @click="editCropper()">
<img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
<el-row>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<vue-cropper
ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
:outputType="options.outputType"
@realTime="realTime"
v-if="visible"
/>
</el-col>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<div class="avatar-upload-preview">
<img :src="options.previews.url" :style="options.previews.img" />
</div>
</el-col>
</el-row>
<br />
<el-row>
<el-col :lg="2" :md="2">
<el-upload
action="#"
:http-request="requestUpload"
:show-file-list="false"
:before-upload="beforeUpload"
>
<el-button>
选择
<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
</el-upload>
</el-col>
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-button icon="Plus" @click="changeScale(1)"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
</el-col>
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
<el-button type="primary" @click="uploadImg()"> </el-button>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script setup>
<script setup lang="ts">
import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";
import { uploadAvatar } from "@/api/system/user";
import useUserStore from "@/store/modules/user";
import { ComponentInternalInstance } from "vue";
interface Options {
img: string | ArrayBuffer | null // 裁剪图片的地址
autoCrop: boolean // 是否默认生成截图框
autoCropWidth: number // 默认生成截图框宽度
autoCropHeight: number // 默认生成截图框高度
fixedBox: boolean // 固定截图框大小 不允许改变
fileName: string
previews: any // 预览数据
outputType: string
visible: boolean
}
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const open = ref(false);
const visible = ref(false);
const title = ref("修改头像");
const cropper = ref<any>({});
//图片裁剪数据
const options = reactive({
img: userStore.avatar, // 裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
outputType: "png", // 默认生成截图为PNG格式
filename: '',
previews: {} //预览数据
const options = reactive<Options>({
img: userStore.avatar,
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true,
outputType: "png",
fileName: '',
previews: {},
visible: false
});
/** 编辑头像 */
function editCropper() {
const editCropper = () => {
open.value = true;
}
/** 打开弹出层结束时的回调 */
function modalOpened() {
const modalOpened = () => {
visible.value = true;
}
/** 覆盖默认上传行为 */
function requestUpload() {}
const requestUpload = (): any => {}
/** 向左旋转 */
function rotateLeft() {
proxy.$refs.cropper.rotateLeft();
const rotateLeft = () => {
cropper.value.rotateLeft();
}
/** 向右旋转 */
function rotateRight() {
proxy.$refs.cropper.rotateRight();
const rotateRight = () => {
cropper.value.rotateRight();
}
/** 图片缩放 */
function changeScale(num) {
const changeScale = (num: number) => {
num = num || 1;
proxy.$refs.cropper.changeScale(num);
cropper.value.changeScale(num);
}
/** 上传预处理 */
function beforeUpload(file) {
const beforeUpload = (file: any) => {
if (file.type.indexOf("image/") == -1) {
proxy.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
proxy?.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
} else {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
options.img = reader.result;
options.filename = file.name;
options.fileName = file.name;
};
}
}
/** 上传图片 */
function uploadImg() {
proxy.$refs.cropper.getCropBlob(data => {
const uploadImg = async () => {
cropper.value.getCropBlob(async (data: any) => {
let formData = new FormData();
formData.append("avatarfile", data, options.filename);
uploadAvatar(formData).then(response => {
open.value = false;
options.img = response.data.imgUrl;
userStore.avatar = options.img;
proxy.$modal.msgSuccess("修改成功");
visible.value = false;
});
formData.append("avatarfile", data, options.fileName);
const res = await uploadAvatar(formData);
open.value = false;
options.img = res.data.imgUrl;
userStore.avatar = options.img as string;
proxy?.$modal.msgSuccess("修改成功");
visible.value = false;
});
}
/** 实时预览 */
function realTime(data) {
const realTime = (data: any) => {
options.previews = data;
}
/** 关闭窗口 */
function closeDialog() {
const closeDialog = () => {
options.img = userStore.avatar;
options.visible = false;
}
</script>
<style lang='scss' scoped>
<template>
<div class="user-info-head" @click="editCropper()">
<img :src="options.img as string" title="点击上传头像" class="img-circle img-lg" />
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
<el-row>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<vue-cropper
ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
:outputType="options.outputType"
@realTime="realTime"
v-if="visible"
/>
</el-col>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<div class="avatar-upload-preview">
<img :src="options.previews.url" :style="options.previews.img" />
</div>
</el-col>
</el-row>
<br />
<el-row>
<el-col :lg="2" :md="2">
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
<el-button>
选择
<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
</el-upload>
</el-col>
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-button icon="Plus" @click="changeScale(1)"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
</el-col>
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
<el-button type="primary" @click="uploadImg()"> </el-button>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<style lang="scss" scoped>
.user-info-head {
position: relative;
display: inline-block;
@ -168,4 +178,4 @@ function closeDialog() {
line-height: 110px;
border-radius: 50%;
}
</style>
</style>

View File

@ -1,56 +1,63 @@
<template>
<el-form ref="userRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="user.nickName" maxlength="30" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="user.phonenumber" maxlength="11" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="user.email" maxlength="50" />
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="user.sex">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
<script setup lang="ts">
import { updateUserProfile } from "@/api/system/user";
import { FormRules } from "element-plus";
import { ComponentInternalInstance } from "vue";
import { PropType } from "vue";
import { ElForm } from "element-plus";
const props = defineProps({
user: {
type: Object
type: Object as PropType<any>,
}
});
const userForm = computed(() => props.user);
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const rules = ref({
const userRef = ref(ElForm);
const rules = ref<FormRules>({
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
});
/** 提交按钮 */
function submit() {
proxy.$refs.userRef.validate(valid => {
const submit = () => {
userRef.value.validate(async (valid: boolean) => {
if (valid) {
updateUserProfile(props.user).then(response => {
proxy.$modal.msgSuccess("修改成功");
});
await updateUserProfile(props.user)
proxy?.$modal.msgSuccess("修改成功");
}
});
};
/** 关闭按钮 */
function close() {
proxy.$tab.closePage();
const close = () => {
proxy?.$tab.closePage();
};
</script>
<template>
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="userForm.nickName" maxlength="30" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="userForm.phonenumber" maxlength="11" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="userForm.email" maxlength="50" />
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="userForm.sex">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>

View File

@ -1,3 +1,3 @@
<template>
<div> 表单构建 <svg-icon icon-class="build" /> </div>
</template>
<div>表单构建 <svg-icon icon-class="build" /></div>
</template>

View File

@ -1,43 +1,17 @@
<template>
<el-form ref="basicInfoForm" :model="info" :rules="rules" label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item label="表名称" prop="tableName">
<el-input placeholder="请输入仓库名称" v-model="info.tableName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="表描述" prop="tableComment">
<el-input placeholder="请输入" v-model="info.tableComment" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实体类名称" prop="className">
<el-input placeholder="请输入" v-model="info.className" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="作者" prop="functionAuthor">
<el-input placeholder="请输入" v-model="info.functionAuthor" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="info.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
import { PropType } from 'vue';
<script setup>
defineProps({
const prop = defineProps({
info: {
type: Object,
default: null
type: Object as PropType<any>,
default: () => {
return {};
}
}
});
const infoForm = computed(() => prop.info)
// 表单校验
const rules = ref({
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
@ -46,3 +20,35 @@ const rules = ref({
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
});
</script>
<template>
<el-form ref="basicInfoForm" :model="infoForm" :rules="rules" label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item label="表名称" prop="tableName">
<el-input placeholder="请输入仓库名称" v-model="infoForm.tableName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="表描述" prop="tableComment">
<el-input placeholder="请输入" v-model="infoForm.tableComment" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实体类名称" prop="className">
<el-input placeholder="请输入" v-model="infoForm.className" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="作者" prop="functionAuthor">
<el-input placeholder="请输入" v-model="infoForm.functionAuthor" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="infoForm.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>

View File

@ -1,198 +1,189 @@
<template>
<el-card>
<el-tabs v-model="activeName">
<el-tab-pane label="基本信息" name="basic">
<basic-info-form ref="basicInfo" :info="info" />
</el-tab-pane>
<el-tab-pane label="字段信息" name="columnInfo">
<el-table ref="dragTable" :data="columns" row-key="columnId" :max-height="tableHeight">
<el-table-column label="序号" type="index" min-width="5%"/>
<el-table-column
label="字段列名"
prop="columnName"
min-width="10%"
:show-overflow-tooltip="true"
/>
<el-table-column label="字段描述" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.columnComment"></el-input>
</template>
</el-table-column>
<el-table-column
label="物理类型"
prop="columnType"
min-width="10%"
:show-overflow-tooltip="true"
/>
<el-table-column label="Java类型" min-width="11%">
<template #default="scope">
<el-select v-model="scope.row.javaType">
<el-option label="Long" value="Long" />
<el-option label="String" value="String" />
<el-option label="Integer" value="Integer" />
<el-option label="Double" value="Double" />
<el-option label="BigDecimal" value="BigDecimal" />
<el-option label="Date" value="Date" />
<el-option label="Boolean" value="Boolean" />
</el-select>
</template>
</el-table-column>
<el-table-column label="java属性" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.javaField"></el-input>
</template>
</el-table-column>
<el-table-column label="插入" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="编辑" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="列表" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="查询" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="查询方式" min-width="10%">
<template #default="scope">
<el-select v-model="scope.row.queryType">
<el-option label="=" value="EQ" />
<el-option label="!=" value="NE" />
<el-option label=">" value="GT" />
<el-option label=">=" value="GE" />
<el-option label="<" value="LT" />
<el-option label="<=" value="LE" />
<el-option label="LIKE" value="LIKE" />
<el-option label="BETWEEN" value="BETWEEN" />
</el-select>
</template>
</el-table-column>
<el-table-column label="必填" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="显示类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.htmlType">
<el-option label="文本框" value="input" />
<el-option label="文本域" value="textarea" />
<el-option label="下拉框" value="select" />
<el-option label="单选框" value="radio" />
<el-option label="复选框" value="checkbox" />
<el-option label="日期控件" value="datetime" />
<el-option label="图片上传" value="imageUpload" />
<el-option label="文件上传" value="fileUpload" />
<el-option label="富文本控件" value="editor" />
</el-select>
</template>
</el-table-column>
<el-table-column label="字典类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
<el-option
v-for="dict in dictOptions"
:key="dict.dictType"
:label="dict.dictName"
:value="dict.dictType">
<span style="float: left">{{ dict.dictName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
</el-option>
</el-select>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="生成信息" name="genInfo">
<gen-info-form ref="genInfo" :info="info" :tables="tables" />
</el-tab-pane>
</el-tabs>
<el-form label-width="100px">
<div style="text-align: center;margin-left:-100px;margin-top:10px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</el-form>
</el-card>
</template>
<script setup name="GenEdit">
import { getGenTable, updateGenTable } from "@/api/tool/gen";
import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
import basicInfoForm from "./basicInfoForm";
import genInfoForm from "./genInfoForm";
<script setup name="GenEdit" lang="ts">
import { getGenTable, updateGenTable } from '@/api/tool/gen';
import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
import { DictTypeVO } from '@/api/system/dict/type/types';
import basicInfoForm from './basicInfoForm.vue';
import genInfoForm from "./genInfoForm.vue";
import { ComponentInternalInstance } from "vue";
const route = useRoute();
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const activeName = ref("columnInfo");
const tableHeight = ref(document.documentElement.scrollHeight - 245 + "px");
const tables = ref([]);
const columns = ref([]);
const dictOptions = ref([]);
const info = ref({});
const activeName = ref('columnInfo');
const tableHeight = ref(document.documentElement.scrollHeight - 245 + 'px');
const tables = ref<DbTableVO[]>([]);
const columns = ref<DbColumnVO[]>([]);
const dictOptions = ref<DictTypeVO[]>([]);
const info = ref<Partial<DbTableVO>>({});
const basicInfo = ref(basicInfoForm);
const genInfo = ref(genInfoForm);
/** 提交按钮 */
function submitForm() {
const basicForm = proxy.$refs.basicInfo.$refs.basicInfoForm;
const genForm = proxy.$refs.genInfo.$refs.genInfoForm;
Promise.all([basicForm, genForm].map(getFormPromise)).then(res => {
const submitForm = () => {
const basicForm = basicInfo.value.$refs.basicInfoForm;
const genForm = genInfo.value.$refs.genInfoForm;
Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
const validateResult = res.every(item => !!item);
if (validateResult) {
const genTable = Object.assign({}, info.value);
const genTable: any = Object.assign({}, info.value);
genTable.columns = columns.value;
genTable.params = {
treeCode: info.value.treeCode,
treeCode: info.value?.treeCode,
treeName: info.value.treeName,
treeParentCode: info.value.treeParentCode,
parentMenuId: info.value.parentMenuId
};
updateGenTable(genTable).then(res => {
proxy.$modal.msgSuccess(res.msg);
if (res.code === 200) {
close();
}
});
};
console.log(genTable)
const response = await updateGenTable(genTable);
proxy?.$modal.msgSuccess(response.msg);
if (response.code === 200) {
close();
}
} else {
proxy.$modal.msgError("表单校验未通过,请重新检查提交内容");
proxy?.$modal.msgError("表单校验未通过,请重新检查提交内容");
}
});
}
function getFormPromise(form) {
const getFormPromise = (form: any) => {
return new Promise(resolve => {
form.validate(res => {
form.validate((res: any) => {
resolve(res);
});
});
}
function close() {
const close = () => {
const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: route.query.pageNum } };
proxy.$tab.closeOpenPage(obj);
proxy?.$tab.closeOpenPage(obj);
}
(() => {
const tableId = route.params && route.params.tableId;
(async () => {
const tableId = route.params && route.params.tableId as string;
if (tableId) {
// 获取表详细信息
getGenTable(tableId).then(res => {
columns.value = res.data.rows;
info.value = res.data.info;
tables.value = res.data.tables;
});
const res = await getGenTable(tableId);
columns.value = res.data.rows;
info.value = res.data.info;
tables.value = res.data.tables;
/** 查询字典下拉列表 */
getDictOptionselect().then(response => {
dictOptions.value = response.data;
});
const response = await getDictOptionselect();
dictOptions.value = response.data;
}
})();
</script>
<template>
<el-card>
<el-tabs v-model="activeName">
<el-tab-pane label="基本信息" name="basic">
<basic-info-form ref="basicInfo" :info="info" />
</el-tab-pane>
<el-tab-pane label="字段信息" name="columnInfo">
<el-table ref="dragTable" :data="columns" row-key="columnId" :max-height="tableHeight">
<el-table-column label="序号" type="index" min-width="5%" />
<el-table-column label="字段列名" prop="columnName" min-width="10%" :show-overflow-tooltip="true" />
<el-table-column label="字段描述" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.columnComment"></el-input>
</template>
</el-table-column>
<el-table-column label="物理类型" prop="columnType" min-width="10%" :show-overflow-tooltip="true" />
<el-table-column label="Java类型" min-width="11%">
<template #default="scope">
<el-select v-model="scope.row.javaType">
<el-option label="Long" value="Long" />
<el-option label="String" value="String" />
<el-option label="Integer" value="Integer" />
<el-option label="Double" value="Double" />
<el-option label="BigDecimal" value="BigDecimal" />
<el-option label="Date" value="Date" />
<el-option label="Boolean" value="Boolean" />
</el-select>
</template>
</el-table-column>
<el-table-column label="java属性" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.javaField"></el-input>
</template>
</el-table-column>
<el-table-column label="插入" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="编辑" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="列表" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="查询" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="查询方式" min-width="10%">
<template #default="scope">
<el-select v-model="scope.row.queryType">
<el-option label="=" value="EQ" />
<el-option label="!=" value="NE" />
<el-option label=">" value="GT" />
<el-option label=">=" value="GE" />
<el-option label="<" value="LT" />
<el-option label="<=" value="LE" />
<el-option label="LIKE" value="LIKE" />
<el-option label="BETWEEN" value="BETWEEN" />
</el-select>
</template>
</el-table-column>
<el-table-column label="必填" min-width="5%">
<template #default="scope">
<el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="显示类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.htmlType">
<el-option label="文本框" value="input" />
<el-option label="文本域" value="textarea" />
<el-option label="下拉框" value="select" />
<el-option label="单选框" value="radio" />
<el-option label="复选框" value="checkbox" />
<el-option label="日期控件" value="datetime" />
<el-option label="图片上传" value="imageUpload" />
<el-option label="文件上传" value="fileUpload" />
<el-option label="富文本控件" value="editor" />
</el-select>
</template>
</el-table-column>
<el-table-column label="字典类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
<el-option v-for="dict in dictOptions" :key="dict.dictType" :label="dict.dictName" :value="dict.dictType">
<span style="float: left">{{ dict.dictName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
</el-option>
</el-select>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="生成信息" name="genInfo">
<gen-info-form ref="genInfo" :info="info" :tables="tables" />
</el-tab-pane>
</el-tabs>
<el-form label-width="100px">
<div style="text-align: center;margin-left:-100px;margin-top:10px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</el-form>
</el-card>
</template>

View File

@ -1,244 +1,32 @@
<template>
<el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item prop="tplCategory">
<template #label>生成模板</template>
<el-select v-model="info.tplCategory" @change="tplSelectChange">
<el-option label="单表(增删改查)" value="crud" />
<el-option label="树表(增删改查)" value="tree" />
</el-select>
</el-form-item>
</el-col>
<script setup lang="ts">
import { listMenu } from '@/api/system/menu';
import { ComponentInternalInstance, PropType } from 'vue';
<el-col :span="12">
<el-form-item prop="packageName">
<template #label>
生成包路径
<el-tooltip content="生成在哪个java包下例如 com.ruoyi.system" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="info.packageName" />
</el-form-item>
</el-col>
interface MenuOptionsType {
menuId: number;
menuName: string;
children: MenuOptionsType[] | undefined;
}
<el-col :span="12">
<el-form-item prop="moduleName">
<template #label>
生成模块名
<el-tooltip content="可理解为子系统名,例如 system" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="info.moduleName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="businessName">
<template #label>
生成业务名
<el-tooltip content="可理解为功能英文名,例如 user" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="info.businessName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="functionName">
<template #label>
生成功能名
<el-tooltip content="用作类描述,例如 用户" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="info.functionName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
上级菜单
<el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<tree-select
v-model:value="info.parentMenuId"
:options="menuOptions"
:objMap="{ value: 'menuId', label: 'menuName', children: 'children' }"
placeholder="请选择系统菜单"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="genType">
<template #label>
生成代码方式
<el-tooltip content="默认为zip压缩包下载也可以自定义生成路径" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
<el-radio v-model="info.genType" label="1">自定义路径</el-radio>
</el-form-item>
</el-col>
<el-col :span="24" v-if="info.genType == '1'">
<el-form-item prop="genPath">
<template #label>
自定义路径
<el-tooltip content="填写磁盘绝对路径若不填写则生成到当前Web项目下" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="info.genPath">
<template #append>
<el-dropdown>
<el-button type="primary">
最近路径快速选择
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<template v-if="info.tplCategory == 'tree'">
<h4 class="form-header">其他信息</h4>
<el-row v-show="info.tplCategory == 'tree'">
<el-col :span="12">
<el-form-item>
<template #label>
树编码字段
<el-tooltip content="树显示的编码字段名, 如dept_id" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="info.treeCode" placeholder="请选择">
<el-option
v-for="(column, index) in info.columns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
树父编码字段
<el-tooltip content="树显示的父编码字段名, 如parent_Id" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="info.treeParentCode" placeholder="请选择">
<el-option
v-for="(column, index) in info.columns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
树名称字段
<el-tooltip content="树节点的显示名称字段名, 如dept_name" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="info.treeName" placeholder="请选择">
<el-option
v-for="(column, index) in info.columns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</template>
<template v-if="info.tplCategory == 'sub'">
<h4 class="form-header">关联信息</h4>
<el-row>
<el-col :span="12">
<el-form-item>
<template #label>
关联子表的表名
<el-tooltip content="关联子表的表名, 如sys_user" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange">
<el-option
v-for="(table, index) in tables"
:key="index"
:label="table.tableName + '' + table.tableComment"
:value="table.tableName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
子表关联的外键名
<el-tooltip content="子表关联的外键名, 如user_id" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="info.subTableFkName" placeholder="请选择">
<el-option
v-for="(column, index) in subColumns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
</template>
<script setup>
import { listMenu } from "@/api/system/menu";
const subColumns = ref([]);
const menuOptions = ref([]);
const { proxy } = getCurrentInstance();
const subColumns = ref<any>([]);
const menuOptions = ref<Array<MenuOptionsType>>([]);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps({
info: {
type: Object,
type: Object as PropType<any>,
default: null
},
tables: {
type: Array,
type: Array as PropType<any[]>,
default: null
}
});
const infoForm = computed(() => props.info);
const table = computed(() => props.tables);
// 表单校验
const rules = ref({
tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
@ -247,34 +35,255 @@ const rules = ref({
businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
});
function subSelectChange(value) {
props.info.subTableFkName = "";
const subSelectChange = () => {
infoForm.value.subTableFkName = "";
}
function tplSelectChange(value) {
const tplSelectChange = (value: string) => {
if (value !== "sub") {
props.info.subTableName = "";
props.info.subTableFkName = "";
infoForm.value.subTableName = "";
infoForm.value.subTableFkName = "";
}
}
function setSubTableColumns(value) {
for (var item in props.tables) {
const name = props.tables[item].tableName;
if (value === name) {
subColumns.value = props.tables[item].columns;
break;
const setSubTableColumns = (value: string) => {
table.value.forEach(item => {
const name = item.tableName;
if (value === name) {
subColumns.value = item.columns;
return;
}
}
})
}
/** 查询菜单下拉树结构 */
function getMenuTreeselect() {
listMenu().then(response => {
menuOptions.value = proxy.handleTree(response.data, "menuId");
});
const getMenuTreeselect = async () => {
const res = await listMenu();
const data = proxy?.handleTree<MenuOptionsType>(res.data, "menuId");
if (data) {
menuOptions.value = data
}
}
watch(() => props.info.subTableName, val => {
setSubTableColumns(val);
});
getMenuTreeselect();
onMounted(() => {
getMenuTreeselect();
})
</script>
<template>
<el-form ref="genInfoForm" :model="infoForm" :rules="rules" label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item prop="tplCategory">
<template #label>生成模板</template>
<el-select v-model="infoForm.tplCategory" @change="tplSelectChange">
<el-option label="单表(增删改查)" value="crud" />
<el-option label="树表(增删改查)" value="tree" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="packageName">
<template #label>
生成包路径
<el-tooltip content="生成在哪个java包下例如 com.ruoyi.system" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="infoForm.packageName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="moduleName">
<template #label>
生成模块名
<el-tooltip content="可理解为子系统名,例如 system" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="infoForm.moduleName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="businessName">
<template #label>
生成业务名
<el-tooltip content="可理解为功能英文名,例如 user" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="infoForm.businessName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="functionName">
<template #label>
生成功能名
<el-tooltip content="用作类描述,例如 用户" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="infoForm.functionName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
上级菜单
<el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<tree-select
v-model:value="infoForm.parentMenuId"
:options="menuOptions"
:objMap="{ value: 'menuId', label: 'menuName', children: 'children' }"
placeholder="请选择系统菜单"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="genType">
<template #label>
生成代码方式
<el-tooltip content="默认为zip压缩包下载也可以自定义生成路径" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-radio v-model="infoForm.genType" label="0">zip压缩包</el-radio>
<el-radio v-model="infoForm.genType" label="1">自定义路径</el-radio>
</el-form-item>
</el-col>
<el-col :span="24" v-if="infoForm.genType == '1'">
<el-form-item prop="genPath">
<template #label>
自定义路径
<el-tooltip content="填写磁盘绝对路径若不填写则生成到当前Web项目下" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-input v-model="infoForm.genPath">
<template #append>
<el-dropdown>
<el-button type="primary">
最近路径快速选择
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="infoForm.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<template v-if="info.tplCategory == 'tree'">
<h4 class="form-header">其他信息</h4>
<el-row v-show="info.tplCategory == 'tree'">
<el-col :span="12">
<el-form-item>
<template #label>
树编码字段
<el-tooltip content="树显示的编码字段名, 如dept_id" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="infoForm.treeCode" placeholder="请选择">
<el-option
v-for="(column, index) in info.columns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
树父编码字段
<el-tooltip content="树显示的父编码字段名, 如parent_Id" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="infoForm.treeParentCode" placeholder="请选择">
<el-option
v-for="(column, index) in infoForm.columns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
树名称字段
<el-tooltip content="树节点的显示名称字段名, 如dept_name" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="infoForm.treeName" placeholder="请选择">
<el-option
v-for="(column, index) in info.columns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</template>
<template v-if="info.tplCategory == 'sub'">
<h4 class="form-header">关联信息</h4>
<el-row>
<el-col :span="12">
<el-form-item>
<template #label>
关联子表的表名
<el-tooltip content="关联子表的表名, 如sys_user" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="infoForm.subTableName" placeholder="请选择" @change="subSelectChange">
<el-option v-for="(t, index) in table" :key="index" :label="t.tableName + '' + t.tableComment" :value="t.tableName"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
子表关联的外键名
<el-tooltip content="子表关联的外键名, 如user_id" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
</template>
<el-select v-model="infoForm.subTableFkName" placeholder="请选择">
<el-option
v-for="(column, index) in subColumns"
:key="index"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
</template>

View File

@ -1,118 +1,106 @@
<template>
<!-- 导入表 -->
<el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input
v-model="queryParams.tableComment"
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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row>
<el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleImportTable"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { listDbTable, importTable } from "@/api/tool/gen";
<script setup lang="ts">
import { listDbTable, importTable } from '@/api/tool/gen';
import { DbTableQuery, DbTableVO } from '@/api/tool/gen/types';
import { ComponentInternalInstance } from 'vue';
import { ElTable, ElForm } from 'element-plus';
const total = ref(0);
const visible = ref(false);
const tables = ref([]);
const dbTableList = ref([]);
const { proxy } = getCurrentInstance();
const tables = ref<Array<string>>([]);
const dbTableList = ref<Array<DbTableVO>>([]);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const queryParams = reactive({
const tableRef = ref(ElTable);
const queryFormRef = ref(ElForm);
const queryParams = reactive<DbTableQuery>({
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
tableName: '',
tableComment: ''
});
const emit = defineEmits(["ok"]);
/** 查询参数列表 */
function show() {
const show = () => {
getList();
visible.value = true;
}
/** 单击选择行 */
function clickRow(row) {
proxy.$refs.table.toggleRowSelection(row);
const clickRow = (row: DbTableVO) => {
tableRef.value.toggleRowSelection(row);
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
const handleSelectionChange = (selection: DbTableVO[]) => {
tables.value = selection.map(item => item.tableName);
}
/** 查询表数据 */
function getList() {
listDbTable(queryParams).then(res => {
dbTableList.value = res.rows;
total.value = res.total;
});
const getList = async () => {
const res = await listDbTable(queryParams);
dbTableList.value = res.rows;
total.value = res.total;
}
/** 搜索按钮操作 */
function handleQuery() {
const handleQuery = () => {
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
const resetQuery = () => {
queryFormRef.value.resetFields();
handleQuery();
}
/** 导入按钮操作 */
function handleImportTable() {
const handleImportTable = async () => {
const tableNames = tables.value.join(",");
if (tableNames == "") {
proxy.$modal.msgError("请选择要导入的表");
proxy?.$modal.msgError("请选择要导入的表");
return;
}
importTable({ tables: tableNames }).then(res => {
proxy.$modal.msgSuccess(res.msg);
if (res.code === 200) {
visible.value = false;
emit("ok");
}
});
const res = await importTable({ tables: tableNames });
proxy?.$modal.msgSuccess(res.msg);
if (res.code === 200) {
visible.value = false;
emit("ok");
}
}
defineExpose({
show,
});
</script>
<template>
<!-- 导入表 -->
<el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="表名称" prop="tableName">
<el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input v-model="queryParams.tableComment" 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="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row>
<el-table @row-click="clickRow" ref="tableRef" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleImportTable"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</template>
</el-dialog>
</template>

View File

@ -1,296 +1,244 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="数据源" prop="dataName">
<el-input
v-model="queryParams.dataName"
placeholder="请输入数据源名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input
v-model="queryParams.tableComment"
placeholder="请输入表描述"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Download"
@click="handleGenTable"
v-hasPermi="['tool:gen:code']"
>生成</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Upload"
@click="openImportTable"
v-hasPermi="['tool:gen:import']"
>导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleEditTable"
v-hasPermi="['tool:gen:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['tool:gen:remove']"
>删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
<el-table-column type="selection" align="center" width="55"></el-table-column>
<el-table-column label="序号" type="index" width="50" align="center">
<template #default="scope">
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
<el-table-column
label="表名称"
align="center"
prop="tableName"
:show-overflow-tooltip="true"
/>
<el-table-column
label="表描述"
align="center"
prop="tableComment"
:show-overflow-tooltip="true"
/>
<el-table-column
label="实体"
align="center"
prop="className"
:show-overflow-tooltip="true"
/>
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" />
<el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="预览" placement="top">
<el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
</el-tooltip>
<el-tooltip content="编辑" placement="top">
<el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
</el-tooltip>
<el-tooltip content="同步" placement="top">
<el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip>
<el-tooltip content="生成代码" placement="top">
<el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 预览界面 -->
<el-dialog :title="preview.title" v-model="preview.open" width="80%" top="5vh" append-to-body class="scrollbar">
<el-tabs v-model="preview.activeName">
<el-tab-pane
v-for="(value, key) in preview.data"
:label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
:key="value"
>
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">&nbsp;复制</el-link>
<pre>{{ value }}</pre>
</el-tab-pane>
</el-tabs>
</el-dialog>
<import-table ref="importRef" @ok="handleQuery" />
</div>
</template>
<script setup name="Gen">
import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
import router from "@/router";
import importTable from "./importTable";
<script setup name="Gen" lang="ts">
import { listTable, previewTable, delTable, genCode, synchDb } from '@/api/tool/gen';
import { TableQuery, TableVO } from '@/api/tool/gen/types';
import router from '@/router';
import importTable from './importTable.vue';
import { ComponentInternalInstance } from 'vue';
import { ElForm, DateModelType } from 'element-plus';
const route = useRoute();
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const tableList = ref([]);
const tableList = ref<TableVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const tableNames = ref([]);
const dateRange = ref([]);
const tableNames = ref<Array<string>>([]);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const uniqueId = ref("");
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined,
dataName: "master"
},
preview: {
open: false,
title: "代码预览",
data: {},
activeName: "domain.java"
}
const queryFormRef = ref(ElForm);
const importRef = ref(importTable);
const queryParams = ref<TableQuery>({
pageNum: 1,
pageSize: 10,
tableName: '',
tableComment: '',
dataName: "master"
})
const preview = ref <any>({
data: {},
activeName: 'domain.java'
})
const dialog = reactive<DialogOption>({
visible: false,
title: '代码预览'
});
const { queryParams, preview } = toRefs(data);
localStorage.setItem("dataName", queryParams.value.dataName);
localStorage.setItem('dataName', queryParams.value.dataName);
onActivated(() => {
const time = route.query.t;
if (time != null && time != uniqueId.value) {
uniqueId.value = time;
queryParams.value.pageNum = Number(route.query.pageNum);
dateRange.value = [];
proxy.resetForm("queryForm");
getList();
}
const time = route.query.t;
if (time != null && time != uniqueId.value) {
uniqueId.value = time as string;
queryParams.value.pageNum = Number(route.query.pageNum);
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
getList();
}
})
/** 查询表集合 */
function getList() {
loading.value = true;
listTable(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
tableList.value = response.rows;
total.value = response.total;
loading.value = false;
});
const getList = async () => {
loading.value = true;
const res = await listTable(proxy?.addDateRange(queryParams.value, dateRange.value));
tableList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 搜索按钮操作 */
function handleQuery() {
localStorage.setItem("dataName", queryParams.value.dataName);
queryParams.value.pageNum = 1;
getList();
const handleQuery = () => {
localStorage.setItem('dataName', queryParams.value.dataName);
queryParams.value.pageNum = 1;
getList();
}
/** 生成代码操作 */
function handleGenTable(row) {
const tbNames = row.tableName || tableNames.value;
if (tbNames == "") {
proxy.$modal.msgError("请选择要生成的数据");
return;
}
if (row.genType === "1") {
genCode(row.tableName).then(response => {
proxy.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath);
});
} else {
proxy.$download.zip("/tool/gen/batchGenCode?tables=" + tbNames, "ruoyi.zip");
}
const handleGenTable = async (row?: TableVO) => {
const tbNames = row?.tableName || tableNames.value;
if (tbNames == "") {
proxy?.$modal.msgError('请选择要生成的数据');
return;
}
if (row?.genType === "1") {
await genCode(row.tableName);
proxy?.$modal.msgSuccess('成功生成到自定义路径:' + row.genPath);
} else {
proxy?.$download.zip('/tool/gen/batchGenCode?tables=' + tbNames, 'ruoyi.zip');
}
}
/** 同步数据库操作 */
function handleSynchDb(row) {
const tableName = row.tableName;
proxy.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function () {
return synchDb(tableName);
}).then(() => {
proxy.$modal.msgSuccess("同步成功");
}).catch(() => {});
const handleSynchDb = async (row: TableVO) => {
const tableName = row.tableName;
await proxy?.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?');
await synchDb(tableName);
proxy?.$modal.msgSuccess('同步成功');
}
/** 打开导入表弹窗 */
function openImportTable() {
proxy.$refs["importRef"].show();
const openImportTable = () => {
importRef.value.show();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
const resetQuery = () => {
dateRange.value = ['', ''];
queryFormRef.value.resetFields();
handleQuery();
}
/** 预览按钮 */
function handlePreview(row) {
previewTable(row.tableId).then(response => {
preview.value.data = response.data;
preview.value.open = true;
preview.value.activeName = "domain.java";
});
const handlePreview = async (row: TableVO) => {
const res = await previewTable(row.tableId);
preview.value.data = res.data;
dialog.visible = true;
preview.value.activeName = 'domain.java';
}
/** 复制代码成功 */
function copyTextSuccess() {
proxy.$modal.msgSuccess("复制成功");
const copyTextSuccess = () => {
proxy?.$modal.msgSuccess('复制成功');
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.tableId);
tableNames.value = selection.map(item => item.tableName);
single.value = selection.length != 1;
multiple.value = !selection.length;
const handleSelectionChange = (selection: TableVO[]) => {
ids.value = selection.map(item => item.tableId);
tableNames.value = selection.map(item => item.tableName);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleEditTable(row) {
const tableId = row.tableId || ids.value[0];
router.push({ path: "/tool/gen-edit/index/" + tableId, query: { pageNum: queryParams.value.pageNum } });
const handleEditTable = (row?: TableVO) => {
const tableId = row?.tableId || ids.value[0];
router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: queryParams.value.pageNum } });
}
/** 删除按钮操作 */
function handleDelete(row) {
const tableIds = row.tableId || ids.value;
proxy.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?').then(function () {
return delTable(tableIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
const handleDelete = async (row?: TableVO) => {
const tableIds = row?.tableId || ids.value;
await proxy?.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?');
await delTable(tableIds);
getList();
proxy?.$modal.msgSuccess('删除成功');
}
getList();
onMounted(() => {
getList();
})
</script>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="数据源" prop="dataName">
<el-input v-model="queryParams.dataName" placeholder="请输入数据源名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Download" @click="handleGenTable()" v-hasPermi="['tool:gen:code']">生成</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Upload" @click="openImportTable" v-hasPermi="['tool:gen:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()" v-hasPermi="['tool:gen:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['tool:gen:remove']">
删除
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
<el-table-column type="selection" align="center" width="55"></el-table-column>
<el-table-column label="序号" type="index" width="50" align="center">
<template #default="scope">
<span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" />
<el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" />
<el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" />
<el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="预览" placement="top">
<el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
</el-tooltip>
<el-tooltip content="编辑" placement="top">
<el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
</el-tooltip>
<el-tooltip content="同步" placement="top">
<el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip>
<el-tooltip content="生成代码" placement="top">
<el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 预览界面 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" top="5vh" append-to-body class="scrollbar">
<el-tabs v-model="preview.activeName">
<el-tab-pane
v-for="(value, key) in preview.data"
:label="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
:name="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
:key="value"
>
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"
>&nbsp;复制</el-link
>
<pre>{{ value }}</pre>
</el-tab-pane>
</el-tabs>
</el-dialog>
<import-table ref="importRef" @ok="handleQuery" />
</div>
</template>