完成验证码及登录功能

This commit is contained in:
橙子
2023-02-04 18:06:42 +08:00
parent cfd25b0a8d
commit b01d242cbc
276 changed files with 24201 additions and 22 deletions

View File

@@ -0,0 +1,402 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="100px"
>
<el-form-item label="物料名称" prop="name" >
<el-input
v-model="queryParams.name"
placeholder="请输入物料名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="物料编号" prop="code" >
<el-input
v-model="queryParams.code"
placeholder="请输入物料编号"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="code"
/>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['erp:material:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['erp:material:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['erp:material:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['erp:material:export']"
>导出</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="code" />
<el-table-column label="物料名称" align="center" prop="name" :show-overflow-tooltip="true"/>
<el-table-column label="单位" align="center" prop="unitName" :show-overflow-tooltip="true">
<template #default="scope">
<el-tag>{{ scope.row.unitName }}</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['business:article:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['business:article: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="600px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="物料编码" prop="code">
<el-input v-model="form.code" placeholder="请输入物料编码" />
</el-form-item>
<el-form-item label="物料名称" prop="name">
<el-input v-model="form.name" placeholder="请输入物料名称" />
</el-form-item>
<el-form-item label="物料单位" prop="unitName">
<el-select v-model="form.unitName" filterable placeholder="请选择单位">
<el-option
v-for="item in unitList"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item> -->
<el-form-item label="备注" prop="remarks">
<el-input
v-model="form.remarks"
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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/erp/materialApi";
import {
allData as allUnitData,
} from "@/api/erp/unitApi";
import { ref } from "@vue/reactivity";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const unitList=ref([]);
const dataList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined
},
rules: {
code: [{ required: true, message: "物料编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "物料名称不能为空", trigger: "blur" }],
unitName: [{ required: true, message: "物料单位不能为空", trigger: "blur" }]
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/**查询全部单位列表*/
function getUnitList() {
allUnitData().then(
(response) => {
unitList.value = response.data;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
isDeleted: false,
remark: undefined,
};
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
const queryRef=ref(null);
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加物料";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改物料";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id,form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
getList();
getUnitList();
</script>

View File

@@ -0,0 +1,775 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="90px"
>
<el-form-item label="供应商名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入供应商名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="采购单编号" prop="code">
<el-input
v-model="queryParams.code"
placeholder="请输入采购单编号"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="code"
/>
</el-form-item>
<el-form-item label="采购员" prop="buyer">
<el-input
v-model="queryParams.code"
placeholder="请输入采购员"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="buyer"
/>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['erp:purchase:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['erp:purchase:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['erp:purchase:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['erp:purchase:export']"
>导出</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="code" />
<el-table-column
label="供应商"
align="center"
prop="supplierName"
:show-overflow-tooltip="true"
/>
<el-table-column
label="需求时间"
align="center"
prop="needTime"
:show-overflow-tooltip="true"
/>
<el-table-column
label="采购员"
align="center"
prop="buyer"
:show-overflow-tooltip="true"
/>
<el-table-column
label="总共金额"
align="center"
prop="totalMoney"
:show-overflow-tooltip="true"
/>
<el-table-column
label="已支付金额"
align="center"
prop="paidMoney"
:show-overflow-tooltip="true"
/>
<el-table-column
label="采购状态"
align="center"
prop="purchaseState"
:show-overflow-tooltip="true"
>
<template #default="scope">
<el-tag>{{purchaseStateComputed(scope.row.purchaseState)}}</el-tag>
</template>
</el-table-column>
<el-table-column
label="备注"
align="center"
prop="remarks"
:show-overflow-tooltip="true"
/>
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleGet(scope.row)"
v-hasPermi="['erp:purchase:edit']"
>查看</el-button
>
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['erp:purchase:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['erp:purchase:remove']"
>结束</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['erp:purchase: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="1200px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="采购单编码" prop="code">
<el-input v-model="form.code" placeholder="请输入采购单编码" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="供应商" prop="supplierName">
<el-select
v-model="form.supplierId"
filterable
placeholder="请选择供应商"
>
<el-option
v-for="item in supplierList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购单员" prop="buyer">
<el-input v-model="form.buyer" placeholder="请输入采购单员" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="需求时间" prop="needTime">
<el-date-picker
v-model="form.needTime"
type="date"
placeholder="选择一个日期"
size="default"
/>
</el-form-item>
</el-col>
<el-col :offset="8" :span="8">
<el-form-item label="总金额">
{{ showTotalMoney }}
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="物料信息">
<el-table :data="form.purchaseDetails" border style="width: 100%">
<el-table-column width="90">
<template #default="scope">
<el-button
@click="delMaterialRow(scope.$index)"
icon="Delete"
type="danger"
size="small"
>删除</el-button
>
</template>
</el-table-column>
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="materialName" label="物料" width="180" />
<el-table-column prop="materialUnit" label="单位" width="180" />
<el-table-column prop="unitPrice" label="单价" width="180">
<template #default="scope">
<el-input v-model="scope.row.unitPrice" />
</template>
</el-table-column>
<el-table-column
prop="totalNumber"
label="采购数量"
width="180"
>
<template #default="scope">
<el-input v-model="scope.row.totalNumber" />
</template>
</el-table-column>
<el-table-column prop="remarks" label="备注">
<template #default="scope">
<el-input v-model="scope.row.remarks" />
</template>
</el-table-column>
</el-table>
<el-button
class="form-add-btn"
type="primary"
icon="CirclePlus"
plain
@click="materialHandleAdd"
>添加物料</el-button
>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remarks">
<el-input
v-model="form.remarks"
type="textarea"
placeholder="请输入内容"
:rows="5"
></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="添加物料"
v-model="openMaterial"
width="800px"
append-to-body
>
<el-form
:model="queryMaterialParams"
ref="queryMaterialRef"
:inline="true"
label-width="70px"
>
<el-form-item label="物料名称" prop="name">
<el-input
v-model="queryMaterialParams.name"
placeholder="请输入物料名称"
clearable
style="width: 150px"
@keyup.enter="handleMaterialQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="物料编码" prop="code">
<el-input
v-model="queryMaterialParams.code"
placeholder="请输入物料编码"
clearable
style="width: 150px"
@keyup.enter="handleMaterialQuery"
prop="code"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleMaterialQuery"
>搜索</el-button
>
<el-button icon="Refresh" @click="resetMaterialQuery">重置</el-button>
</el-form-item>
<!-- 物料表单 -->
<el-table
style="width: 100%"
:data="materialList"
@selection-change="materialHandleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column property="code" label="物料编码" />
<el-table-column property="name" label="物料信息" />
<el-table-column property="unitName" label="物料单位" />
</el-table>
<pagination
v-show="materialTotal > 0"
:total="materialTotal"
v-model:page="queryMaterialParams.pageNum"
v-model:limit="queryMaterialParams.pageSize"
@pagination="getMaterialList"
/>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitMaterialForm"
> </el-button
>
<el-button @click="materialCancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- ---------------------这里是采购订单详情对话框--------------------- -->
<el-dialog
title="订单详情"
v-model="openDetails"
width="1200px"
append-to-body
>
<el-form
ref="dataDetailsRef"
:model="form"
:rules="rules"
label-width="100px"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="物料" prop="code">
<el-input placeholder="请输入物料" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item>
<el-button type="primary" icon="Search"
>查询</el-button
>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="物料信息">
<el-table :data="form.purchaseDetails" border style="width: 100%" >
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="materialName" label="物料" width="180" align="center" />
<el-table-column prop="materialUnit" label="单位" width="180" align="center" />
<el-table-column prop="unitPrice" label="单价" width="180" align="center">
</el-table-column>
<el-table-column
prop="totalNumber"
label="采购数量"
width="180"
align="center"
>
</el-table-column>
<el-table-column prop="remarks" label="备注" >
</el-table-column>
</el-table>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="订单备注" prop="remarks">
{{ form.remarks }}
</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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/erp/purchaseApi";
import { allData as supplierlAllData } from "@/api/erp/supplierApi";
import { listData as materialListData } from "@/api/erp/materialApi";
import { getListByPurchaseId } from "@/api/erp/purchaseDetailsApi";
import { ref } from "@vue/reactivity";
import { computed } from "@vue/runtime-core";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
//详情物料对话框
const openDetails = ref(false);
//添加物料对话框
const openMaterial = ref(false);
const materialList = ref([]);
const materialTotal = ref(0);
const materialMultipleSelection = ref([]);
//选择框供应商
const supplierList = ref([]);
const dataList = 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 data = reactive({
form: {
supplierId: undefined,
totalMoney: 0,
purchaseDetails: [],
},
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined,
buyer: undefined,
},
queryMaterialParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined,
},
rules: {
code: [{ required: true, message: "采购单编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "采购单名称不能为空", trigger: "blur" }],
},
});
const { queryParams, form, queryMaterialParams, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加采购单";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改采购单";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id, form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
/** 查看详情 */
function handleGet(row) {
getListByPurchaseId(row.id).then((response) => {
form.value.purchaseDetails = response.data;
});
form.value.remarks=row.remarks;
openDetails.value = true;
}
//-------------这里开始是物料对话框的数据-----------
/** 物料查询列表 */
function getMaterialList() {
materialListData(
proxy.addDateRange(queryMaterialParams.value, dateRange.value)
).then((response) => {
materialList.value = response.data.data;
materialTotal.value = response.data.total;
});
}
/** 表单改变选择 */
function materialHandleSelectionChange(select) {
materialMultipleSelection.value = select;
}
/** 打开对话框 */
function materialHandleAdd() {
getMaterialList();
openMaterial.value = true;
}
/** 搜索 */
function handleMaterialQuery() {
getMaterialList();
}
/**重置表单 */
function resetMaterialQuery() {
proxy.resetForm("queryMaterialRef");
handleMaterialQuery();
}
/** 提交物料表单 */
function submitMaterialForm() {
if (materialMultipleSelection.value.length > 0) {
const purchaseDetailsList = materialMultipleSelection.value.map((u) => {
return { materialName: u.name, materialUnit: u.unitName };
});
form.value.purchaseDetails.push(...purchaseDetailsList);
materialCancel();
} else {
proxy.$modal.msgError("请选择至少一个物料");
}
}
/** 取消对话框 */
function materialCancel() {
openMaterial.value = false;
}
/** 删除物料行 */
function delMaterialRow(index) {
form.value.purchaseDetails.splice(index, 1);
}
// watch(data.form, (newValue, oldValue) => {
// console.log(newValue.purchaseDetails,999)
// }
// , { immdiate: true })
/** 计算属性:实时计算展示的价格 */
const showTotalMoney = computed(() => {
let res = 0;
form.value.purchaseDetails.forEach((details) => {
if (details.unitPrice != undefined && details.totalNumber != undefined) {
res += details.unitPrice * details.totalNumber;
}
});
return res;
});
const purchaseStateEnum=[
{key:"build",name:"新建"},
{key:"run",name:"进行中"},
{key:"complete",name:"已完成"},
{key:"end",name:"已结束"},
]
/** 计算属性:采购订单状态 */
const purchaseStateComputed= computed(()=>
(purchaseState) => {
return purchaseStateEnum[purchaseState].name
});
//-------------这里开始是供货商的数据-----------
/** 供货商查询列表 */
function getSupplierList() {
supplierlAllData().then((response) => {
supplierList.value = response.data;
});
}
getList();
getSupplierList();
</script>
<style scoped>
.form-add-btn {
width: 100%;
margin-top: 10px;
}
</style>

View File

@@ -0,0 +1,363 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="100px"
>
<el-form-item label="库存名称" prop="name" >
<el-input
v-model="queryParams.name"
placeholder="请输入库存名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="库存编号" prop="code" >
<el-input
v-model="queryParams.code"
placeholder="请输入库存编号"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="code"
/>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['erp:stock:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['erp:stock:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['erp:stock:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['erp:stock:export']"
>导出</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="code" />
<el-table-column label="库存名称" align="center" prop="name" :show-overflow-tooltip="true"/>
<el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['business:article:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['business:article: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="600px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="库存编码" prop="code">
<el-input v-model="form.code" placeholder="请输入库存编码" />
</el-form-item>
<el-form-item label="库存名称" prop="name">
<el-input v-model="form.name" placeholder="请输入库存名称" />
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item> -->
<el-form-item label="备注" prop="remarks">
<el-input
v-model="form.remarks"
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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/erp/stockApi";
import { ref } from "@vue/reactivity";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const dataList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined,
},
rules: {
code: [{ required: true, message: "库存编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "库存名称不能为空", trigger: "blur" }],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加库存";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改库存";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id,form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
getList();
</script>

View File

@@ -0,0 +1,390 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="100px"
>
<el-form-item label="供应商名称" prop="name" >
<el-input
v-model="queryParams.name"
placeholder="请输入供应商名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="供应商编号" prop="code" >
<el-input
v-model="queryParams.code"
placeholder="请输入供应商编号"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="code"
/>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['erp:supplier:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['erp:supplier:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['erp:supplier:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['erp:supplier:export']"
>导出</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="code" />
<el-table-column label="供应商名称" align="center" prop="name" :show-overflow-tooltip="true"/>
<el-table-column label="详细地址" align="center" prop="address" :show-overflow-tooltip="true"/>
<el-table-column label="联系人" align="center" prop="name" :show-overflow-tooltip="true"/>
<el-table-column label="联系电话" align="center" prop="phone" :show-overflow-tooltip="true"/>
<el-table-column label="传真" align="center" prop="fax" :show-overflow-tooltip="true"/>
<el-table-column label="邮箱" align="center" prop="email" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['business:article:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['business:article: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="600px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="供应商编码" prop="code">
<el-input v-model="form.code" placeholder="请输入供应商编码" />
</el-form-item>
<el-form-item label="供应商名称" prop="name">
<el-input v-model="form.name" 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="code">
<el-input v-model="form.code" placeholder="请输入供应商编码" />
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" />
</el-form-item>
<el-form-item label="传真" prop="fax">
<el-input v-model="form.fax" placeholder="请输入传真" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item> -->
<el-form-item label="备注" prop="remarks">
<el-input
v-model="form.remarks"
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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/erp/supplierApi";
import { ref } from "@vue/reactivity";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const dataList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined,
},
rules: {
code: [{ required: true, message: "供应商编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "供应商名称不能为空", trigger: "blur" }],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加供应商";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改供应商";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id,form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
getList();
</script>

View File

@@ -0,0 +1,363 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="100px"
>
<el-form-item label="单位名称" prop="name" >
<el-input
v-model="queryParams.name"
placeholder="请输入单位名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="单位编号" prop="code" >
<el-input
v-model="queryParams.code"
placeholder="请输入单位编号"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="code"
/>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['erp:unit:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['erp:unit:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['erp:unit:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['erp:unit:export']"
>导出</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="code" />
<el-table-column label="单位名称" align="center" prop="name" :show-overflow-tooltip="true"/>
<el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['business:article:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['business:article: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="600px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="单位编码" prop="code">
<el-input v-model="form.code" placeholder="请输入单位编码" />
</el-form-item>
<el-form-item label="单位名称" prop="name">
<el-input v-model="form.name" placeholder="请输入单位名称" />
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item> -->
<el-form-item label="备注" prop="remarks">
<el-input
v-model="form.remarks"
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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/erp/unitApi";
import { ref } from "@vue/reactivity";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const dataList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined,
},
rules: {
code: [{ required: true, message: "单位编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "单位名称不能为空", trigger: "blur" }],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加单位";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改单位";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id,form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
getList();
</script>

View File

@@ -0,0 +1,368 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="100px"
>
<el-form-item label="仓库名称" prop="name" >
<el-input
v-model="queryParams.name"
placeholder="请输入仓库名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="name"
/>
</el-form-item>
<el-form-item label="仓库编号" prop="code" >
<el-input
v-model="queryParams.code"
placeholder="请输入仓库编号"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
prop="code"
/>
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['erp:warehouse:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['erp:warehouse:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['erp:warehouse:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['erp:warehouse:export']"
>导出</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="code" />
<el-table-column label="仓库名称" align="center" prop="name" :show-overflow-tooltip="true"/>
<el-table-column label="备注" align="center" prop="remarks" :show-overflow-tooltip="true"/>
<!-- <el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['business:article:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['business:article: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="600px" append-to-body>
<el-form ref="dataRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="仓库编码" prop="code">
<el-input v-model="form.code" placeholder="请输入仓库编码" />
</el-form-item>
<el-form-item label="仓库名称" prop="name">
<el-input v-model="form.name" placeholder="请输入仓库名称" />
</el-form-item>
<!-- <el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item> -->
<el-form-item label="备注" prop="remarks">
<el-input
v-model="form.remarks"
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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/erp/warehouseApi";
import { ref } from "@vue/reactivity";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const dataList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
code: undefined,
},
rules: {
code: [{ required: true, message: "仓库编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "仓库名称不能为空", trigger: "blur" }],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
isDeleted: false,
remark: undefined,
};
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加仓库";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改仓库";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value.id,form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
getList();
</script>

View File

@@ -0,0 +1,381 @@
<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="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="['bbs:article:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['bbs:article:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['bbs:article:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['bbs:article:export']"
>导出</el-button
>
</el-col>
<right-toolbar
v-model:showSearch="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="articleList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="编号" align="center" prop="id" />
<el-table-column
label="文章标题"
align="center"
prop="title"
:show-overflow-tooltip="true"
/>
<el-table-column
label="文章部分内容"
align="left"
prop="content"
:show-overflow-tooltip="true"
>
<template #default="scope">
{{scope.row.content.slice(0,30)}}
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag
:options="sys_normal_disable"
:value="scope.row.isDeleted"
/>
</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"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleOpen(scope.row)"
>文章详情</el-button
>
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['bbs:article:edit']"
>修改</el-button
>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['bbs:article: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="文章标题" prop="title">
<el-input v-model="form.title" placeholder="请输入文章标题" />
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(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>
import {
listData,
getData,
delData,
addData,
updateData,
} from "@/api/bbs/articleApi";
import { ref } from "@vue/reactivity";
import { computed } from "@vue/runtime-core";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const articleList = 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 articleDialogVisible=ref(false);
const articleId=ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
title: undefined,
isDeleted: undefined,
},
rules: {
title: [{ required: true, message: "文章标题不能为空", trigger: "blur" }],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询列表 */
function getList() {
loading.value = true;
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
articleList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
title: undefined,
isDeleted: false,
remark: undefined,
};
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加文章";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改文章类型";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate((valid) => {
if (valid) {
if (form.value.id != undefined) {
updateData(form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addData(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const delIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除字典编号为"' + delIds + '"的数据项?')
.then(function () {
return delData(delIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {}
/** 打开文章详情 */
function handleOpen(row){
articleId.value=row.id;
articleDialogVisible.value=true;
}
getList();
</script>

View File

@@ -0,0 +1,82 @@
<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>
</template>
<script setup>
import errImage from "@/assets/401_images/401.gif";
let { proxy } = getCurrentInstance();
const errGif = ref(errImage + "?" + +new Date());
function back() {
if (proxy.$route.query.noGoBack) {
proxy.$router.push({ path: "/" });
} else {
proxy.$router.go(-1);
}
}
</script>
<style lang="scss" scoped>
.errPage-container {
width: 800px;
max-width: 100%;
margin: 100px auto;
.pan-back-btn {
background: #008489;
color: #fff;
border: none !important;
}
.pan-gif {
margin: 0 auto;
display: block;
}
.pan-img {
display: block;
margin: 0 auto;
width: 100%;
}
.text-jumbo {
font-size: 60px;
font-weight: 700;
color: #484848;
}
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
</style>

View File

@@ -0,0 +1,227 @@
<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>
</template>
<script setup>
let message = computed(() => {
return '找不到网页!'
})
</script>
<style lang="scss" scoped>
.wscn-http404-container{
transform: translate(-50%,-50%);
position: absolute;
top: 40%;
left: 50%;
}
.wscn-http404 {
position: relative;
width: 1200px;
padding: 0 50px;
overflow: hidden;
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
}
</style>

View File

@@ -0,0 +1,934 @@
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :sm="24" :lg="24">
<blockquote class="text-warning" style="font-size: 14px">
领取阿里云通用云产品1888优惠券
<br />
<el-link
href="https://www.aliyun.com/minisite/goods?userCode=brki8iof"
type="primary"
target="_blank"
>https://www.aliyun.com/minisite/goods?userCode=brki8iof</el-link
>
<br />
领取腾讯云通用云产品2860优惠券
<br />
<el-link
href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console"
type="primary"
target="_blank"
>https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console</el-link
>
<br />
阿里云服务器折扣区
<el-link href="http://aly.ruoyi.vip" type="primary" target="_blank"
>>点我进入</el-link
>
&nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区
<el-link href="http://txy.ruoyi.vip" type="primary" target="_blank"
>>点我进入</el-link
><br />
<h4 class="text-danger">
云产品通用红包可叠加官网常规优惠使用(仅限新用户)
</h4>
</blockquote>
<hr />
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>意框架-若依后台管理框架</h2>
<h3>当前在线人数{{onlineNum}}</h3>
<p>
Ruoyi:一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适自己的于是利用空闲休息时间开始自己写一套后台系统如此有了若依管理系统她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA等等当然您也可以对她进行深度定制以做出更强系统所有前端后台代码封装过后十分精简易上手出错概率低同时支持移动客户端访问系统会陆续更新一些实用功能
</p>
<p>
<b>当前Ruoyi版本:</b> <span>v{{ version }}</span>
</p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
>访问码云</el-button
>
<el-button
icon="HomeFilled"
plain
@click="goTarget('http://ruoyi.vip')"
>访问主页</el-button
>
</p>
</el-col>
<el-col :sm="24" :lg="12" style="padding-left: 50px">
<el-row>
<el-col :span="12">
<h2>技术选型</h2>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<h4>后端技术</h4>
<ul>
<li>.Net6</li>
<li>WebFirst</li>
<li>JWT</li>
<li>Sqlsugar</li>
<li>Redis</li>
<li>json</li>
<li>...</li>
</ul>
</el-col>
<el-col :span="6">
<h4>前端技术</h4>
<ul>
<li>Vue</li>
<li>Vuex</li>
<li>Element-ui</li>
<li>Axios</li>
<li>Sass</li>
<li>Quill</li>
<li>...</li>
</ul>
</el-col>
</el-row>
</el-col>
</el-row>
<el-divider />
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<template v-slot:header>
<div class="clearfix">
<span>联系信息</span>
</div>
</template>
<div class="body">
<p>
<i class="el-icon-s-promotion"></i> Sqlsugar官网地址<el-link
href="https://www.donet5.com/"
target="_blank"
>https://www.donet5.com/</el-link
>
</p>
<p>
<i class="el-icon-s-promotion"></i> Yi意框架地址<el-link
href="https://gitee.com/ccnetcore/yi"
target="_blank"
>https://gitee.com/ccnetcore/yi</el-link
>
</p>
<p>
<i class="el-icon-s-promotion"></i> Ruoyi官网<el-link
href="http://www.ruoyi.vip"
target="_blank"
>http://www.ruoyi.vip</el-link
>
</p>
<p>
<i class="el-icon-user-solid"></i> Yi框架 QQ群<s>官方一群已满</s> <s>官方二群已满</s>
<a href="https://jq.qq.com/?_wv=1027&k=0fsNiYZt" target="_blank">
官方三群160110482</a
>
</p>
<p>
<i class="el-icon-user-solid"></i> Ruoyi QQ群<s>满937441</s> <s>满887144332</s>
<s>满180251782</s> <s>满104180207</s> <s>满186866453</s> <s>满201396349</s>
<s>满101456076</s> <s>满101539465</s> <s>满264312783</s> <s>满167385320</s>
<s>满104748341</s> <a href="https://jq.qq.com/?_wv=1027&k=0fsNiYZt" target="_blank">
160110482</a
>
</p>
<p>
<i class="el-icon-chat-dot-round"></i> 微信<a
href="javascript:;"
>/ *若依</a
>
</p>
<p>
<i class="el-icon-money"></i> 支付宝<a
href="javascript:;"
class="支付宝信息"
>/ *若依</a
>
</p>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<template v-slot:header>
<div class="clearfix">
<span>更新日志</span>
</div>
</template>
<el-collapse accordion>
<el-collapse-item title="v3.8.3 - 2022-06-27">
<ol>
<li>新增缓存列表菜单功能</li>
<li>代码生成树表新增(展开/折叠)</li>
<li>Excel注解支持color字体颜色</li>
<li>新增Anonymous匿名访问不鉴权注解</li>
<li>用户头像上传限制只能为图片格式</li>
<li>接口使用泛型使其看到响应属性字段</li>
<li>检查定时任务bean所在包名是否为白名单配置</li>
<li>添加页签openPage支持传递参数</li>
<li>用户缓存信息添加部门ancestors祖级列表</li>
<li>升级element-ui到最新版本2.15.8</li>
<li>升级oshi到最新版本6.1.6</li>
<li>升级druid到最新版本1.2.11</li>
<li>升级fastjson到最新版2.0.8</li>
<li>升级spring-boot到最新版本2.5.14</li>
<li>降级jsencrypt版本兼容IE浏览器</li>
<li>删除多余的salt字段</li>
<li>新增获取不带后缀文件名称方法</li>
<li>新增获取配置文件中的属性值方法</li>
<li>新增内容编码/解码方便插件集成使用</li>
<li>字典类型必须以字母开头且只能为小写字母数字下滑线</li>
<li>优化设置分页参数默认值</li>
<li>优化对空字符串参数处理的过滤</li>
<li>优化显示顺序orderNum类型为整型</li>
<li>优化表单构建按钮不显示正则校验</li>
<li>优化字典数据回显样式下拉框显示值</li>
<li>优化R响应成功状态码与全局保持一致</li>
<li>优化druid开启wall过滤器出现的异常问题</li>
<li>优化用户管理左侧树型组件增加选中高亮保持</li>
<li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
<li>优化默认不启用压缩文件缓存防止node_modules过大</li>
<li>修复字典数据显示不全问题</li>
<li>修复操作日志查询类型条件为0时会查到所有数据</li>
<li>修复Excel注解prompt/combo同时使用不生效问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.2 - 2022-04-01">
<ol>
<li>前端支持设置是否需要防止数据重复提交</li>
<li>开启TopNav没有子菜单情况隐藏侧边栏</li>
<li>侧边栏菜单名称过长悬停显示标题</li>
<li>用户访问控制时校验数据权限防止越权</li>
<li>导出Excel时屏蔽公式防止CSV注入风险</li>
<li>组件ImagePreview支持多图预览显示</li>
<li>组件ImageUpload支持多图同时选择上传</li>
<li>组件FileUpload支持多文件同时选择上传</li>
<li>服务监控新增运行参数信息显示</li>
<li>定时任务目标字符串过滤特殊字符</li>
<li>定时任务目标字符串验证包名白名单</li>
<li>代码生成列表图片支持预览</li>
<li>代码生成编辑修改打开新页签</li>
<li>代码生成新增Java类型Boolean</li>
<li>代码生成子表支持日期/字典配置</li>
<li>代码生成同步保留必填/类型选项</li>
<li>升级oshi到最新版本6.1.2</li>
<li>升级fastjson到最新版1.2.80</li>
<li>升级pagehelper到最新版1.4.1</li>
<li>升级spring-boot到最新版本2.5.11</li>
<li>升级spring-boot-mybatis到最新版2.2.2</li>
<li>添加遗漏的分页参数合理化属性</li>
<li>修改npm即将过期的注册源地址</li>
<li>修复分页组件请求两次问题</li>
<li>修复通用文件下载接口跨域问题</li>
<li>修复Xss注解字段值为空时的异常问题</li>
<li>修复选项卡点击右键刷新丢失参数问题</li>
<li>修复表单清除元素位置未垂直居中问题</li>
<li>修复服务监控中运行参数显示条件错误</li>
<li>修复导入Excel时字典字段类型为Long转义为空问题</li>
<li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li>
<li>优化加载字典缓存数据</li>
<li>优化IP地址获取到多个的问题</li>
<li>优化任务队列满时任务拒绝策略</li>
<li>优化文件上传兼容Weblogic环境</li>
<li>优化定时任务默认保存到内存中执行</li>
<li>优化部门修改缩放后出现的错位问题</li>
<li>优化Excel格式化不同类型的日期对象</li>
<li>优化菜单表关键字导致的插件报错问题</li>
<li>优化Oracle用户头像列为空时不显示问题</li>
<li>优化页面若未匹配到字典标签则返回原字典值</li>
<li>优化修复登录失效后多次请求提示多次弹窗问题</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.1 - 2022-01-01">
<ol>
<li>新增Vue3前端代码生成模板</li>
<li>新增图片预览组件</li>
<li>新增压缩插件实现打包Gzip</li>
<li>自定义xss校验注解实现</li>
<li>自定义文字复制剪贴指令</li>
<li>代码生成预览支持复制内容</li>
<li>路由支持单独配置菜单或角色权限</li>
<li>用户管理部门查询选择节点后分页参数初始</li>
<li>修复用户分配角色属性错误</li>
<li>修复打包后字体图标偶现的乱码问题</li>
<li>修复菜单管理重置表单出现的错误</li>
<li>修复版本差异导致的懒加载报错问题</li>
<li>修复Cron组件中周回显问题</li>
<li>修复定时任务多参数逗号分隔的问题</li>
<li>修复根据ID查询列表可能出现的主键溢出问题</li>
<li>修复tomcat配置参数已过期问题</li>
<li>升级clipboard到最新版本2.0.8</li>
<li>升级oshi到最新版本v5.8.6</li>
<li>升级fastjson到最新版1.2.79</li>
<li>升级spring-boot到最新版本2.5.8</li>
<li>升级log4j2到2.17.1防止漏洞风险</li>
<li>优化下载解析blob异常提示</li>
<li>优化代码生成字典组重复问题</li>
<li>优化查询用户的角色组&岗位组代码</li>
<li>优化定时任务cron表达式小时设置24</li>
<li>优化用户导入提示溢出则显示滚动条</li>
<li>优化防重复提交标识组合为(key+url+header)</li>
<li>优化分页方法设置成通用方便灵活调用</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.0 - 2021-12-01">
<ol>
<li>新增配套并同步的Vue3前端版本</li>
<li>新增通用方法简化模态/缓存/下载/权限/页签使用</li>
<li>优化导出数据/使用通用下载方法</li>
<li>Excel注解支持自定义数据处理器</li>
<li>Excel注解支持导入导出标题信息</li>
<li>Excel导入支持@Excels注解</li>
<li>新增组件data-dict简化数据字典使用</li>
<li>新增Jaxb依赖防止jdk8以上出现的兼容错误</li>
<li>生产环境使用路由懒加载提升页面响应速度</li>
<li>修复五级以上菜单出现的404问题</li>
<li>防重提交注解支持配置间隔时间/提示消息</li>
<li>日志注解新增是否保存响应参数</li>
<li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
<li>升级SpringBoot到最新版本2.5.6</li>
<li>升级pagehelper到最新版1.4.0</li>
<li>升级spring-boot-mybatis到最新版2.2.0</li>
<li>升级oshi到最新版本v5.8.2</li>
<li>升级druid到最新版1.2.8</li>
<li>升级velocity到最新版本2.3</li>
<li>升级fastjson到最新版1.2.78</li>
<li>升级axios到最新版本0.24.0</li>
<li>升级dart-sass到版本1.32.13</li>
<li>升级core-js到最新版本3.19.1</li>
<li>升级jsencrypt到最新版本3.2.1</li>
<li>升级js-cookie到最新版本3.0.1</li>
<li>升级file-saver到最新版本2.0.5</li>
<li>升级sass-loader到最新版本10.1.1</li>
<li>升级element-ui到最新版本2.15.6</li>
<li>新增sendGet无参请求方法</li>
<li>禁用el-tag组件的渐变动画</li>
<li>代码生成点击预览重置激活tab</li>
<li>AjaxResult重写put方法以方便链式调用</li>
<li>优化登录/验证码请求headers不设置token</li>
<li>优化用户个人信息接口防止修改用户名</li>
<li>优化Cron表达式生成器关闭时销毁避免缓存</li>
<li>优化注册成功提示消息类型success</li>
<li>优化aop语法使用spring自动注入注解</li>
<li>优化记录登录信息移除不必要的修改</li>
<li>优化mybatis全局默认的执行器</li>
<li>优化Excel导入图片可能出现的异常</li>
<li>修复代码生成模板主子表删除缺少事务</li>
<li>修复日志记录可能出现的转换异常</li>
<li>修复代码生成复选框字典遗漏问题</li>
<li>修复关闭xss功能导致可重复读RepeatableFilter失效</li>
<li>修复字符串无法被反转义问题</li>
<li>修复后端主子表代码模板方法名生成错误问题</li>
<li>修复xss过滤后格式出现的异常</li>
<li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.7.0 - 2021-09-13">
<ol>
<li>参数管理支持配置验证码开关</li>
<li>新增是否开启用户注册功能</li>
<li>定时任务支持在线生成cron表达式</li>
<li>菜单管理支持配置路由参数</li>
<li>支持自定义注解实现接口限流</li>
<li>Excel注解支持Image图片导入</li>
<li>自定义弹层溢出滚动样式</li>
<li>自定义可拖动弹窗宽度指令</li>
<li>自定义可拖动弹窗高度指令</li>
<li>修复任意账户越权问题</li>
<li>修改时检查用户数据权限范围</li>
<li>修复保存配置主题颜色失效问题</li>
<li>新增暗色菜单风格主题</li>
<li>菜单&部门新增展开/折叠功能</li>
<li>页签新增关闭左侧&添加图标</li>
<li>顶部菜单排除隐藏的默认路由</li>
<li>顶部菜单同步系统主题样式</li>
<li>跳转路由高亮相对应的菜单栏</li>
<li>代码生成主子表多选行数据</li>
<li>日期范围支持添加多组</li>
<li>升级element-ui到最新版本2.15.5</li>
<li>升级oshi到最新版本v5.8.0</li>
<li>升级commons.io到最新版本v2.11.0</li>
<li>定时任务屏蔽ldap远程调用</li>
<li>定时任务屏蔽http(s)远程调用</li>
<li>补充定时任务表字段注释</li>
<li>定时任务对检查异常进行事务回滚</li>
<li>启用父部门状态排除顶级节点</li>
<li>富文本新增上传文件大小限制</li>
<li>默认首页使用keep-alive缓存</li>
<li>修改代码生成字典回显样式</li>
<li>自定义分页合理化传入参数</li>
<li>修复字典组件值为整形不显示问题</li>
<li>修复定时任务日志执行状态显示</li>
<li>角色&菜单新增字段属性提示信息</li>
<li>修复角色分配用户页面参数类型错误提醒</li>
<li>优化布局设置动画特效</li>
<li>优化异常处理信息</li>
<li>优化错误token导致的解析异常</li>
<li>密码框新增显示切换密码图标</li>
<li>定时任务新增更多操作</li>
<li>更多操作按钮添加权限控制</li>
<li>导入用户样式优化</li>
<li>提取通用方法到基类控制器</li>
<li>优化使用权限工具获取用户信息</li>
<li>优化用户不能删除自己</li>
<li>优化XSS跨站脚本过滤</li>
<li>优化代码生成模板</li>
<li>验证码默认20s超时</li>
<li>BLOB下载时清除URL对象引用</li>
<li>代码生成导入表按创建时间排序</li>
<li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
<li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li>
<li>多图上传组件移除多余的api地址&验证失败导致图片删除问题&无法删除相应图片修复</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.6.0 - 2021-07-12">
<ol>
<li>角色管理新增分配用户功能</li>
<li>用户管理新增分配角色功能</li>
<li>日志列表支持排序操作</li>
<li>优化参数&字典缓存操作</li>
<li>系统布局配置支持动态标题开关</li>
<li>菜单路由配置支持内链访问</li>
<li>默认访问后端首页新增提示语</li>
<li>富文本默认上传返回url类型</li>
<li>新增自定义弹窗拖拽指令</li>
<li>全局注册常用通用组件</li>
<li>全局挂载字典标签组件</li>
<li>ImageUpload组件支持多图片上传</li>
<li>FileUpload组件支持多文件上传</li>
<li>文件上传组件添加数量限制属性</li>
<li>富文本编辑组件添加类型属性</li>
<li>富文本组件工具栏配置视频</li>
<li>封装通用iframe组件</li>
<li>限制超级管理员不允许操作</li>
<li>用户信息长度校验限制</li>
<li>分页组件新增pagerCount属性</li>
<li>添加bat脚本执行应用</li>
<li>升级oshi到最新版本v5.7.4</li>
<li>升级element-ui到最新版本2.15.2</li>
<li>升级pagehelper到最新版1.3.1</li>
<li>升级commons.io到最新版本v2.10.0</li>
<li>升级commons.fileupload到最新版本v1.4</li>
<li>升级swagger到最新版本v3.0.0</li>
<li>修复关闭confirm提示框控制台报错问题</li>
<li>修复存在的SQL注入漏洞问题</li>
<li>定时任务屏蔽rmi远程调用</li>
<li>修复用户搜索分页变量错误</li>
<li>修复导出角色数据范围翻译缺少仅本人</li>
<li>修复表单构建选择下拉选择控制台报错问题</li>
<li>优化图片工具类读取文件</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.5.0 - 2021-05-25">
<ol>
<li>新增菜单导航显示风格TopNavfalse为左侧导航菜单true为顶部导航菜单</li>
<li>布局设置支持保存&重置配置</li>
<li>修复树表数据显示不全&加载慢问题</li>
<li>新增IE浏览器版本过低提示页面</li>
<li>用户登录后记录最后登录IP&时间</li>
<li>页面导出按钮点击之后添加遮罩</li>
<li>富文本编辑器支持自定义上传地址</li>
<li>富文本编辑组件新增readOnly属性</li>
<li>页签TagsView新增关闭右侧功能</li>
<li>显隐列组件加载初始默认隐藏列</li>
<li>关闭头像上传窗口还原默认图片</li>
<li>个人信息添加手机&邮箱重复验证</li>
<li>代码生成模板导出按钮点击后添加遮罩</li>
<li>代码生成模板树表操作列添加新增按钮</li>
<li>代码生成模板修复主子表字段重名问题</li>
<li>升级fastjson到最新版1.2.76</li>
<li>升级druid到最新版本v1.2.6</li>
<li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li>
<li>升级oshi到最新版本v5.6.0</li>
<li>velocity剔除commons-collections版本防止3.2.1版本的反序列化漏洞</li>
<li>数据监控页默认账户密码防止越权访问</li>
<li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
<li>修正后端导入表权限标识</li>
<li>修正前端操作日志&登录日志权限标识</li>
<li>设置Redis配置HashKey序列化</li>
<li>删除操作日志记录信息</li>
<li>上传媒体类型添加视频格式</li>
<li>修复请求形参未传值记录日志异常问题</li>
<li>优化xss校验json请求条件</li>
<li>树级结构更新子节点使用replaceFirst</li>
<li>优化ExcelUtil空值处理</li>
<li>日志记录过滤BindingResult对象防止异常</li>
<li>修改主题后mini类型按钮无效问题</li>
<li>优化通用下载完成后删除节点</li>
<li>通用Controller添加响应返回消息</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.4.0 - 2021-02-22">
<ol>
<li>代码生成模板支持主子表</li>
<li>表格右侧工具栏组件支持显隐列</li>
<li>图片组件添加预览&移除功能</li>
<li>Excel注解支持Image图片导出</li>
<li>操作按钮组调整为朴素按钮样式</li>
<li>代码生成支持文件上传组件</li>
<li>代码生成日期控件区分范围</li>
<li>代码生成数据库文本类型生成表单文本域</li>
<li>用户手机邮箱&菜单组件修改允许空字符串</li>
<li>升级SpringBoot到最新版本2.2.13 提升启动速度</li>
<li>升级druid到最新版本v1.2.4</li>
<li>升级fastjson到最新版1.2.75</li>
<li>升级element-ui到最新版本2.15.0</li>
<li>修复IE11浏览器报错问题</li>
<li>优化多级菜单之间切换无法缓存的问题</li>
<li>修复四级菜单无法显示问题</li>
<li>修正侧边栏静态路由丢失问题</li>
<li>修复角色管理-编辑角色-功能权限显示异常</li>
<li>配置文件新增redis数据库索引属性</li>
<li>权限工具类增加admin判断</li>
<li>角色非自定义权限范围清空选择值</li>
<li>修复导入数据为负浮点数时丢失精度问题</li>
<li>移除path-to-regexp正则匹配插件</li>
<li>修复生成树表代码异常</li>
<li>修改ip字段长度防止ipv6地址长度不够</li>
<li>防止get请求参数值为false或0等特殊值会导致无法正确的传参</li>
<li>登录后push添加catch防止出现检查错误</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.3.0 - 2020-12-14">
<ol>
<li>新增缓存监控功能</li>
<li>支持主题风格配置</li>
<li>修复多级菜单之间切换无法缓存的问题</li>
<li>多级菜单自动配置组件</li>
<li>代码生成预览支持高亮显示</li>
<li>支持Get请求映射Params参数</li>
<li>删除用户和角色解绑关联</li>
<li>去除用户手机邮箱部门必填验证</li>
<li>Excel支持注解align对齐方式</li>
<li>Excel支持导入Boolean型数据</li>
<li>优化头像样式鼠标移入悬停遮罩</li>
<li>代码生成预览提供滚动机制</li>
<li>代码生成删除多余的数字float类型</li>
<li>修正转换字符串的目标字符集属性</li>
<li>回显数据字典防止空值报错</li>
<li>日志记录增加过滤多文件场景</li>
<li>修改缓存Set方法可能导致嵌套的问题</li>
<li>移除前端一些多余的依赖</li>
<li>防止安全扫描YUI出现的风险提示</li>
<li>修改node-sass为dart-sass</li>
<li>升级SpringBoot到最新版本2.1.18</li>
<li>升级poi到最新版本4.1.2</li>
<li>升级oshi到最新版本v5.3.6</li>
<li>升级bitwalker到最新版本1.21</li>
<li>升级axios到最新版本0.21.0</li>
<li>升级element-ui到最新版本2.14.1</li>
<li>升级vue到最新版本2.6.12</li>
<li>升级vuex到最新版本3.6.0</li>
<li>升级vue-cli到版本4.5.9</li>
<li>升级vue-router到最新版本3.4.9</li>
<li>升级vue-cli到最新版本4.4.6</li>
<li>升级vue-cropper到最新版本0.5.5</li>
<li>升级clipboard到最新版本2.0.6</li>
<li>升级core-js到最新版本3.8.1</li>
<li>升级echarts到最新版本4.9.0</li>
<li>升级file-saver到最新版本2.0.4</li>
<li>升级fuse.js到最新版本6.4.3</li>
<li>升级js-beautify到最新版本1.13.0</li>
<li>升级js-cookie到最新版本2.2.1</li>
<li>升级path-to-regexp到最新版本6.2.0</li>
<li>升级quill到最新版本1.3.7</li>
<li>升级screenfull到最新版本5.0.2</li>
<li>升级sortablejs到最新版本1.10.2</li>
<li>升级vuedraggable到最新版本2.24.3</li>
<li>升级chalk到最新版本4.1.0</li>
<li>升级eslint到最新版本7.15.0</li>
<li>升级eslint-plugin-vue到最新版本7.2.0</li>
<li>升级lint-staged到最新版本10.5.3</li>
<li>升级runjs到最新版本4.4.2</li>
<li>升级sass-loader到最新版本10.1.0</li>
<li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
<li>升级svg-sprite-loader到最新版本5.1.1</li>
<li>升级vue-template-compiler到最新版本2.6.12</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.2.1 - 2020-11-18">
<ol>
<li>阻止任意文件下载漏洞</li>
<li>代码生成支持上传控件</li>
<li>新增图片上传组件</li>
<li>调整默认首页</li>
<li>升级druid到最新版本v1.2.2</li>
<li>mapperLocations配置支持分隔符</li>
<li>权限信息调整</li>
<li>调整sql默认时间</li>
<li>解决代码生成没有bit类型的问题</li>
<li>升级pagehelper到最新版1.3.0</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.2.0 - 2020-10-10">
<ol>
<li>升级springboot版本到2.1.17 提升安全性</li>
<li>升级oshi到最新版本v5.2.5</li>
<li>升级druid到最新版本v1.2.1</li>
<li>升级jjwt到版本0.9.1</li>
<li>升级fastjson到最新版1.2.74</li>
<li>修改sass为node-sass避免el-icon图标乱码</li>
<li>代码生成支持同步数据库</li>
<li>代码生成支持富文本控件</li>
<li>代码生成页面时不忽略remark属性</li>
<li>代码生成添加select必填选项</li>
<li>Excel导出类型NUMERIC支持精度浮点类型</li>
<li>Excel导出targetAttr优化获取值防止get方法不规范</li>
<li>Excel注解支持自动统计数据总和</li>
<li>Excel注解支持设置BigDecimal精度&舍入规则</li>
<li>菜单&数据权限新增展开/折叠 全选/全不选 父子联动</li>
<li>允许用户分配到部门父节点</li>
<li>菜单新增是否缓存keep-alive</li>
<li>表格操作列间距调整</li>
<li>限制系统内置参数不允许删除</li>
<li>富文本组件优化支持自定义高度&图片冲突问题</li>
<li>富文本工具栏样式对齐</li>
<li>导入excel整形值校验优化</li>
<li>修复页签关闭所有时固定标签路由不刷新问题</li>
<li>表单构建布局型组件新增按钮</li>
<li>左侧菜单文字过长显示省略号</li>
<li>修正根节点为子部门时树状结构显示问题</li>
<li>修正调用目标字符串最大长度</li>
<li>修正菜单提示信息错误</li>
<li>修正定时任务执行一次权限标识</li>
<li>修正数据库字符串类型nvarchar</li>
<li>优化递归子节点</li>
<li>优化数据权限判断</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.1.0 - 2020-08-13">
<ol>
<li>表格工具栏右侧添加刷新&显隐查询组件</li>
<li>后端支持CORS跨域请求</li>
<li>代码生成支持选择上级菜单</li>
<li>代码生成支持自定义路径</li>
<li>代码生成支持复选框</li>
<li>Excel导出导入支持dictType字典类型</li>
<li>Excel支持分割字符串组内容</li>
<li>验证码类型支持数组计算字符验证</li>
<li>升级vue-cli版本到4.4.4</li>
<li>修改 node-sass dart-sass</li>
<li>表单类型为Integer/Long设置整形默认值</li>
<li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
<li>优化防重复提交拦截器</li>
<li>优化上级菜单不能选择自己</li>
<li>修复角色的权限分配后未实时生效问题</li>
<li>修复在线用户日志记录类型</li>
<li>修复富文本空格和缩进保存后不生效问题</li>
<li>修复在线用户判断逻辑</li>
<li>唯一限制条件只返回单条数据</li>
<li>添加获取当前的环境配置方法</li>
<li>超时登录后页面跳转到首页</li>
<li>全局异常状态汉化拦截处理</li>
<li>HTML过滤器改为将html转义</li>
<li>检查字符支持小数点&降级改成异常提醒</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.0.0 - 2020-07-20">
<ol>
<li>单应用调整为多模块项目</li>
<li>升级element-ui版本到2.13.2</li>
<li>删除babel提高编译速度</li>
<li>新增菜单默认主类目</li>
<li>编码文件名修改为uuid方式</li>
<li>定时任务cron表达式验证</li>
<li>角色权限修改时已有权限未自动勾选异常修复</li>
<li>防止切换权限用户后登录出现404</li>
<li>Excel支持sort导出排序</li>
<li>创建用户不允许选择超级管理员角色</li>
<li>修复代码生成导入表结构出现异常页面不提醒问题</li>
<li>修复代码生成点击多次表修改数据不变化的问题</li>
<li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
<li>修复布局为small者mini用户表单显示错位问题</li>
<li>修复热部署导致的强换异常问题</li>
<li>修改用户管理复选框宽度防止部分浏览器出现省略号</li>
<li>IpUtils工具清除Xss特殊字符防止Xff注入攻击</li>
<li>生成domain 如果是浮点型 统一用BigDecimal</li>
<li>定时任务调整label-width防止部署出现错位</li>
<li>调整表头固定列默认样式</li>
<li>代码生成模板调整字段为String并且必填则加空串条件</li>
<li>代码生成字典Integer/Long使用parseInt</li>
<li>
修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
</li>
<li>修正岗位导出权限注解</li>
<li>禁止加密密文返回前端</li>
<li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
<li>修复首页搜索菜单外链无法点击跳转问题</li>
<li>修复菜单管理选择图标backspace删除时不过滤数据</li>
<li>用户管理部门分支节点不可检查&显示计数</li>
<li>数据范围过滤属性调整</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.3.0 - 2020-06-01">
<ol>
<li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
<li>dev启动默认打开浏览器</li>
<li>vue-cli使用默认source-map</li>
<li>slidebar eslint报错优化</li>
<li>当tags-view滚动关闭右键菜单</li>
<li>字典管理添加缓存读取</li>
<li>参数管理支持缓存操作</li>
<li>支持一级菜单和主页同级在main区域显示</li>
<li>限制外链地址必须以http(s)开头</li>
<li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
<li>修改数据源类型优先级先根据方法再根据类</li>
<li>支持是否需要设置token属性自定义返回码消息</li>
<li>swagger请求前缀加入配置</li>
<li>登录地点设置内容过长则隐藏显示</li>
<li>修复定时任务执行一次按钮后不提示消息问题</li>
<li>修改上级部门选择项排除本身和下级</li>
<li>通用http发送方法增加参数 contentType 编码类型</li>
<li>更换IP地址查询接口</li>
<li>修复页签变量undefined</li>
<li>添加校验部门包含未停用的子部门</li>
<li>修改定时任务详情下次执行时间日期显示错误</li>
<li>角色管理查询设置默认排序字段</li>
<li>swagger添加enable参数控制是否启用</li>
<li>只对json类型请求构建可重复读取inputStream的request</li>
<li>修改代码生成字典字段int类型没有自动选中问题</li>
<li>vuex用户名取值修正</li>
<li>表格树模板去掉多余的)</li>
<li>代码生成序号修正</li>
<li>全屏情况下不调整上外边距</li>
<li>代码生成Date字段添加默认格式</li>
<li>用户管理角色选择权限控制</li>
<li>修复路由懒加载报错问题</li>
<li>模板sql.vm添加菜单状态</li>
<li>设置用户名称不能修改</li>
<li>dialog添加append-to-body属性防止ie遮罩</li>
<li>菜单区分状态和显示隐藏功能</li>
<li>升级fastjson到最新版1.2.68 修复安全加固</li>
<li>修复代码生成如果选择字典类型缺失逗号问题</li>
<li>登录请求params更换为data防止暴露url</li>
<li>日志返回时间格式处理</li>
<li>添加handle控制允许拖动的元素</li>
<li>布局设置点击扩大范围</li>
<li>代码生成列属性排序查询</li>
<li>代码生成列支持拖动排序</li>
<li>修复时间格式不支持ios问题</li>
<li>表单构建添加父级class防止冲突</li>
<li>定时任务并发属性修正</li>
<li>角色禁用&菜单隐藏不查询权限</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.2.0 - 2020-03-18">
<ol>
<li>系统监控新增定时任务功能</li>
<li>添加一个打包Web工程bat</li>
<li>修复页签鼠标滚轮按下的时候可以关闭不可关闭的tag</li>
<li>修复点击退出登录有时会无提示问题</li>
<li>修复防重复提交注解无效问题</li>
<li>修复通知公告批量删除异常问题</li>
<li>添加菜单时路由地址必填限制</li>
<li>代码生成字段描述可编辑</li>
<li>修复用户修改个人信息导致缓存不过期问题</li>
<li>个人信息创建时间获取正确属性值</li>
<li>操作日志详细显示正确类型</li>
<li>导入表单击行数据时选中对应的复选框</li>
<li>批量替换表前缀逻辑调整</li>
<li>固定重定向路径表达式</li>
<li>升级element-ui版本到2.13.0</li>
<li>操作日志排序调整</li>
<li>修复charts切换侧边栏或者缩放窗口显示bug</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.1.0 - 2020-02-24">
<ol>
<li>新增表单构建</li>
<li>代码生成支持树表结构</li>
<li>新增用户导入</li>
<li>修复动态加载路由页面刷新问题</li>
<li>修复地址开关无效问题</li>
<li>汉化错误提示页面</li>
<li>代码生成已知问题修改</li>
<li>修复多数据源下配置关闭出现异常处理</li>
<li>添加HTML过滤器用于去除XSS漏洞隐患</li>
<li>修复上传头像控制台出现异常</li>
<li>修改用户管理分页不正确的问题</li>
<li>修复验证码记录提示错误</li>
<li>修复request.js缺少Message引用</li>
<li>修复表格时间为空出现的异常</li>
<li>添加Jackson日期反序列化时区配置</li>
<li>调整根据用户权限加载菜单数据树形结构</li>
<li>调整成功登录不恢复按钮防止多次点击</li>
<li>修改用户个人资料同步缓存信息</li>
<li>修复页面同时出现el-upload和Editor不显示处理</li>
<li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
<li>配置文件新增redis密码属性</li>
<li>设置mybatis全局的配置文件</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.0.0 - 2019-12-02">
<ol>
<li>新增代码生成</li>
<li>新增@RepeatSubmit注解防止重复提交</li>
<li>新增菜单主目录添加/删除操作</li>
<li>日志记录过滤特殊对象防止转换异常</li>
<li>修改代码生成路由脚本错误</li>
<li>用户上传头像实时同步缓存无需重新登录</li>
<li>调整切换页签后不重新加载数据</li>
<li>添加jsencrypt实现参数的前端加密</li>
<li>系统退出删除用户缓存记录</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.1.0 - 2019-11-11">
<ol>
<li>新增在线用户管理</li>
<li>新增按钮组功能实现批量删除导出清空</li>
<li>新增查询条件重置按钮</li>
<li>新增Swagger全局Token配置</li>
<li>新增后端参数校验</li>
<li>修复字典管理页面的日期查询异常</li>
<li>修改时间函数命名防止冲突</li>
<li>去除菜单上级校验默认为顶级</li>
<li>修复用户密码无法修改问题</li>
<li>修复菜单类型为按钮时不显示权限标识</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.0.0 - 2019-10-08">
<ol>
<li>若依前后端分离系统正式发布</li>
</ol>
</el-collapse-item>
</el-collapse>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<template v-slot:header>
<div class="clearfix">
<span>RuoYi捐赠支持</span>
</div>
</template>
<div class="body">
<img
src="https://oscimg.oschina.net/oscnet/up-d6695f82666e5018f715c41cb7ee60d3b73.png"
alt="donate"
style="width:100%"
/>
<span style="display: inline-block; height: 30px; line-height: 30px"
>你可以请作者喝杯咖啡表示鼓励</span
>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="Index">
import useSocketStore from '@/store/modules/socket'
import { ref } from 'vue';
import { storeToRefs } from 'pinia';
const socketStore=useSocketStore();
const {onlineNum}=storeToRefs(socketStore);
const version = ref('3.8.3')
function goTarget(url) {
window.open(url, '__blank')
}
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul {
padding: 0;
margin: 0;
}
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
ul {
list-style-type: none;
}
h4 {
margin-top: 0px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
p {
margin-top: 10px;
b {
font-weight: 700;
}
}
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
}
}
}
</style>

View File

@@ -0,0 +1,218 @@
<template>
<div class="login">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">意框架-Ruoyi管理系统</h3>
<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-2022 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script setup>
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const router = useRouter();
const { proxy } = getCurrentInstance();
const loginForm = ref({
username: "cc",
password: "123456",
rememberMe: false,
code: "",
uuid: ""
});
const loginRules = {
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
};
const codeUrl = ref("");
const loading = ref(false);
// 验证码开关
const captchaEnabled = ref(true);
// 注册开关
const register = ref(false);
const redirect = ref(undefined);
function handleLogin() {
proxy.$refs.loginRef.validate(valid => {
if (valid) {
loading.value = true;
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) {
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 });
} else {
// 否则移除
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove("rememberMe");
}
// 调用action的登录方法
userStore.login(loginForm.value).then(() => {
router.push({ path: redirect.value || "/" });
}).catch(() => {
loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
getCode();
}
});
}
});
}
function getCode() {
getCodeImg().then(res => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.data.img;
loginForm.value.uuid = res.data.uuid;
}
});
}
function getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get("rememberMe");
loginForm.value = {
username: username === undefined ? loginForm.value.username : username,
password: password === undefined ? loginForm.value.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
}
getCode();
getCookie();
</script>
<style lang='scss' scoped>
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
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;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 40px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 40px;
padding-left: 12px;
}
</style>

View File

@@ -0,0 +1,131 @@
<template>
<div class="app-container">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<template #header><span>基本信息</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><span>命令统计</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>
<span>内存信息</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">
import { getCache } from '@/api/monitor/cache';
import * as echarts from 'echarts';
const cache = ref([]);
const commandstats = ref(null);
const usedmemory = ref(null);
const { proxy } = getCurrentInstance();
function getList() {
proxy.$modal.loading("正在加载缓存监控数据,请稍候!");
getCache().then(response => {
proxy.$modal.closeLoading();
cache.value = response.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: 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: "内存消耗"
}
]
}
]
})
})
}
getList();
</script>

View File

@@ -0,0 +1,241 @@
<template>
<div class="app-container">
<el-row :gutter="10">
<el-col :span="8">
<el-card style="height: calc(100vh - 125px)">
<template #header>
<span>缓存列表</span>
<el-button
style="float: right; padding: 3px 0"
type="text"
icon="Refresh"
@click="refreshCacheNames()"
></el-button>
</template>
<el-table
v-loading="loading"
:data="cacheNames"
:height="tableHeight"
highlight-current-row
@row-click="getCacheKeys"
style="width: 100%"
>
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column
label="缓存名称"
align="center"
prop="cacheName"
:show-overflow-tooltip="true"
:formatter="nameFormatter"
></el-table-column>
<el-table-column
label="备注"
align="center"
prop="remark"
:show-overflow-tooltip="true"
/>
<el-table-column
label="操作"
width="60"
align="center"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Delete"
@click="handleClearCacheName(scope.row)"
></el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<el-col :span="8">
<el-card style="height: calc(100vh - 125px)">
<template #header>
<span>键名列表</span>
<el-button
style="float: right; padding: 3px 0"
type="text"
icon="Refresh"
@click="refreshCacheKeys()"
></el-button>
</template>
<el-table
v-loading="subLoading"
:data="cacheKeys"
:height="tableHeight"
highlight-current-row
@row-click="handleCacheValue"
style="width: 100%"
>
<el-table-column
label="序号"
width="60"
type="index"
></el-table-column>
<el-table-column
label="缓存键名"
align="center"
:show-overflow-tooltip="true"
:formatter="keyFormatter"
>
</el-table-column>
<el-table-column
label="操作"
width="60"
align="center"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
type="text"
icon="Delete"
@click="handleClearCacheKey(scope.row)"
></el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<el-col :span="8">
<el-card :bordered="false" style="height: calc(100vh - 125px)">
<template #header>
<span>缓存内容</span>
<el-button
style="float: right; padding: 3px 0"
type="text"
icon="Refresh"
@click="handleClearCacheAll()"
>清理全部</el-button
>
</template>
<el-form :model="cacheForm">
<el-row :gutter="32">
<el-col :offset="1" :span="22">
<el-form-item label="缓存名称:" prop="cacheName">
<el-input v-model="cacheForm.cacheName" :readOnly="true" />
</el-form-item>
</el-col>
<el-col :offset="1" :span="22">
<el-form-item label="缓存键名:" prop="cacheKey">
<el-input v-model="cacheForm.cacheKey" :readOnly="true" />
</el-form-item>
</el-col>
<el-col :offset="1" :span="22">
<el-form-item label="缓存内容:" prop="cacheValue">
<el-input
v-model="cacheForm.cacheValue"
type="textarea"
:rows="8"
:readOnly="true"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="CacheList">
import { listCacheName, listCacheKey, getCacheValue, clearCacheName, clearCacheKey, clearCacheAll } from "@/api/monitor/cache";
const { proxy } = getCurrentInstance();
const cacheNames = ref([]);
const cacheKeys = ref([]);
const cacheForm = ref({});
const loading = ref(true);
const subLoading = ref(false);
const nowCacheName = ref("");
const tableHeight = ref(window.innerHeight - 200);
/** 查询缓存名称列表 */
function getCacheNames() {
loading.value = true;
listCacheName().then(response => {
cacheNames.value = response.data;
loading.value = false;
});
}
/** 刷新缓存名称列表 */
function refreshCacheNames() {
getCacheNames();
proxy.$modal.msgSuccess("刷新缓存列表成功");
}
/** 清理指定名称缓存 */
function handleClearCacheName(row) {
clearCacheName(row.cacheName).then(response => {
proxy.$modal.msgSuccess("清理缓存名称[" + nowCacheName.value + "]成功");
getCacheKeys();
});
}
/** 查询缓存键名列表 */
function getCacheKeys(row) {
const cacheName = row !== undefined ? row.cacheName : nowCacheName.value;
if (cacheName === "") {
return;
}
subLoading.value = true;
listCacheKey(cacheName).then(response => {
cacheKeys.value = response.data;
subLoading.value = false;
nowCacheName.value = cacheName;
});
}
/** 刷新缓存键名列表 */
function refreshCacheKeys() {
getCacheKeys();
proxy.$modal.msgSuccess("刷新键名列表成功");
}
/** 清理指定键名缓存 */
function handleClearCacheKey(cacheKey) {
clearCacheKey(cacheKey).then(response => {
proxy.$modal.msgSuccess("清理缓存键名[" + cacheKey + "]成功");
getCacheKeys();
});
}
/** 列表前缀去除 */
function nameFormatter(row) {
return row.cacheName.replace(":", "");
}
/** 键名前缀去除 */
function keyFormatter(cacheKey) {
return cacheKey.replace(nowCacheName.value, "");
}
/** 查询缓存内容详细 */
function handleCacheValue(cacheKey) {
getCacheValue(nowCacheName.value, cacheKey).then(response => {
cacheForm.value = response.data;
});
}
/** 清理全部缓存 */
function handleClearCacheAll() {
clearCacheAll().then(response => {
proxy.$modal.msgSuccess("清理全部缓存成功");
});
}
getCacheNames();
</script>

View File

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

View File

@@ -0,0 +1,503 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
placeholder="请输入任务名称"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="任务组名" prop="jobGroup">
<el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable>
<el-option
v-for="dict in sys_job_group"
: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>
<el-option
v-for="dict in sys_job_status"
: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="['monitor:job:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['monitor:job:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:job:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['monitor:job:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Operation"
@click="handleJobLog"
v-hasPermi="['monitor:job:query']"
>日志</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="任务编号" width="100" align="center" prop="jobId" />
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
<el-table-column label="任务组名" align="center" prop="jobGroup">
<template #default="scope">
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" />
</template>
</el-table-column>
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
<el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center">
<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="200" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['monitor:job:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['monitor:job:remove']"
></el-button>
</el-tooltip>
<el-tooltip content="执行一次" placement="top">
<el-button
type="text"
icon="CaretRight"
@click="handleRun(scope.row)"
v-hasPermi="['monitor:job:changeStatus']"
></el-button>
</el-tooltip>
<el-tooltip content="任务详细" placement="top">
<el-button
type="text"
icon="View"
@click="handleView(scope.row)"
v-hasPermi="['monitor:job:query']"
></el-button>
</el-tooltip>
<el-tooltip content="调度日志" placement="top">
<el-button
type="text"
icon="Operation"
@click="handleJobLog(scope.row)"
v-hasPermi="['monitor:job: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-dialog :title="title" v-model="open" width="800px" append-to-body>
<el-form ref="jobRef" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="任务名称" prop="jobName">
<el-input v-model="form.jobName" placeholder="请输入任务名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务分组" prop="jobGroup">
<el-select v-model="form.jobGroup" placeholder="请选择">
<el-option
v-for="dict in sys_job_group"
: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 prop="invokeTarget">
<template #label>
<span>
调用方法
<el-tooltip placement="top">
<template #content>
<div>
Bean调用示例ryTask.ryParams('ry')
<br />Class类调用示例com.ruoyi.quartz.task.RyTask.ryParams('ry')
<br />参数说明支持字符串布尔类型长整型浮点型整型
</div>
</template>
<el-icon><question-filled /></el-icon>
</el-tooltip>
</span>
</template>
<el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="cron表达式" prop="cronExpression">
<el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式">
<template #append>
<el-button type="primary" @click="handleShowCron">
生成表达式
<i class="el-icon-time el-icon--right"></i>
</el-button>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="执行策略" prop="misfirePolicy">
<el-radio-group v-model="form.misfirePolicy">
<el-radio-button label="1">立即执行</el-radio-button>
<el-radio-button label="2">执行一次</el-radio-button>
<el-radio-button label="3">放弃执行</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否并发" prop="concurrent">
<el-radio-group v-model="form.concurrent">
<el-radio-button label="0">允许</el-radio-button>
<el-radio-button label="1">禁止</el-radio-button>
</el-radio-group>
</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_job_status"
: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>
<!-- 任务日志详细 -->
<el-dialog title="任务详细" v-model="openView" width="700px" append-to-body>
<el-form :model="form" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item>
<el-form-item label="创建时间:">{{ form.createTime }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="cron表达式">{{ form.cronExpression }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下次执行时间:">{{ parseTime(form.nextValidTime) }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item>
</el-col>
<el-col :span="12">
<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="12">
<el-form-item label="是否并发:">
<div v-if="form.concurrent == 0">允许</div>
<div v-else-if="form.concurrent == 1">禁止</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="执行策略:">
<div v-if="form.misfirePolicy == 0">默认策略</div>
<div v-else-if="form.misfirePolicy == 1">立即执行</div>
<div v-else-if="form.misfirePolicy == 2">执行一次</div>
<div v-else-if="form.misfirePolicy == 3">放弃执行</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="openView = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Job">
import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job";
const router = useRouter();
const { proxy } = getCurrentInstance();
const { sys_job_group, sys_job_status } = proxy.useDict("sys_job_group", "sys_job_status");
const jobList = 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 openView = ref(false);
const openCron = ref(false);
const expression = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
jobName: undefined,
jobGroup: undefined,
status: undefined
},
rules: {
jobName: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
invokeTarget: [{ required: true, message: "调用目标字符串不能为空", trigger: "blur" }],
cronExpression: [{ required: true, message: "cron执行表达式不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询定时任务列表 */
function getList() {
loading.value = true;
listJob(queryParams.value).then(response => {
jobList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 任务组名字典翻译 */
function jobGroupFormat(row, column) {
return proxy.selectDictLabel(sys_job_group.value, row.jobGroup);
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
jobId: undefined,
jobName: undefined,
jobGroup: undefined,
invokeTarget: undefined,
cronExpression: undefined,
misfirePolicy: 1,
concurrent: 1,
status: "0"
};
proxy.resetForm("jobRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.jobId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
// 更多操作触发
function handleCommand(command, row) {
switch (command) {
case "handleRun":
handleRun(row);
break;
case "handleView":
handleView(row);
break;
case "handleJobLog":
handleJobLog(row);
break;
default:
break;
}
}
// 任务状态修改
function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function () {
return changeJobStatus(row.jobId, row.status);
}).then(() => {
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
row.status = row.status === "0" ? "1" : "0";
});
}
/* 立即执行一次 */
function handleRun(row) {
proxy.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function () {
return runJob(row.jobId, row.jobGroup);
}).then(() => {
proxy.$modal.msgSuccess("执行成功");})
.catch(() => {});
}
/** 任务详细信息 */
function handleView(row) {
getJob(row.jobId).then(response => {
form.value = response.data;
openView.value = true;
});
}
/** cron表达式按钮操作 */
function handleShowCron() {
expression.value = form.value.cronExpression;
openCron.value = true;
}
/** 确定后回传值 */
function crontabFill(value) {
form.value.cronExpression = value;
}
/** 任务日志列表查询 */
function handleJobLog(row) {
const jobId = row.jobId || 0;
router.push({ path: "/monitor/job-log/index", query: { jobId: jobId } });
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加任务";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const jobId = row.jobId || ids.value;
getJob(jobId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改任务";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["jobRef"].validate(valid => {
if (valid) {
if (form.value.jobId != undefined) {
updateJob(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addJob(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const jobIds = row.jobId || ids.value;
proxy.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function () {
return delJob(jobIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/job/export", {
...queryParams.value,
}, `job_${new Date().getTime()}.xlsx`);
}
getList();
</script>

View File

@@ -0,0 +1,282 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
placeholder="请输入任务名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="任务组名" prop="jobGroup">
<el-select
v-model="queryParams.jobGroup"
placeholder="请选择任务组名"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_job_group"
: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"
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="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:job:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
@click="handleClean"
v-hasPermi="['monitor:job:remove']"
>清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['monitor:job: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="jobLogList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
<el-table-column label="任务组名" align="center" prop="jobGroup" :show-overflow-tooltip="true">
<template #default="scope">
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" />
</template>
</el-table-column>
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
<el-table-column label="日志信息" align="center" prop="jobMessage" :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="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
type="text"
icon="View"
@click="handleView(scope.row)"
v-hasPermi="['monitor:job: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.jobLogId }}</el-form-item>
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务分组:">{{ form.jobGroup }}</el-form-item>
<el-form-item label="执行时间:">{{ form.createTime }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="调用方法:">{{ form.invokeTarget }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="日志信息:">{{ form.jobMessage }}</el-form-item>
</el-col>
<el-col :span="24">
<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="24">
<el-form-item label="异常信息:" v-if="form.status == 1">{{ form.exceptionInfo }}</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="JobLog">
import { getJob } from "@/api/monitor/job";
import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog";
const { proxy } = getCurrentInstance();
const { sys_common_status, sys_job_group } = proxy.useDict("sys_common_status", "sys_job_group");
const jobLogList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const multiple = ref(true);
const total = ref(0);
const dateRange = ref([]);
const route = useRoute();
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
status: undefined
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询调度日志列表 */
function getList() {
loading.value = true;
listJobLog(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
jobLogList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 返回按钮
function handleClose() {
const obj = { path: "/monitor/job" };
proxy.$tab.closeOpenPage(obj);
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.jobLogId);
multiple.value = !selection.length;
}
/** 详细按钮操作 */
function handleView(row) {
open.value = true;
form.value = row;
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除调度日志编号为"' + ids.value + '"的数据项?').then(function () {
return delJobLog(ids.value);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有调度日志数据项?").then(function () {
return cleanJobLog();
}).then(() => {
getList();
proxy.$modal.msgSuccess("清空成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/jobLog/export", {
...queryParams.value,
}, `job_log_${new Date().getTime()}.xlsx`);
}
(() => {
const jobId = route.query.jobId;
if (jobId !== undefined && jobId != 0) {
getJob(jobId).then(response => {
queryParams.value.jobName = response.data.jobName;
queryParams.value.jobGroup = response.data.jobGroup;
getList();
});
} else {
getList();
}
})();
getList();
</script>

View File

@@ -0,0 +1,224 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="登录Ip" prop="loginIp">
<el-input
v-model="queryParams.loginIp"
placeholder="请输入登录Ip"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="loginUser">
<el-input
v-model="queryParams.loginUser"
placeholder="请输入用户名称"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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"
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="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>
<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="id" />
<el-table-column label="用户名称" align="center" prop="loginUser" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="地址" align="center" prop="loginIp" :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="isDeleted">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.isDeleted" />
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="msg" />
<el-table-column label="访问时间" align="center" prop="createTime" sortable="custom" :sort-orders="['descending', 'ascending']" 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"
/>
</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 loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const selectName = ref("");
const total = ref(0);
const dateRange = ref([]);
const defaultSort = ref({ prop: "createTime", order: "descending" });
// 查询参数
const queryParams = ref({
pageNum: 1,
pageSize: 10,
loginIp: undefined,
loginUser: undefined,
isDeleted: undefined,
orderByColumn: undefined,
isAsc: undefined
});
/** 查询登录日志列表 */
function getList() {
loading.value = true;
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
logininforList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
proxy.$refs["logininforRef"].sort(defaultSort.value.prop, defaultSort.value.order);
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
multiple.value = !selection.length;
single.value = selection.length != 1;
selectName.value = selection.map(item => item.loginUser);
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop;
queryParams.value.isAsc = column.order;
getList();
}
/** 删除按钮操作 */
function handleDelete(row) {
const infoIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function () {
return delLogininfor(infoIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有登录日志数据项?").then(function () {
return cleanLogininfor();
}).then(() => {
getList();
proxy.$modal.msgSuccess("清空成功");
}).catch(() => {});
}
/** 解锁按钮操作 */
function handleUnlock() {
const loginUser = selectName.value;
proxy.$modal.confirm('是否确认解锁用户"' + loginUser + '"数据项?').then(function () {
return unlockLogininfor(loginUser);
}).then(() => {
proxy.$modal.msgSuccess("用户" + loginUser + "解锁成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/logininfor/export", {
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`);
}
getList();
</script>

View File

@@ -0,0 +1,110 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="68px">
<el-form-item label="登录ip" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录ip"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
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-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="connnectionId" :show-overflow-tooltip="true" />
<el-table-column label="登录名称" align="center" prop="userName" :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
type="text"
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="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
</div>
</template>
<script setup name="Online">
import { forceLogout, list as initData } from "@/api/monitor/online";
const { proxy } = getCurrentInstance();
const onlineList = ref([]);
const loading = ref(true);
const total = ref(0);
// const pageNum = ref(1);
// const pageSize = ref(10);
const queryParams = ref({
pageNum: 1,
pageSize: 10,
ipaddr: undefined,
userName: undefined
});
/** 查询登录日志列表 */
function getList() {
loading.value = true;
initData(queryParams.value).then(response => {
onlineList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 强退按钮操作 */
function handleForceLogout(row) {
proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
return forceLogout(row.connnectionId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
getList();
</script>

View File

@@ -0,0 +1,279 @@
<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="operUser">
<el-input
v-model="queryParams.operUser"
placeholder="请输入操作人员"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="类型" prop="operType">
<el-select
v-model="queryParams.operType"
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="isDeleted">
<el-select v-model="queryParams.isDeleted" 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"
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="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>
<el-table ref="operlogRef" v-loading="loading" :data="operlogList" @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="id" />
<el-table-column label="系统模块" align="center" prop="title" />
<el-table-column label="操作类型" align="center" prop="operType">
<template #default="scope">
<dict-tag :options="sys_oper_type" :value="scope.row.operType" />
</template>
</el-table-column>
<el-table-column label="请求方式" align="center" prop="requestMethod" />
<el-table-column label="操作人员" align="center" prop="operUser" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" width="100" />
<el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.isDeleted" />
</template>
</el-table-column>
<el-table-column label="操作日期" align="center" prop="createTime" sortable="custom" :sort-orders="['descending', 'ascending']" 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
type="text"
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.operUser }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求地址:">{{ form.method }}</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.requestParam }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="返回参数:">{{ form.requestResult }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="操作状态:">
<div v-if="form.isDeleted === false">正常</div>
<div v-else-if="form.isDeleted === true">失败</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="操作时间:">{{ parseTime(form.createTime) }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="异常信息:" v-if="form.isDeleted === 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 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 defaultSort = ref({ prop: "operTime", order: "descending" });
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
title: undefined,
operUser: undefined,
operType: undefined,
isDeleted: undefined
}
});
const { queryParams, form } = toRefs(data);
/** 查询登录日志 */
function getList() {
loading.value = true;
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
operlogList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 操作日志类型字典翻译 */
function typeFormat(row, column) {
return proxy.selectDictLabel(sys_oper_type.value, row.businessType);
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
proxy.$refs["operlogRef"].sort(defaultSort.value.prop, defaultSort.value.order);
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
multiple.value = !selection.length;
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop;
queryParams.value.isAsc = column.order;
getList();
}
/** 详细按钮操作 */
function handleView(row) {
open.value = true;
form.value = row;
}
/** 删除按钮操作 */
function handleDelete(row) {
const operIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function () {
return delOperlog(operIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有操作日志数据项?").then(function () {
return cleanOperlog();
}).then(() => {
getList();
proxy.$modal.msgSuccess("清空成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/operlog/export",{
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`);
}
getList();
</script>

View File

@@ -0,0 +1,187 @@
<template>
<div class="app-container">
<el-row>
<el-col :span="12" class="card-box">
<el-card>
<template #header><span>CPU</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;">
<thead>
<tr>
<th class="el-table__cell is-leaf"><div class="cell">属性</div></th>
<th class="el-table__cell is-leaf"><div class="cell"></div></th>
</tr>
</thead>
<tbody>
<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="server.cpu">{{ server.cpu.cpuNum }}</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="server.cpu">{{ server.cpu.used }}%</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="server.cpu">{{ server.cpu.sys }}%</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="server.cpu">{{ server.cpu.free }}%</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<template #header><span>内存</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;">
<thead>
<tr>
<th class="el-table__cell is-leaf"><div class="cell">属性</div></th>
<th class="el-table__cell is-leaf"><div class="cell">内存</div></th>
<th class="el-table__cell is-leaf"><div class="cell">JVM</div></th>
</tr>
</thead>
<tbody>
<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="server.mem">{{ server.mem.total }}G</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.total }}M</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="server.mem">{{ server.mem.used}}G</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.used}}M</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="server.mem">{{ server.mem.free }}G</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.free }}M</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="server.mem" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm" :class="{'text-danger': server.jvm.usage > 80}">{{ server.jvm.usage }}%</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-card>
<template #header><span>服务器信息</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">服务器名称</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.computerName }}</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="server.sys">{{ server.sys.osName }}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">服务器IP</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.computerIp }}</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="server.sys">{{ server.sys.osArch }}</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-card>
<template #header><span>Java虚拟机信息</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;table-layout:fixed;">
<tbody>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">Java名称</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.name }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">Java版本</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.version }}</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="server.jvm">{{ server.jvm.startTime }}</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="server.jvm">{{ server.jvm.runTime }}</div></td>
</tr>
<tr>
<td colspan="1" class="el-table__cell is-leaf"><div class="cell">安装路径</div></td>
<td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.home }}</div></td>
</tr>
<tr>
<td colspan="1" class="el-table__cell is-leaf"><div class="cell">项目路径</div></td>
<td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.userDir }}</div></td>
</tr>
<tr>
<td colspan="1" class="el-table__cell is-leaf"><div class="cell">运行参数</div></td>
<td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.inputArgs }}</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-card>
<template #header><span>磁盘状态</span></template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;">
<thead>
<tr>
<th class="el-table__cell el-table__cell is-leaf"><div class="cell">盘符路径</div></th>
<th class="el-table__cell is-leaf"><div class="cell">文件系统</div></th>
<th class="el-table__cell is-leaf"><div class="cell">盘符类型</div></th>
<th class="el-table__cell is-leaf"><div class="cell">总大小</div></th>
<th class="el-table__cell is-leaf"><div class="cell">可用大小</div></th>
<th class="el-table__cell is-leaf"><div class="cell">已用大小</div></th>
<th class="el-table__cell is-leaf"><div class="cell">已用百分比</div></th>
</tr>
</thead>
<tbody v-if="server.sysFiles">
<tr v-for="(sysFile, index) in server.sysFiles" :key="index">
<td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.dirName }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.sysTypeName }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.typeName }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.total }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.free }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.used }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell" :class="{'text-danger': sysFile.usage > 80}">{{ sysFile.usage }}%</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { getServer } from '@/api/monitor/server'
const server = ref([]);
const { proxy } = getCurrentInstance();
function getList() {
proxy.$modal.loading("正在加载服务监控数据,请稍候!");
getServer().then(response => {
server.value = response.data;
proxy.$modal.closeLoading();
});
}
getList();
</script>

View File

@@ -0,0 +1,14 @@
<template>
<div></div>
</template>
<script setup>
import { useRoute, useRouter } from 'vue-router'
const route = useRoute();
const router = useRouter();
const { params, query } = route
const { path } = params
router.replace({ path: '/' + path, query })
</script>

View File

@@ -0,0 +1,218 @@
<template>
<div class="register">
<el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">意框架-Ruoyi管理系统</h3>
<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-2022 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script setup>
import { ElMessageBox } from "element-plus";
import { getCodeImg, register } from "@/api/login";
const router = useRouter();
const { proxy } = getCurrentInstance();
const registerForm = ref({
username: "",
password: "",
confirmPassword: "",
code: "",
uuid: ""
});
const equalToPassword = (rule, value, callback) => {
if (registerForm.value.password !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
const registerRules = {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" },
{ min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
{ required: true, validator: equalToPassword, trigger: "blur" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
};
const codeUrl = ref("");
const loading = ref(false);
const captchaEnabled = ref(true);
function handleRegister() {
proxy.$refs.registerRef.validate(valid => {
if (valid) {
loading.value = true;
register(registerForm.value).then(res => {
const username = registerForm.value.username;
ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
dangerouslyUseHTMLString: true,
type: "success",
}).then(() => {
router.push("/login");
}).catch(() => {});
}).catch(() => {
loading.value = false;
if (captchaEnabled) {
getCode();
}
});
}
});
}
function getCode() {
getCodeImg().then(res => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img;
registerForm.value.uuid = res.uuid;
}
});
}
getCode();
</script>
<style lang='scss' scoped>
.register {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.register-form {
border-radius: 6px;
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;
}
}
.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;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.register-code-img {
height: 40px;
padding-left: 12px;
}
</style>

View File

@@ -0,0 +1,316 @@
<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"
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="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="id" />
<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" />
<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
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:config:edit']"
>修改</el-button>
<el-button
type="text"
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">
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
const { proxy } = getCurrentInstance();
const { sys_yes_no } = proxy.useDict("sys_yes_no");
const configList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
configName: undefined,
configKey: undefined,
configType: undefined
},
rules: {
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询参数列表 */
function getList() {
loading.value = true;
listConfig(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
configList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
configName: undefined,
configKey: undefined,
configValue: undefined,
configType: "Y",
remark: undefined,
isDeleted: false
};
proxy.resetForm("configRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加参数";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const configId = row.id || ids.value;
getConfig(configId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改参数";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["configRef"].validate(valid => {
if (valid) {
if (form.value.id != 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();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const configIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function () {
return delConfig(configIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/config/export", {
...queryParams.value
}, `config_${new Date().getTime()}.xlsx`);
}
/** 刷新缓存按钮操作 */
function handleRefreshCache() {
refreshCache().then(() => {
proxy.$modal.msgSuccess("刷新缓存成功");
});
}
getList();
</script>

View File

@@ -0,0 +1,297 @@
<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
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select v-model="queryParams.isDeleted" 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>
<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>
<el-table
v-if="refreshTable"
v-loading="loading"
:data="deptList"
row-key="id"
: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="isDeleted" label="状态" width="100">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.isDeleted" />
</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
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:dept:edit']"
>修改</el-button>
<el-button
type="text"
icon="Plus"
@click="handleAdd(scope.row)"
v-hasPermi="['system:dept:add']"
>新增</el-button>
<el-button
v-if="scope.row.parentId != 0"
type="text"
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: 'id', label: 'deptName', children: 'children' }"
value-key="id"
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.isDeleted">
<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>
<script setup name="Dept">
import { listDept, getDept, delDept, addDept, updateDept} from "@/api/system/dept";
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 data = reactive({
form: {},
queryParams: {
deptName: undefined,
isDeleted: undefined
},
rules: {
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
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);
/** 查询部门列表 */
function getList() {
loading.value = true;
listDept(queryParams.value).then(response => {
deptList.value = proxy.handleTree(response.data, "id");
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
parentId: undefined,
deptName: undefined,
orderNum: 0,
leader: undefined,
phone: undefined,
email: undefined,
isDeleted: false
};
proxy.resetForm("deptRef");
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
listDept().then(response => {
deptOptions.value = proxy.handleTree(response.data, "deptId");
deptOptions.value = proxy.handleTree(response.data, "id");
});
if (row != undefined) {
form.value.parentId = row.deptId;
form.value.parentId = row.id;
}
open.value = true;
title.value = "添加部门";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
listDeptExcludeChild(row.deptId).then(response => {
deptOptions.value = proxy.handleTree(response.data, "deptId");
listDept().then(response => {
//前端排除自己
deptOptions.value = proxy.handleTree(response.data.filter(i=>i.id!=row.id), "id");
});
getDept(row.id).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改部门";
});
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["deptRef"].validate(valid => {
if (valid) {
if (form.value.id != 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.id);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
getList();
</script>

View File

@@ -0,0 +1,355 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType">
<el-option
v-for="item in typeOptions"
:key="item.id"
: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
@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>
<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="id" />
<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="orderNum" />
<el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.isDeleted" />
</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
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
<el-button
type="text"
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="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="JSON.parse(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">
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";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const dataList = 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 defaultDictType = ref("");
const typeOptions = ref([]);
const route = useRoute();
// 数据标签回显样式
const listClassOptions = ref([
{ 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,
isDeleted: false
},
rules: {
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
orderNum: [{ 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();
});
}
/** 查询字典类型列表 */
function getTypeList() {
getDictOptionselect().then(response => {
typeOptions.value = response.data;
});
}
/** 查询字典数据列表 */
function getList() {
loading.value = true;
listData(queryParams.value).then(response => {
dataList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
dictLabel: undefined,
dictValue: undefined,
cssClass: undefined,
listClass: "default",
orderNum: 0,
isDeleted: false,
remark: undefined
};
proxy.resetForm("dataRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 返回按钮操作 */
function handleClose() {
const obj = { path: "/system/dict" };
proxy.$tab.closeOpenPage(obj);
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
queryParams.value.dictType = defaultDictType;
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加字典数据";
form.value.dictType = queryParams.value.dictType;
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const id = row.id || ids.value;
getData(id).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改字典数据";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate(valid => {
if (valid) {
if (form.value.id != 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();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除字典编码为"' + dictIds + '"的数据项?').then(function() {
return delData(dictIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
useDictStore().removeDict(queryParams.value.dictType);
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/data/export", {
...queryParams.value
}, `dict_data_${new Date().getTime()}.xlsx`);
}
getTypes(route.params && route.params.dictId);
getTypeList();
</script>

View File

@@ -0,0 +1,318 @@
<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="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="id" />
<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.id" class="link-type">
<span>{{ scope.row.dictType }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.isDeleted" />
</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" class-name="small-padding fixed-width">
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
<el-button
type="text"
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="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="JSON.parse(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">
import useDictStore from '@/store/modules/dict'
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const typeList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
isDeleted: false
},
rules: {
dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典类型列表 */
function getList() {
loading.value = true;
listType(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
typeList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
dictName: undefined,
dictType: undefined,
isDeleted: false,
remark: undefined
};
proxy.resetForm("dictRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加字典类型";
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const dictId = row.id || ids.value;
getType(dictId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改字典类型";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dictRef"].validate(valid => {
if (valid) {
if (form.value.id != 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();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
return delType(dictIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/type/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
}
/** 刷新缓存按钮操作 */
function handleRefreshCache() {
refreshCache().then(() => {
proxy.$modal.msgSuccess("刷新成功");
useDictStore().cleanDict();
});
}
getList();
</script>

View File

@@ -0,0 +1,454 @@
<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
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select v-model="queryParams.isDeleted" 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>
<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>
<el-table
v-if="refreshTable"
v-loading="loading"
:data="menuList"
row-key="id"
: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="menuIcon" label="图标" align="center" width="100">
<template #default="scope">
<svg-icon :icon-class="scope.row.menuIcon" />
</template>
</el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="permissionCode" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="router" 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="isDeleted" label="状态" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.isDeleted" />
</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" width="200" class-name="small-padding fixed-width">
<template #default="scope">
<el-button
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:menu:edit']"
>修改</el-button>
<el-button
type="text"
icon="Plus"
@click="handleAdd(scope.row)"
v-hasPermi="['system:menu:add']"
>新增</el-button>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:menu:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改菜单对话框 -->
<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: 'id', label: 'menuName', children: 'children' }"
value-key="id"
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=0>目录</el-radio>
<el-radio :label=1>菜单</el-radio>
<el-radio :label=2>按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.menuType != 2">
<el-form-item label="菜单图标" prop="menuIcon">
<el-popover
placement="bottom-start"
:width="540"
v-model:visible="showChooseIcon"
trigger="click"
@show="showSelectIcon"
>
<template #reference>
<el-input v-model="form.menuIcon" placeholder="点击选择图标" @click="showSelectIcon" v-click-outside="hideSelectIcon" readonly>
<template #prefix>
<svg-icon
v-if="form.menuIcon"
:icon-class="form.menuIcon"
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 != 2">
<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.isLink">
<el-radio :label=true></el-radio>
<el-radio :label=false></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 2">
<el-form-item prop="router">
<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.router" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 1">
<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 != 0">
<el-form-item>
<el-input v-model="form.permissionCode" 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 == 1">
<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 == 1">
<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=true>缓存</el-radio>
<el-radio :label=false>不缓存</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 2">
<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.isShow">
<el-radio
v-for="dict in sys_show_hide"
:key="dict.value"
:label="JSON.parse(dict.value)"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 2">
<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.isDeleted">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="JSON.parse(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>
<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" }],
router: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询菜单列表 */
function getList() {
loading.value = true;
listMenu(queryParams.value).then(response => {
menuList.value = proxy.handleTree(response.data, "id");
loading.value = false;
});
}
/** 查询菜单下拉树结构 */
function getTreeselect() {
menuOptions.value = [];
listMenu().then(response => {
const menu = { id: 0, menuName: "主类目", children: [] };
menu.children = proxy.handleTree(response.data, "id");
menuOptions.value.push(menu);
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
parentId: 0,
menuName: undefined,
menuIcon: undefined,
menuType: 0,
orderNum: 0,
isLink: false,
isCache: false,
isShow: true,
isDeleted: false
};
proxy.resetForm("menuRef");
}
/** 展示下拉图标 */
function showSelectIcon() {
iconSelectRef.value.reset();
showChooseIcon.value = true;
}
/** 选择图标 */
function selected(name) {
form.value.menuIcon = 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.id) {
form.value.parentId = row.id;
} 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.id).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改菜单";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["menuRef"].validate(valid => {
if (valid) {
if (form.value.id != 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.id);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
getList();
</script>

View File

@@ -0,0 +1,296 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input
v-model="queryParams.noticeTitle"
placeholder="请输入公告标题"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="操作人员" prop="createBy">
<el-input
v-model="queryParams.createBy"
placeholder="请输入操作人员"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable>
<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" />
<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="createBy" 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
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:notice:edit']"
>修改</el-button>
<el-button
type="text"
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="内容">
<el-input
:rows="6"
type="textarea"
placeholder="请输入内容"
v-model="form.noticeContent"
/>
</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">
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
const { proxy } = getCurrentInstance();
const { sys_notice_status, sys_notice_type } = proxy.useDict("sys_notice_status", "sys_notice_type");
const noticeList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
noticeTitle: undefined,
createBy: undefined,
status: undefined
},
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;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
noticeId: undefined,
noticeTitle: undefined,
noticeType: undefined,
noticeContent: undefined,
status: "0"
};
proxy.resetForm("noticeRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.noticeId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加公告";
}
/**修改按钮操作 */
function handleUpdate(row) {
reset();
const noticeId = row.noticeId || ids.value;
getNotice(noticeId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改公告";
});
}
/** 提交按钮 */
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();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const noticeIds = row.noticeId || ids.value
proxy.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
return delNotice(noticeIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
getList();
</script>

View File

@@ -0,0 +1,281 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="岗位编码" prop="postCode">
<el-input
v-model="queryParams.postCode"
placeholder="请输入岗位编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="岗位名称" prop="postName">
<el-input
v-model="queryParams.postName"
placeholder="请输入岗位名称"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select v-model="queryParams.isDeleted" 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>
<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="id" />
<el-table-column label="岗位编码" align="center" prop="postCode" />
<el-table-column label="岗位名称" align="center" prop="postName" />
<el-table-column label="岗位排序" align="center" prop="orderNum" />
<el-table-column label="状态" align="center" prop="isDeleted">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.isDeleted" />
</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
type="text"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:post:edit']"
>修改</el-button>
<el-button
type="text"
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="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="岗位状态" prop="isDeleted">
<el-radio-group v-model="form.isDeleted">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="JSON.parse(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">
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const postList = 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 data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
postCode: undefined,
postName: undefined,
isDeleted: undefined
},
rules: {
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询岗位列表 */
function getList() {
loading.value = true;
listPost(queryParams.value).then(response => {
postList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
id: undefined,
postCode: undefined,
postName: undefined,
orderNum: 0,
isDeleted: false,
remark: undefined
};
proxy.resetForm("postRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加岗位";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const postId = row.id || ids.value;
getPost(postId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改岗位";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["postRef"].validate(valid => {
if (valid) {
if (form.value.id != 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();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const postIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
return delPost(postIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/post/export", {
...queryParams.value
}, `post_${new Date().getTime()}.xlsx`);
}
getList();
</script>

View File

@@ -0,0 +1,177 @@
<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
type="text"
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";
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
const route = useRoute();
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const userList = ref([]);
const loading = ref(true);
const showSearch = ref(true);
const multiple = ref(true);
const total = ref(0);
const userIds = ref([]);
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
roleId: route.params.roleId,
userName: undefined,
phonenumber: undefined,
});
/** 查询授权用户列表 */
function getList() {
loading.value = true;
allocatedUserList(queryParams).then(response => {
userList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 返回按钮
function handleClose() {
const obj = { path: "/system/role" };
proxy.$tab.closeOpenPage(obj);
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
userIds.value = selection.map(item => item.userId);
multiple.value = !selection.length;
}
/** 打开授权用户表弹窗 */
function openSelectUser() {
proxy.$refs["selectRef"].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(() => {});
}
/** 批量取消授权按钮操作 */
function cancelAuthUserAll(row) {
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(() => {});
}
getList();
</script>

View File

@@ -0,0 +1,740 @@
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
v-show="showSearch"
:inline="true"
>
<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="roleCode">
<el-input
v-model="queryParams.roleCode"
placeholder="请输入权限字符"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select
v-model="queryParams.isDeleted"
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="结束日期"
></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="roleCode" width="120" />
<el-table-column
label="角色名称"
prop="roleName"
:show-overflow-tooltip="true"
width="150"
/>
<el-table-column
label="权限字符"
prop="roleCode"
:show-overflow-tooltip="true"
width="150"
/>
<el-table-column label="显示顺序" prop="orderNum" width="100" />
<el-table-column label="状态" align="center" width="100">
<template #default="scope">
<el-switch
v-model="scope.row.isDeleted"
:active-value="false"
:inactive-value="true"
@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
type="text"
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
type="text"
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
type="text"
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
type="text"
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.role"
:rules="rules"
label-width="100px"
>
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="form.role.roleName" placeholder="请输入角色名称" />
</el-form-item>
<el-form-item prop="roleCode">
<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.role.roleCode" placeholder="请输入权限字符" />
</el-form-item>
<el-form-item label="角色顺序" prop="orderNum">
<el-input-number
v-model="form.role.orderNum"
controls-position="right"
:min="0"
/>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.role.isDeleted">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="JSON.parse(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.role.menuCheckStrictly"
@change="handleCheckedTreeConnect($event, 'menu')"
>父子联动
</el-checkbox>
<el-tree
class="tree-border"
:data="menuOptions"
show-checkbox
ref="menuRef"
node-key="id"
:check-strictly="!form.role.menuCheckStrictly"
empty-text="加载中请稍候"
:props="{ label: 'label', children: 'children' }"
></el-tree>
</el-form-item>
<el-form-item label="备注">
<el-input
v-model="form.role.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.role.roleName" :disabled="true" />
</el-form-item>
<el-form-item label="权限字符">
<el-input v-model="form.role.roleCode" :disabled="true" />
</el-form-item>
<el-form-item label="权限范围">
<el-select
v-model="form.role.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.role.dataScope == 1">
<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">
import {
addRole,
changeRoleStatus,
dataScope,
delRole,
getRole,
listRole,
updateRole,
} from "@/api/system/role";
import {
roleMenuTreeselect,
treeselect as menuTreeselect,
listMenu,
} from "@/api/system/menu";
import { listDept, roleDeptTreeselect } from "@/api/system/dept";
const router = useRouter();
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = 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(true);
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 dataScopeOptions = ref([
{ value: 0, label: "全部数据权限" },
{ value: 1, label: "自定数据权限" },
{ value: 2, label: "本部门数据权限" },
{ value: 3, label: "本部门及以下数据权限" },
{ value: 4, label: "仅本人数据权限" },
]);
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
roleName: undefined,
roleCode: undefined,
isDeleted: undefined,
},
rules: {
roleName: [
{ required: true, message: "角色名称不能为空", trigger: "blur" },
],
roleCode: [
{ required: true, message: "权限字符不能为空", trigger: "blur" },
],
orderNum: [
{ required: true, message: "角色顺序不能为空", trigger: "blur" },
],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询角色列表 */
function getList() {
loading.value = true;
listRole(proxy.addDateRange(queryParams.value, dateRange.value)).then(
(response) => {
roleList.value = response.data.data;
total.value = response.data.total;
loading.value = false;
}
);
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 删除按钮操作 */
function handleDelete(row) {
const roleIds = row.id || ids.value;
proxy.$modal
.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?')
.then(function () {
return delRole(roleIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download(
"system/role/export",
{
...queryParams.value,
},
`role_${new Date().getTime()}.xlsx`
);
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 角色状态修改 */
function handleStatusChange(row) {
let text = row.isDeleted === false ? "启用" : "停用";
proxy.$modal
.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?')
.then(function () {
return changeRoleStatus(row.id, row.isDeleted);
})
.then(() => {
proxy.$modal.msgSuccess(text + "成功");
})
.catch(function () {
row.isDeleted = row.isDeleted === "0" ? "1" : "0";
});
}
/** 更多操作 */
function handleCommand(command, row) {
switch (command) {
case "handleDataScope":
handleDataScope(row);
break;
case "handleAuthUser":
handleAuthUser(row);
break;
default:
break;
}
}
/** 分配用户 */
function handleAuthUser(row) {
router.push("/system/role-auth/user/" + row.roleId);
}
/** 查询菜单树结构 */
function getMenuTreeselect() {
listMenu().then((response) => {
const options = [];
response.data.forEach((m) => {
options.push({
id: m.id,
label: m.menuName,
parentId: m.parentId,
children: m.children,
});
});
menuOptions.value = proxy.handleTree(options);
});
}
/** 所有部门节点数据 */
function getDeptAllCheckedKeys() {
// 目前被选中的部门节点
let checkedKeys = deptRef.value.getCheckedKeys();
// 半选中的部门节点
let halfCheckedKeys = deptRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
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 = {
role: {
id: undefined,
roleName: undefined,
roleCode: undefined,
orderNum: 0,
IsDeleted: false,
menuCheckStrictly: false,
deptCheckStrictly: false,
remark: undefined,
dataScope: 0,
},
menuIds: [],
deptIds: [],
};
proxy.resetForm("roleRef");
}
/** 添加角色 */
function handleAdd() {
reset();
getMenuTreeselect();
open.value = true;
title.value = "添加角色";
}
/** 修改角色 */
function handleUpdate(row) {
reset();
const roleId = row.id || ids.value;
getRoleMenuTreeselect(roleId);
getRole(roleId).then((response) => {
form.value.role = response.data;
form.value.role.orderNum = Number(form.value.role.orderNum);
open.value = true;
title.value = "修改角色";
});
}
/** 根据角色ID查询菜单树结构 */
function getRoleMenuTreeselect(roleId) {
//1获取该角色下的全部菜单id
//2获取全量菜单
getMenuTreeselect();
roleMenuTreeselect(roleId).then((response) => {
const menuIds = [];
response.data.forEach((m) => {
menuIds.push(m.id);
});
nextTick(() => {
menuIds.forEach((v) => {
menuRef.value.setChecked(v, true, false);
});
//这里是要一个当前用户已拥有的菜单的id
});
});
}
/** 根据角色ID查询部门树结构 */
function getDeptTree(roleId) {
return listDept().then((response) => {
const selectList = [];
response.data.forEach((res) => {
selectList.push({
id: res.id,
label: res.deptName,
parentId: res.parentId,
orderNum: res.orderNum,
children: [],
});
});
deptOptions.value = proxy.handleTree(selectList, "id");
let deptIds = [];
roleDeptTreeselect(roleId).then((response) => {
deptIds = response.data.map((x) => x.id);
// nextTick(() => {
if (deptRef.value) {
deptRef.value.setCheckedKeys(deptIds);
}
// });
});
});
}
/** 树权限(展开/折叠)*/
function handleCheckedTreeExpand(value, type) {
if (type == "menu") {
let treeList = menuOptions.value;
for (let i = 0; i < treeList.length; i++) {
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
} else if (type == "dept") {
let treeList = deptOptions.value;
for (let i = 0; i < treeList.length; i++) {
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
}
}
}
/** 树权限(全选/全不选) */
function handleCheckedTreeNodeAll(value, type) {
if (type == "menu") {
menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
} else if (type == "dept") {
deptRef.value.setCheckedNodes(value ? deptOptions.value : []);
}
}
/** 树权限(父子联动) */
function handleCheckedTreeConnect(value, type) {
if (type == "menu") {
form.value.menuCheckStrictly = value ? true : false;
} else if (type == "dept") {
form.value.deptCheckStrictly = value ? true : false;
}
}
/** 所有菜单节点数据 */
function getMenuAllCheckedKeys() {
// 目前被选中的菜单节点
let checkedKeys = menuRef.value.getCheckedKeys();
// 半选中的菜单节点
let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
return checkedKeys;
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["roleRef"].validate((valid) => {
if (valid) {
if (form.value.role.id != 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();
});
}
}
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 选择角色权限范围触发 */
function dataScopeSelectChange(value) {
if (value !== "2") {
deptRef.value.setCheckedKeys([]);
}
}
/** 分配数据权限操作 */
function handleDataScope(row) {
reset();
getDeptTree(row.id);
getRole(row.id).then((response) => {
form.value.role = response.data;
openDataScope.value = true;
title.value = "分配数据权限";
});
}
/** 提交按钮(数据权限) */
function submitDataScope() {
if (form.value.role.id != undefined) {
form.value.deptIds = getDeptAllCheckedKeys();
dataScope(form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
openDataScope.value = false;
getList();
});
}
}
/** 取消按钮(数据权限)*/
function cancelDataScope() {
openDataScope.value = false;
reset();
}
getList();
</script>

View File

@@ -0,0 +1,138 @@
<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
@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="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">
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
const props = defineProps({
roleId: {
type: [Number, String]
}
});
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const userList = ref([]);
const visible = ref(false);
const total = ref(0);
const userIds = ref([]);
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
roleId: undefined,
userName: undefined,
phonenumber: undefined
});
// 显示弹框
function show() {
queryParams.roleId = props.roleId;
getList();
visible.value = true;
}
/**选择行 */
function clickRow(row) {
proxy.$refs["refTable"].toggleRowSelection(row);
}
// 多选框选中数据
function handleSelectionChange(selection) {
userIds.value = selection.map(item => item.userId);
}
// 查询表数据
function getList() {
unallocatedUserList(queryParams).then(res => {
userList.value = res.rows;
total.value = res.total;
});
}
/** 搜索按钮操作 */
function 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");
}
});
}
defineExpose({
show,
});
</script>

View File

@@ -0,0 +1,112 @@
<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";
const route = useRoute();
const { proxy } = getCurrentInstance();
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({
nickName: undefined,
userName: undefined,
userId: undefined
});
/** 单击选中行数据 */
function clickRow(row) {
proxy.$refs["roleRef"].toggleRowSelection(row);
};
/** 多选框选中数据 */
function handleSelectionChange(selection) {
roleIds.value = selection.map(item => item.roleId);
};
/** 保存选中的数据编号 */
function getRowKey(row) {
return row.roleId;
};
/** 关闭按钮 */
function close() {
const obj = { path: "/system/user" };
proxy.$tab.closeOpenPage(obj);
};
/** 提交按钮 */
function submitForm() {
const userId = form.value.userId;
const rIds = roleIds.value.join(",");
updateAuthRole({ userId: userId, roleIds: rIds }).then(response => {
proxy.$modal.msgSuccess("授权成功");
close();
});
};
(() => {
const userId = route.params && route.params.userId;
if (userId) {
loading.value = true;
getAuthRole(userId).then(response => {
form.value = response.user;
roles.value = response.roles;
total.value = roles.value.length;
nextTick(() => {
roles.value.forEach(row => {
if (row.flag) {
proxy.$refs["roleRef"].toggleRowSelection(row);
}
});
});
loading.value = false;
});
}
})();
</script>

View File

@@ -0,0 +1,550 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<!--部门数据-->
<el-col :span="4" :xs="24">
<div class="head-container">
<el-input v-model="deptName" placeholder="请输入部门名称" clearable prefix-icon="Search"
style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="{ label: 'label', children: 'children' }"
:expand-on-click-node="false" :filter-node-method="filterNode" ref="deptTreeRef" highlight-current
default-expand-all @node-click="handleNodeClick" />
</div>
</el-col>
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<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="phone">
<el-input v-model="queryParams.phone" placeholder="请输入手机号码" clearable style="width: 240px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="isDeleted">
<el-select v-model="queryParams.isDeleted" 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="结束日期"></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:user:add']">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
v-hasPermi="['system:user:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
v-hasPermi="['system:user:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">
导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['system:user:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="id" prop="id" v-if="columns[0].visible" />
<el-table-column label="用户账号" align="center" key="userName" prop="userName" v-if="columns[1].visible"
:show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nick" prop="nick" v-if="columns[2].visible"
:show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="dept.deptName" prop="dept.deptName" v-if="columns[3].visible"
:show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phone" prop="phone" v-if="columns[4].visible"
width="120" />
<el-table-column label="状态" align="isDeleted" key="isDeleted" v-if="columns[5].visible">
<template #default="scope">
<el-switch v-model="scope.row.isDeleted" :active-value=false :inactive-value=true
@change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
<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" v-if="scope.row.userName != 'cc'">
<el-button type="text" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top" v-if="scope.row.userName != 'cc'">
<el-button type="text" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']"></el-button>
</el-tooltip>
<el-tooltip content="重置密码" placement="top" v-if="scope.row.userName != 'cc'">
<el-button type="text" icon="Key" @click="handleResetPwd(scope.row)"
v-hasPermi="['system:user:resetPwd']"></el-button>
</el-tooltip>
<el-tooltip content="分配角色" placement="top" v-if="scope.row.userName != 'cc'">
<el-button type="text" icon="CircleCheck" @click="handleAuthRole(scope.row)"
v-hasPermi="['system:user: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-col>
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
<el-form :model="form.user" :rules="rules" ref="userRef" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nick">
<el-input v-model="form.user.nick" placeholder="请输入用户昵称" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<el-tree-select v-model="form.deptId" :data="deptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" value-key="id"
placeholder="请选择归属部门" check-strictly />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phone">
<el-input v-model="form.user.phone" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.user.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="form.id == undefined" label="用户账号" prop="userName">
<el-input v-model="form.user.userName" placeholder="请输入用户账号" maxlength="30" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.id == undefined" label="用户密码" prop="password">
<el-input v-model="form.user.password" placeholder="请输入用户密码" type="password" maxlength="20"
show-password />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.user.sex" placeholder="请选择">
<el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="JSON.parse(dict.value) "></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.user.isDeleted">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="JSON.parse(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option v-for="item in postOptions" :key="item.id" :label="item.postName"
:value="item.id" :disabled="item.isDeleted == true"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择">
<el-option v-for="item in roleOptions" :key="item.id" :label="item.roleName" :value="item.id"
:disabled="item.isDeleted ==true"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.user.remark" type="textarea" placeholder="请输入内容"></el-input>
</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>
<!-- 用户导入对话框 -->
<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" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<el-icon class="el-icon--upload">
<upload-filled />
</el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip text-center">
<!-- <div class="el-upload__tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
</div> -->
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
@click="importTemplate">下载模板</el-link>
</div>
</template>
</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>
<script setup name="User">
import { getToken } from "@/utils/auth";
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser } from "@/api/system/user";
import { roleOptionselect } from "@/api/system/role";
import { postOptionselect } from "@/api/system/post";
import { listDept } from "@/api/system/dept";
const router = useRouter();
const { proxy } = getCurrentInstance();
const { sys_normal_disable, sys_user_sex } = proxy.useDict("sys_normal_disable", "sys_user_sex");
const userList = 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 deptName = ref("");
const deptOptions = ref(undefined);
const initPassword = ref(undefined);
const postOptions = ref([]);
const roleOptions = ref([]);
/*** 用户导入参数 */
const upload = reactive({
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "/user/import"
});
// 列显隐信息
const columns = ref([
{ key: 0, label: `用户编号`, visible: true },
{ key: 1, label: `用户名称`, visible: true },
{ key: 2, label: `用户昵称`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true }
]);
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phone: undefined,
isDeleted: undefined,
deptId: undefined
},
rules: {
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
nick: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
// password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }],
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 filterNode = (value, data) => {
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
/** 根据名称筛选部门树 */
watch(deptName, val => {
proxy.$refs["deptTreeRef"].filter(val);
});
/** 查询部门下拉树结构 */
function getDeptTree() {
listDept().then(response => {
const selectList = [];
response.data.forEach(res => {
selectList.push({ id: res.id, label: res.deptName, parentId: res.parentId, orderNum: res.orderNum, children: [] })
}
)
deptOptions.value = proxy.handleTree(selectList, "id");;
});
};
/** 查询用户列表 */
function getList() {
loading.value = true;
listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(res => {
loading.value = false;
userList.value = res.data.data;
total.value = res.data.total;
});
};
/** 节点单击事件 */
function handleNodeClick(data) {
queryParams.value.deptId = data.id;
handleQuery();
};
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
// console.log(proxy.$refs["deptTreeRef"])
queryParams.value.deptId=undefined;
handleQuery();
};
/** 删除按钮操作 */
function handleDelete(row) {
const userIds = row.id || ids.value;
proxy.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
return delUser(userIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
};
/** 导出按钮操作 */
function handleExport() {
proxy.download("user/export");
};
/** 用户状态修改 */
function handleStatusChange(row) {
console.log(row)
let text = row.isDeleted === false ? "启用" : "停用";
proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
return changeUserStatus(row.id, row.isDeleted);
}).then(() => {
proxy.$modal.msgSuccess(text + "成功");
}).catch(function () {
row.isDeleted = row.isDeleted === true ? false : true;
});
};
/** 更多操作 */
function handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
handleResetPwd(row);
break;
case "handleAuthRole":
handleAuthRole(row);
break;
default:
break;
}
};
/** 跳转角色分配 */
function handleAuthRole(row) {
const userId = row.id;
router.push("/system/user-auth/role/" + userId);
};
/** 重置密码按钮操作 */
function handleResetPwd(row) {
proxy.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
}).then(({ value }) => {
resetUserPwd(row.id, value).then(response => {
proxy.$modal.msgSuccess("修改成功,新密码是:" + value);
});
}).catch(() => { });
};
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 导入按钮操作 */
function handleImport() {
upload.title = "用户导入";
upload.open = true;
};
/** 下载模板操作 */
function importTemplate() {
proxy.download("user/template");
};
/**文件上传中处理 */
const handleFileUploadProgress = (event, file, fileList) => {
upload.isUploading = true;
};
/** 文件上传成功处理 */
const handleFileSuccess = (response, file, fileList) => {
upload.open = false;
upload.isUploading = false;
proxy.$refs["uploadRef"].handleRemove(file);
proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
getList();
};
/** 提交上传文件 */
function submitFileForm() {
proxy.$refs["uploadRef"].submit();
};
/** 重置操作表单 */
function reset() {
form.value = {
user: {
userName: undefined,
nick: undefined,
password: undefined,
phone: undefined,
email: undefined,
sex: undefined,
isDeleted: false,
remark: undefined,
},
postIds: [],
roleIds: [],
deptId: undefined
};
proxy.resetForm("userRef");
if (postOptions.value.length == 0 || roleOptions.value.length == 0) {
roleOptionselect().then(response => {
//岗位从另一个接口获取全量
roleOptions.value = response.data;
})
postOptionselect().then(response => {
postOptions.value = response.data;
}
)
}
};
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
};
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加用户";
};
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const userId = row.id || ids.value;
getUser(userId).then(response => {
form.value.user = response.data;
response.data.posts.forEach(post => {
form.value.postIds.push(post.id)
});
form.value.deptId= response.data.deptId;
response.data.roles.forEach(role => {
form.value.roleIds.push(role.id)
});
open.value = true;
title.value = "修改用户";
form.value.user.password = null;
});
};
/** 提交按钮 */
function submitForm() {
proxy.$refs["userRef"].validate(valid => {
if (valid) {
if (form.value.user.id != undefined) {
updateUser(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addUser(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
};
getDeptTree();
getList();
</script>

View File

@@ -0,0 +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.phone }}</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.dept">{{ state.dept.deptName }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="peoples" />所属角色
<div class="pull-right"><span v-for="role in state.roles" :key="role.id">{{ role.roleName }} /</span></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";
import { getUserProfile } from "@/api/system/user";
const activeTab = ref("userinfo");
const state = reactive({
user: {},
dept: {},
roles: [],
roleGroup: {},
postGroup: {}
});
function getUser() {
getUserProfile().then(response => {
state.user = response.data.user;
state.dept=response.data.dept;
state.roles=response.data.roles;
state.roleGroup = response.roleGroup;
state.postGroup = response.postGroup;
});
};
getUser();
</script>

View File

@@ -0,0 +1,57 @@
<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>
import { updateUserPwd } from "@/api/system/user";
const { proxy } = getCurrentInstance();
const user = reactive({
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
});
const equalToPassword = (rule, value, callback) => {
if (user.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
});
/** 提交按钮 */
function submit() {
proxy.$refs.pwdRef.validate(valid => {
if (valid) {
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
proxy.$modal.msgSuccess("修改成功");
});
}
});
};
/** 关闭按钮 */
function close() {
proxy.$tab.closePage();
};
</script>

View File

@@ -0,0 +1,175 @@
<template>
<div class="user-info-head" @click="editCropper()"><img :src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
<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"
@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>
</template>
<script setup>
import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";
import { upload } from "@/api/file";
import { updateUserProfile } from "@/api/system/user";
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const { proxy } = getCurrentInstance();
const open = ref(false);
const visible = ref(false);
const title = ref("修改头像");
//图片裁剪数据
const options = reactive({
img: userStore.avatar, // 裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
previews: {} //预览数据
});
/** 编辑头像 */
function editCropper() {
open.value = true;
};
/** 打开弹出层结束时的回调 */
function modalOpened() {
visible.value = true;
};
/** 覆盖默认上传行为 */
function requestUpload() {
};
/** 向左旋转 */
function rotateLeft() {
proxy.$refs.cropper.rotateLeft();
};
/** 向右旋转 */
function rotateRight() {
proxy.$refs.cropper.rotateRight();
};
/** 图片缩放 */
function changeScale(num) {
num = num || 1;
proxy.$refs.cropper.changeScale(num);
};
/** 上传预处理 */
function beforeUpload(file) {
if (file.type.indexOf("image/") == -1) {
proxy.$modal.msgError("文件格式错误,请上传图片类型,如JPGPNG后缀的文件。");
} else {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
options.img = reader.result;
};
}
};
/** 上传图片 */
function uploadImg() {
proxy.$refs.cropper.getCropBlob(data => {
let formData = new FormData();
formData.append("file", data);
upload("image",formData).then(response => {
open.value = false;
options.img = import.meta.env.VITE_APP_BASE_API +"/file/"+response.data[0];
userStore.avatar = options.img;
updateUserProfile({icon:response.data[0]}).then(response2=>{
proxy.$modal.msgSuccess("修改成功");
visible.value = false;
})
});
});
};
/** 实时预览 */
function realTime(data) {
options.previews = data;
};
/** 关闭窗口 */
function closeDialog() {
options.img = userStore.avatar;
options.visible = false;
};
</script>
<style lang='scss' scoped>
.user-info-head {
position: relative;
display: inline-block;
height: 120px;
}
.user-info-head:hover:after {
content: "+";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
border-radius: 50%;
}
</style>

View File

@@ -0,0 +1,56 @@
<template>
<el-form ref="userRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="user.nick" maxlength="30" />
</el-form-item>
<el-form-item label="手机号码" prop="phone">
<el-input v-model="user.phone" 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>
import { updateUserProfile } from "@/api/system/user";
const props = defineProps({
user: {
type: Object
}
});
const { proxy } = getCurrentInstance();
const rules = ref({
nick: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phone: [{ 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 => {
if (valid) {
updateUserProfile(props.user).then(response => {
proxy.$modal.msgSuccess("修改成功");
});
}
});
};
/** 关闭按钮 */
function close() {
proxy.$tab.closePage();
};
</script>

View File

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

View File

@@ -0,0 +1,48 @@
<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>
defineProps({
info: {
type: Object,
default: null
}
});
// 表单校验
const rules = ref({
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
});
</script>

View File

@@ -0,0 +1,198 @@
<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" 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" 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" 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" 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="GTE" />
<el-option label="<" value="LT" />
<el-option label="<=" value="LTE" />
<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" 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";
const route = useRoute();
const { proxy } = getCurrentInstance();
const activeName = ref("columnInfo");
const tableHeight = ref(document.documentElement.scrollHeight - 245 + "px");
const tables = ref([]);
const columns = ref([]);
const dictOptions = ref([]);
const info = ref({});
/** 提交按钮 */
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 validateResult = res.every(item => !!item);
if (validateResult) {
const genTable = Object.assign({}, info.value);
genTable.columns = columns.value;
genTable.params = {
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();
}
});
} else {
proxy.$modal.msgError("表单校验未通过,请重新检查提交内容");
}
});
}
function getFormPromise(form) {
return new Promise(resolve => {
form.validate(res => {
resolve(res);
});
});
}
function close() {
const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: route.query.pageNum } };
proxy.$tab.closeOpenPage(obj);
}
(() => {
const tableId = route.params && route.params.tableId;
if (tableId) {
// 获取表详细信息
getGenTable(tableId).then(res => {
columns.value = res.data.rows;
info.value = res.data.info;
tables.value = res.data.tables;
});
/** 查询字典下拉列表 */
getDictOptionselect().then(response => {
dictOptions.value = response.data;
});
}
})();
</script>

View File

@@ -0,0 +1,281 @@
<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-option label="主子表(增删改查)" value="sub" />
</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="info.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="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 props = defineProps({
info: {
type: Object,
default: null
},
tables: {
type: Array,
default: null
}
});
// 表单校验
const rules = ref({
tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
packageName: [{ required: true, message: "请输入生成包路径", trigger: "blur" }],
moduleName: [{ required: true, message: "请输入生成模块名", trigger: "blur" }],
businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
});
function subSelectChange(value) {
props.info.subTableFkName = "";
}
function tplSelectChange(value) {
if (value !== "sub") {
props.info.subTableName = "";
props.info.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;
}
}
}
/** 查询菜单下拉树结构 */
function getMenuTreeselect() {
listMenu().then(response => {
menuOptions.value = proxy.handleTree(response.data, "menuId");
});
}
watch(() => props.info.subTableName, val => {
setSubTableColumns(val);
});
getMenuTreeselect();
</script>

View File

@@ -0,0 +1,118 @@
<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";
const total = ref(0);
const visible = ref(false);
const tables = ref([]);
const dbTableList = ref([]);
const { proxy } = getCurrentInstance();
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
});
const emit = defineEmits(["ok"]);
/** 查询参数列表 */
function show() {
getList();
visible.value = true;
}
/** 单击选择行 */
function clickRow(row) {
proxy.$refs.table.toggleRowSelection(row);
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
tables.value = selection.map(item => item.tableName);
}
/** 查询表数据 */
function getList() {
listDbTable(queryParams).then(res => {
dbTableList.value = res.rows;
total.value = res.total;
});
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 导入按钮操作 */
function handleImportTable() {
const tableNames = tables.value.join(",");
if (tableNames == "") {
proxy.$modal.msgError("请选择要导入的表");
return;
}
importTable({ tables: tableNames }).then(res => {
proxy.$modal.msgSuccess(res.msg);
if (res.code === 200) {
visible.value = false;
emit("ok");
}
});
}
defineExpose({
show,
});
</script>

View File

@@ -0,0 +1,306 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<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 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
type="text"
icon="View"
@click="handlePreview(scope.row)"
v-hasPermi="['tool:gen:preview']"
></el-button>
</el-tooltip>
<el-tooltip content="编辑" placement="top">
<el-button
type="text"
icon="Edit"
@click="handleEditTable(scope.row)"
v-hasPermi="['tool:gen:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['tool:gen:remove']"
></el-button>
</el-tooltip>
<el-tooltip content="同步" placement="top">
<el-button
type="text"
icon="Refresh"
@click="handleSynchDb(scope.row)"
v-hasPermi="['tool:gen:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="生成代码" placement="top">
<el-button
type="text"
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 custom-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";
const route = useRoute();
const { proxy } = getCurrentInstance();
const tableList = ref([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const tableNames = ref([]);
const dateRange = ref([]);
const uniqueId = ref("");
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
},
preview: {
open: false,
title: "代码预览",
data: {},
activeName: "domain.java"
}
});
const { queryParams, preview } = toRefs(data);
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();
}
})
/** 查询表集合 */
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;
});
}
/** 搜索按钮操作 */
function handleQuery() {
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");
}
}
/** 同步数据库操作 */
function handleSynchDb(row) {
const tableName = row.tableName;
proxy.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function () {
return synchDb(tableName);
}).then(() => {
proxy.$modal.msgSuccess("同步成功");
}).catch(() => {});
}
/** 打开导入表弹窗 */
function openImportTable() {
proxy.$refs["importRef"].show();
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = [];
proxy.resetForm("queryRef");
handleQuery();
}
/** 预览按钮 */
function handlePreview(row) {
previewTable(row.tableId).then(response => {
preview.value.data = response.data;
preview.value.open = true;
preview.value.activeName = "domain.java";
});
}
/** 复制代码成功 */
function 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;
}
/** 修改按钮操作 */
function handleEditTable(row) {
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(() => {});
}
getList();
</script>

View File

@@ -0,0 +1,9 @@
<template>
<i-frame v-model:src="url"></i-frame>
</template>
<script setup>
import iFrame from '@/components/iFrame'
const url = ref(import.meta.env.VITE_APP_BASE_API + "/swagger-ui/index.html")
</script>