feat/1
This commit is contained in:
parent
3f5d2314a9
commit
b85428ddea
|
|
@ -0,0 +1,414 @@
|
|||
<template>
|
||||
<div class="access-dashboard">
|
||||
<!-- 设备卡片网格 -->
|
||||
<el-row :gutter="24" class="devices-grid">
|
||||
<el-col
|
||||
v-for="(device, index) in displayedDevices"
|
||||
:key="device.id"
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="6"
|
||||
>
|
||||
<!-- 设备卡片:根据状态显示不同样式 -->
|
||||
<el-card
|
||||
class="device-card"
|
||||
:class="{
|
||||
'status-on': device.status === '开启' && !device.isFault,
|
||||
'status-off': device.status === '关闭' && !device.isFault,
|
||||
'status-fault': device.isFault,
|
||||
}"
|
||||
shadow="hover"
|
||||
>
|
||||
<!-- 故障标签 -->
|
||||
<div class="device-badge" v-if="device.isFault">
|
||||
<el-tag type="danger" size="small">故障</el-tag>
|
||||
</div>
|
||||
|
||||
<div class="device-info">
|
||||
<h3 class="device-name">{{ device.name }}</h3>
|
||||
<div class="info-row">
|
||||
<span class="info-label">运行状态:</span>
|
||||
<span class="info-value" :class="getTextClass(device)">
|
||||
{{ device.status }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">设备类型:</span>
|
||||
<span class="info-value">{{ device.type }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">安装位置:</span>
|
||||
<span class="info-value">{{ device.position }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">最近操作:</span>
|
||||
<span class="info-value">{{ device.lastOperation }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="device-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleTurnOn(device)"
|
||||
:disabled="device.status === '开启' || device.isFault"
|
||||
class="control-btn"
|
||||
>
|
||||
<i class="el-icon-unlock"></i> 开启
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleTurnOff(device)"
|
||||
:disabled="device.status === '关闭'"
|
||||
class="control-btn"
|
||||
>
|
||||
<i class="el-icon-lock"></i> 关闭
|
||||
</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<div v-if="displayedDevices.length === 0" class="empty-state">
|
||||
<el-empty description="暂无门禁设备数据"></el-empty>
|
||||
</div>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="totalDevices"
|
||||
:page-size.sync="pageSize"
|
||||
:current-page.sync="currentPage"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:page-sizes="[6, 12, 18, 24]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
export default {
|
||||
name: "AccessControlSystem",
|
||||
setup() {
|
||||
const allDevices = ref([])
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(12)
|
||||
const searchQuery = ref("")
|
||||
|
||||
// 过滤后的设备列表
|
||||
const filteredDevices = computed(() => {
|
||||
if (!searchQuery.value) return allDevices.value
|
||||
const query = searchQuery.value.toLowerCase()
|
||||
return allDevices.value.filter(
|
||||
(device) =>
|
||||
device.name.toLowerCase().includes(query) ||
|
||||
device.position.toLowerCase().includes(query)
|
||||
)
|
||||
})
|
||||
|
||||
// 当前页显示的设备
|
||||
const displayedDevices = computed(() => {
|
||||
const start = (currentPage.value - 1) * pageSize.value
|
||||
const end = start + pageSize.value
|
||||
return filteredDevices.value.slice(start, end)
|
||||
})
|
||||
|
||||
// 总设备数
|
||||
const totalDevices = computed(() => {
|
||||
return filteredDevices.value.length
|
||||
})
|
||||
|
||||
// 状态统计
|
||||
const onlineCount = computed(() => {
|
||||
return allDevices.value.filter((d) => d.status === "开启" && !d.isFault)
|
||||
.length
|
||||
})
|
||||
|
||||
const offlineCount = computed(() => {
|
||||
return allDevices.value.filter((d) => d.status === "关闭" && !d.isFault)
|
||||
.length
|
||||
})
|
||||
|
||||
const faultCount = computed(() => {
|
||||
return allDevices.value.filter((d) => d.isFault).length
|
||||
})
|
||||
|
||||
// 获取文字状态类名
|
||||
const getTextClass = (device) => {
|
||||
if (device.isFault) return "text-fault"
|
||||
return device.status === "开启" ? "text-on" : "text-off"
|
||||
}
|
||||
|
||||
// 初始化设备数据
|
||||
const initDevices = () => {
|
||||
// 生成44条模拟数据
|
||||
allDevices.value = Array.from({ length: 44 }, (_, i) => {
|
||||
const isFault = Math.random() > 0.85 // 15%概率故障
|
||||
const status = isFault ? "关闭" : Math.random() > 0.3 ? "开启" : "关闭"
|
||||
const operations = [
|
||||
"无操作",
|
||||
"刷卡进入",
|
||||
"密码解锁",
|
||||
"远程开启",
|
||||
"手动开启",
|
||||
]
|
||||
|
||||
return {
|
||||
id: i + 1,
|
||||
name: `Door-${String(i + 1).padStart(2, "0")}`,
|
||||
status,
|
||||
type: ["门禁一体机", "电磁锁", "指纹门禁", "人脸识别"][
|
||||
Math.floor(Math.random() * 4)
|
||||
],
|
||||
position: `区域${String.fromCharCode(65 + Math.floor(i / 10))}-${
|
||||
(i % 10) + 1
|
||||
}入口`,
|
||||
lastOperation:
|
||||
operations[Math.floor(Math.random() * operations.length)],
|
||||
isFault,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新设备数据
|
||||
const refreshDevices = () => {
|
||||
initDevices()
|
||||
ElMessage.success("门禁设备数据已刷新")
|
||||
}
|
||||
|
||||
// 处理页面大小变化
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
// 处理页码变化
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val
|
||||
}
|
||||
|
||||
// 开启设备
|
||||
const handleTurnOn = (device) => {
|
||||
ElMessageBox.confirm("确认开启?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning", // 弹窗类型(warning/info/success/error)
|
||||
}).then(() => {
|
||||
device.status = "开启"
|
||||
device.lastOperation = "远程开启"
|
||||
ElMessage.success(`门禁 ${device.name} 已开启`)
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭设备
|
||||
const handleTurnOff = (device) => {
|
||||
ElMessageBox.confirm("确认关闭?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning", // 弹窗类型(warning/info/success/error)
|
||||
}).then(() => {
|
||||
device.status = "关闭"
|
||||
device.lastOperation = "远程关闭"
|
||||
ElMessage.success(`门禁 ${device.name} 已关闭`)
|
||||
})
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (device) => {
|
||||
ElMessage.info(`查看 ${device.name} 详情`)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initDevices()
|
||||
})
|
||||
|
||||
return {
|
||||
allDevices,
|
||||
currentPage,
|
||||
pageSize,
|
||||
searchQuery,
|
||||
filteredDevices,
|
||||
displayedDevices,
|
||||
totalDevices,
|
||||
onlineCount,
|
||||
offlineCount,
|
||||
faultCount,
|
||||
getTextClass,
|
||||
initDevices,
|
||||
refreshDevices,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
handleTurnOn,
|
||||
handleTurnOff,
|
||||
handleDetail
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面基础样式 - 与给排水系统保持一致 */
|
||||
.access-dashboard {
|
||||
padding: 20px;
|
||||
background-color: #f8fafc;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 设备网格 */
|
||||
.devices-grid {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
/* 设备卡片样式 */
|
||||
.device-card {
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
margin-bottom: 24px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 不同状态的卡片样式 */
|
||||
.status-on {
|
||||
background-color: #f0fff4;
|
||||
border-top: 3px solid #48bb78;
|
||||
}
|
||||
|
||||
.status-off {
|
||||
background-color: #edf2f7;
|
||||
border-top: 3px solid #a0aec0;
|
||||
}
|
||||
|
||||
.status-fault {
|
||||
background-color: #fff5f5;
|
||||
border-top: 3px solid #fc8181;
|
||||
}
|
||||
|
||||
.device-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 故障标签位置 */
|
||||
.device-badge {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 设备信息区域 */
|
||||
.device-info {
|
||||
padding: 16px 16px 12px;
|
||||
}
|
||||
|
||||
.device-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin: 0 0 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px dashed #e2e8f0;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #64748b;
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #334155;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 状态文字颜色 */
|
||||
.text-on {
|
||||
color: #48bb78;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.text-off {
|
||||
color: #a0aec0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.text-fault {
|
||||
color: #fc8181;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 设备操作按钮 */
|
||||
.device-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-top: 1px solid #f1f5f9;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.detail-btn {
|
||||
color: #3b82f6;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.detail-btn:hover {
|
||||
color: #2563eb;
|
||||
}
|
||||
|
||||
/* 空状态和分页 */
|
||||
.empty-state {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
width: 70px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -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 style="width: 240px">
|
||||
<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="configId" />
|
||||
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="系统内置" align="center" prop="configType">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_yes_no" :value="scope.row.configType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:config:edit']" >修改</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:config:remove']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="configRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="参数名称" prop="configName">
|
||||
<el-input v-model="form.configName" placeholder="请输入参数名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参数键名" prop="configKey">
|
||||
<el-input v-model="form.configKey" placeholder="请输入参数键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参数键值" prop="configValue">
|
||||
<el-input v-model="form.configValue" type="textarea" 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"
|
||||
:value="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.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
configId: undefined,
|
||||
configName: undefined,
|
||||
configKey: undefined,
|
||||
configValue: undefined,
|
||||
configType: "Y",
|
||||
remark: undefined
|
||||
}
|
||||
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.configId)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset()
|
||||
open.value = true
|
||||
title.value = "添加参数"
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset()
|
||||
const configId = row.configId || 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.configId != undefined) {
|
||||
updateConfig(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addConfig(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const configIds = row.configId || 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>
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input
|
||||
v-model="queryParams.deptName"
|
||||
placeholder="请输入部门名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="部门状态" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<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="deptId"
|
||||
:default-expand-all="isExpandAll"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']">新增</el-button>
|
||||
<el-button v-if="scope.row.parentId != 0" link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 添加或修改部门对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
|
||||
<el-form ref="deptRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="24" v-if="form.parentId !== 0">
|
||||
<el-form-item label="上级部门" prop="parentId">
|
||||
<el-tree-select
|
||||
v-model="form.parentId"
|
||||
:data="deptOptions"
|
||||
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
||||
value-key="deptId"
|
||||
placeholder="选择上级部门"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input v-model="form.deptName" placeholder="请输入部门名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="显示排序" prop="orderNum">
|
||||
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="负责人" prop="leader">
|
||||
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="部门状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="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, listDeptExcludeChild } 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,
|
||||
status: 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, "deptId")
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
deptId: undefined,
|
||||
parentId: undefined,
|
||||
deptName: undefined,
|
||||
orderNum: 0,
|
||||
leader: undefined,
|
||||
phone: undefined,
|
||||
email: undefined,
|
||||
status: "0"
|
||||
}
|
||||
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")
|
||||
})
|
||||
if (row != undefined) {
|
||||
form.value.parentId = row.deptId
|
||||
}
|
||||
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")
|
||||
})
|
||||
getDept(row.deptId).then(response => {
|
||||
form.value = response.data
|
||||
open.value = true
|
||||
title.value = "修改部门"
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["deptRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.deptId != undefined) {
|
||||
updateDept(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addDept(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
proxy.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
|
||||
return delDept(row.deptId)
|
||||
}).then(() => {
|
||||
getList()
|
||||
proxy.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
getList()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="字典名称" prop="dictType">
|
||||
<el-select v-model="queryParams.dictType" style="width: 200px">
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.dictId"
|
||||
:label="item.dictName"
|
||||
:value="item.dictType"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="字典标签" prop="dictLabel">
|
||||
<el-input
|
||||
v-model="queryParams.dictLabel"
|
||||
placeholder="请输入字典标签"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:dict:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Edit"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['system:dict:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['system:dict:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:dict:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Close"
|
||||
@click="handleClose"
|
||||
>关闭</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="字典编码" align="center" prop="dictCode" />
|
||||
<el-table-column label="字典标签" align="center" prop="dictLabel">
|
||||
<template #default="scope">
|
||||
<span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
|
||||
<el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字典键值" align="center" prop="dictValue" />
|
||||
<el-table-column label="字典排序" align="center" prop="dictSort" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="dataRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="字典类型">
|
||||
<el-input v-model="form.dictType" :disabled="true" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数据标签" prop="dictLabel">
|
||||
<el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数据键值" prop="dictValue">
|
||||
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="样式属性" prop="cssClass">
|
||||
<el-input v-model="form.cssClass" placeholder="请输入样式属性" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示排序" prop="dictSort">
|
||||
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="回显样式" prop="listClass">
|
||||
<el-select v-model="form.listClass">
|
||||
<el-option
|
||||
v-for="item in listClassOptions"
|
||||
:key="item.value"
|
||||
:label="item.label + '(' + item.value + ')'"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="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,
|
||||
dictType: undefined,
|
||||
dictLabel: undefined,
|
||||
status: undefined
|
||||
},
|
||||
rules: {
|
||||
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
|
||||
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
|
||||
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
|
||||
}
|
||||
})
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data)
|
||||
|
||||
/** 查询字典类型详细 */
|
||||
function getTypes(dictId) {
|
||||
getType(dictId).then(response => {
|
||||
queryParams.value.dictType = response.data.dictType
|
||||
defaultDictType.value = response.data.dictType
|
||||
getList()
|
||||
})
|
||||
}
|
||||
|
||||
/** 查询字典类型列表 */
|
||||
function getTypeList() {
|
||||
getDictOptionselect().then(response => {
|
||||
typeOptions.value = response.data
|
||||
})
|
||||
}
|
||||
|
||||
/** 查询字典数据列表 */
|
||||
function getList() {
|
||||
loading.value = true
|
||||
listData(queryParams.value).then(response => {
|
||||
dataList.value = response.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
dictCode: undefined,
|
||||
dictLabel: undefined,
|
||||
dictValue: undefined,
|
||||
cssClass: undefined,
|
||||
listClass: "default",
|
||||
dictSort: 0,
|
||||
status: "0",
|
||||
remark: undefined
|
||||
}
|
||||
proxy.resetForm("dataRef")
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
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.value
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset()
|
||||
open.value = true
|
||||
title.value = "添加字典数据"
|
||||
form.value.dictType = queryParams.value.dictType
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.dictCode)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset()
|
||||
const dictCode = row.dictCode || ids.value
|
||||
getData(dictCode).then(response => {
|
||||
form.value = response.data
|
||||
open.value = true
|
||||
title.value = "修改字典数据"
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["dataRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.dictCode != undefined) {
|
||||
updateData(form.value).then(response => {
|
||||
useDictStore().removeDict(queryParams.value.dictType)
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addData(form.value).then(response => {
|
||||
useDictStore().removeDict(queryParams.value.dictType)
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const dictCodes = row.dictCode || ids.value
|
||||
proxy.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
|
||||
return delData(dictCodes)
|
||||
}).then(() => {
|
||||
getList()
|
||||
proxy.$modal.msgSuccess("删除成功")
|
||||
useDictStore().removeDict(queryParams.value.dictType)
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download("system/dict/data/export", {
|
||||
...queryParams.value
|
||||
}, `dict_data_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
getTypes(route.params && route.params.dictId)
|
||||
getTypeList()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="字典名称" prop="dictName">
|
||||
<el-input
|
||||
v-model="queryParams.dictName"
|
||||
placeholder="请输入字典名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="字典类型" prop="dictType">
|
||||
<el-input
|
||||
v-model="queryParams.dictType"
|
||||
placeholder="请输入字典类型"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="字典状态"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" style="width: 308px">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
value-format="YYYY-MM-DD"
|
||||
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="dictId" />
|
||||
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
<router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
|
||||
<span>{{ scope.row.dictType }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="dictRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="字典名称" prop="dictName">
|
||||
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典类型" prop="dictType">
|
||||
<el-input v-model="form.dictType" placeholder="请输入字典类型" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="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,
|
||||
status: undefined
|
||||
},
|
||||
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.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
dictId: undefined,
|
||||
dictName: undefined,
|
||||
dictType: undefined,
|
||||
status: "0",
|
||||
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.dictId)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset()
|
||||
const dictId = row.dictId || ids.value
|
||||
getType(dictId).then(response => {
|
||||
form.value = response.data
|
||||
open.value = true
|
||||
title.value = "修改字典类型"
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["dictRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.dictId != undefined) {
|
||||
updateType(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addType(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const dictIds = row.dictId || 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>
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
<template>
|
||||
<div class="operation-record-page">
|
||||
<!-- 卡片容器:悬浮阴影 + 圆角优化 -->
|
||||
<el-card class="page-card" shadow="hover">
|
||||
<!-- 搜索表单区域 -->
|
||||
<el-form inline :model="searchForm" class="search-form">
|
||||
<el-form-item label="账号:">
|
||||
<el-input
|
||||
v-model="searchForm.accountName"
|
||||
placeholder="请输入账号或姓名"
|
||||
clearable
|
||||
style="width: 140px;"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分区:">
|
||||
<el-input
|
||||
v-model="searchForm.area"
|
||||
placeholder="请输入分区"
|
||||
clearable
|
||||
style="width: 140px;"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="舱室:">
|
||||
<el-input
|
||||
v-model="searchForm.cabin"
|
||||
placeholder="请输入舱室"
|
||||
clearable
|
||||
style="width: 140px;"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备:">
|
||||
<el-input
|
||||
v-model="searchForm.device"
|
||||
placeholder="请输入设备"
|
||||
clearable
|
||||
style="width: 140px;"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始时间:" style="width: 220px;">
|
||||
<el-date-picker
|
||||
v-model="searchForm.startTime"
|
||||
type="date"
|
||||
placeholder="选择开始日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间:" style="width: 220px;">
|
||||
<el-date-picker
|
||||
v-model="searchForm.endTime"
|
||||
type="date"
|
||||
placeholder="选择结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作记录表格:边框 + 斑马纹 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:header-cell-style="headerStyle"
|
||||
border
|
||||
stripe
|
||||
class="record-table"
|
||||
>
|
||||
<el-table-column
|
||||
prop="account"
|
||||
label="账号"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="姓名"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="area"
|
||||
label="分区"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="cabin"
|
||||
label="舱室"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="device"
|
||||
label="设备"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="operation"
|
||||
label="操作"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="time"
|
||||
label="时间"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, toRefs } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
// 搜索表单数据
|
||||
const searchForm = reactive({
|
||||
accountName: '', // 账号、姓名
|
||||
area: '', // 分区
|
||||
cabin: '', // 舱室
|
||||
device: '', // 设备
|
||||
startTime: '2025-09-09', // 开始时间(原型默认值)
|
||||
endTime: '2025-10-09', // 结束时间(原型默认值)
|
||||
});
|
||||
|
||||
// 分页参数
|
||||
const total = ref(11); // 原型中总记录数为11
|
||||
const queryParams = reactive({
|
||||
pageNum: 1, // 当前页码
|
||||
pageSize: 10, // 每页条数
|
||||
});
|
||||
|
||||
// 表头样式(保持清新浅蓝主题)
|
||||
const headerStyle = {
|
||||
backgroundColor: '#f0f9ff',
|
||||
color: '#409eff',
|
||||
fontWeight: '500',
|
||||
};
|
||||
|
||||
// 模拟操作记录表格数据(与原型一致)
|
||||
const tableData = ref([
|
||||
{ account: 'admin', name: '管理员', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '开', time: '2025-10-09 08:37:53' },
|
||||
{ account: '系统', name: '联动控制', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '开', time: '2025-10-09 08:34:49' },
|
||||
{ account: '系统', name: '联动控制', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '关', time: '2025-10-09 08:33:34' },
|
||||
{ account: '系统', name: '联动控制', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '关', time: '2025-10-09 08:32:02' },
|
||||
{ account: '系统', name: '联动控制', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '开', time: '2025-10-09 08:31:36' },
|
||||
{ account: 'admin', name: '管理员', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '开', time: '2025-09-30 16:11:34' },
|
||||
{ account: '系统', name: '', area: '分区1', cabin: '燃气舱', device: '燃气舱排水泵', operation: '开', time: '2025-09-30 16:01:24' },
|
||||
{ account: 'admin2', name: '张三', area: '分区2', cabin: '舱室2', device: '设备2', operation: '关', time: '2025-09-18 16:51:47' },
|
||||
{ account: 'admin2', name: '', area: '分区2', cabin: '舱室2', device: '设备2', operation: '关', time: '2025-09-18 16:32:00' },
|
||||
{ account: 'admin', name: '', area: '分区', cabin: '舱室', device: '设备', operation: '关', time: '2025-09-18 16:27:06' },
|
||||
]);
|
||||
|
||||
// 查询按钮逻辑
|
||||
const handleQuery = () => {
|
||||
console.log('查询条件:', searchForm);
|
||||
ElMessage.info('查询条件已提交(实际需对接接口)');
|
||||
};
|
||||
|
||||
// 分页-每页条数变化
|
||||
const handleSizeChange = (val) => {
|
||||
queryParams.pageSize = val;
|
||||
console.log('每页条数变更为:', val);
|
||||
// 实际项目中调用接口加载对应页数据
|
||||
};
|
||||
|
||||
// 分页-当前页码变化
|
||||
const handleCurrentChange = (val) => {
|
||||
queryParams.pageNum = val;
|
||||
console.log('当前页码变更为:', val);
|
||||
// 实际项目中调用接口加载对应页数据
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面整体样式:浅灰蓝背景 + 适配布局 */
|
||||
.operation-record-page {
|
||||
padding: 20px;
|
||||
background-color: #f8fafc;
|
||||
min-height: calc(100vh - 64px); /* 适配顶部导航高度 */
|
||||
}
|
||||
|
||||
/* 卡片样式:圆角 + 悬浮阴影增强层次感 */
|
||||
.page-card {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 搜索表单样式:间距与对齐优化 */
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 按钮样式:间距调整避免拥挤 */
|
||||
.el-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* 表格样式:100%宽度占满容器 */
|
||||
.record-table {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,452 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="菜单名称" prop="menuName">
|
||||
<el-input
|
||||
v-model="queryParams.menuName"
|
||||
placeholder="请输入菜单名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<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="menuId"
|
||||
:default-expand-all="isExpandAll"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<svg-icon :icon-class="scope.row.icon" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
|
||||
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="80">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']">新增</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 添加或修改菜单对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
||||
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="上级菜单">
|
||||
<el-tree-select
|
||||
v-model="form.parentId"
|
||||
:data="menuOptions"
|
||||
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
||||
value-key="menuId"
|
||||
placeholder="选择上级菜单"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="菜单类型" prop="menuType">
|
||||
<el-radio-group v-model="form.menuType">
|
||||
<el-radio value="M">目录</el-radio>
|
||||
<el-radio value="C">菜单</el-radio>
|
||||
<el-radio value="F">按钮</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||
<el-form-item label="菜单图标" prop="icon">
|
||||
<el-popover
|
||||
placement="bottom-start"
|
||||
:width="540"
|
||||
trigger="click"
|
||||
>
|
||||
<template #reference>
|
||||
<el-input v-model="form.icon" placeholder="点击选择图标" @blur="showSelectIcon" readonly>
|
||||
<template #prefix>
|
||||
<svg-icon
|
||||
v-if="form.icon"
|
||||
:icon-class="form.icon"
|
||||
class="el-input__icon"
|
||||
style="height: 32px;width: 16px;"
|
||||
/>
|
||||
<el-icon v-else style="height: 32px;width: 16px;"><search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<icon-select ref="iconSelectRef" @selected="selected" :active-icon="form.icon" />
|
||||
</el-popover>
|
||||
</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="menuName">
|
||||
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||
<el-form-item prop="routeName">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="默认不填则和路由地址相同:如地址为:`user`,则名称为`User`(注意:因为router会删除名称相同路由,为避免名字的冲突,特殊情况下请自定义,保证唯一性)" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
路由名称
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.routeName" placeholder="请输入路由名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>是否外链
|
||||
</span>
|
||||
</template>
|
||||
<el-radio-group v-model="form.isFrame">
|
||||
<el-radio value="0">是</el-radio>
|
||||
<el-radio value="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||
<el-form-item prop="path">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
路由地址
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.path" placeholder="请输入路由地址" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||
<el-form-item prop="component">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
组件路径
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.component" placeholder="请输入组件路径" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'M'">
|
||||
<el-form-item>
|
||||
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
权限字符
|
||||
</span>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||
<el-form-item>
|
||||
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
路由参数
|
||||
</span>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
是否缓存
|
||||
</span>
|
||||
</template>
|
||||
<el-radio-group v-model="form.isCache">
|
||||
<el-radio value="0">缓存</el-radio>
|
||||
<el-radio value="1">不缓存</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
显示状态
|
||||
</span>
|
||||
</template>
|
||||
<el-radio-group v-model="form.visible">
|
||||
<el-radio
|
||||
v-for="dict in sys_show_hide"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>{{ dict.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
菜单状态
|
||||
</span>
|
||||
</template>
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="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"
|
||||
|
||||
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 iconSelectRef = ref(null)
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
menuName: undefined,
|
||||
visible: undefined
|
||||
},
|
||||
rules: {
|
||||
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
|
||||
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
|
||||
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
|
||||
},
|
||||
})
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data)
|
||||
|
||||
/** 查询菜单列表 */
|
||||
function getList() {
|
||||
loading.value = true
|
||||
listMenu(queryParams.value).then(response => {
|
||||
menuList.value = proxy.handleTree(response.data, "menuId")
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 查询菜单下拉树结构 */
|
||||
function getTreeselect() {
|
||||
menuOptions.value = []
|
||||
listMenu().then(response => {
|
||||
const menu = { menuId: 0, menuName: "主类目", children: [] }
|
||||
menu.children = proxy.handleTree(response.data, "menuId")
|
||||
menuOptions.value.push(menu)
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
menuId: undefined,
|
||||
parentId: 0,
|
||||
menuName: undefined,
|
||||
icon: undefined,
|
||||
menuType: "M",
|
||||
orderNum: undefined,
|
||||
isFrame: "1",
|
||||
isCache: "0",
|
||||
visible: "0",
|
||||
status: "0"
|
||||
}
|
||||
proxy.resetForm("menuRef")
|
||||
}
|
||||
|
||||
/** 展示下拉图标 */
|
||||
function showSelectIcon() {
|
||||
iconSelectRef.value.reset()
|
||||
}
|
||||
|
||||
/** 选择图标 */
|
||||
function selected(name) {
|
||||
form.value.icon = name
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef")
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd(row) {
|
||||
reset()
|
||||
getTreeselect()
|
||||
if (row != null && row.menuId) {
|
||||
form.value.parentId = row.menuId
|
||||
} else {
|
||||
form.value.parentId = 0
|
||||
}
|
||||
open.value = true
|
||||
title.value = "添加菜单"
|
||||
}
|
||||
|
||||
/** 展开/折叠操作 */
|
||||
function toggleExpandAll() {
|
||||
refreshTable.value = false
|
||||
isExpandAll.value = !isExpandAll.value
|
||||
nextTick(() => {
|
||||
refreshTable.value = true
|
||||
})
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
async function handleUpdate(row) {
|
||||
reset()
|
||||
await getTreeselect()
|
||||
getMenu(row.menuId).then(response => {
|
||||
form.value = response.data
|
||||
open.value = true
|
||||
title.value = "修改菜单"
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["menuRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.menuId != undefined) {
|
||||
updateMenu(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addMenu(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
proxy.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
|
||||
return delMenu(row.menuId)
|
||||
}).then(() => {
|
||||
getList()
|
||||
proxy.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
getList()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-input
|
||||
v-model="queryParams.noticeTitle"
|
||||
placeholder="请输入公告标题"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人员" prop="createBy">
|
||||
<el-input
|
||||
v-model="queryParams.createBy"
|
||||
placeholder="请输入操作人员"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="noticeType">
|
||||
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_notice_type"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:notice:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Edit"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['system:notice:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['system:notice:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" prop="noticeId" width="100" />
|
||||
<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 link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']" >删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改公告对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="780px" append-to-body>
|
||||
<el-form ref="noticeRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="公告类型" prop="noticeType">
|
||||
<el-select v-model="form.noticeType" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in sys_notice_type"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_notice_status"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>{{ dict.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="内容">
|
||||
<editor v-model="form.noticeContent" :min-height="192"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Notice">
|
||||
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>
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="岗位编码" prop="postCode">
|
||||
<el-input
|
||||
v-model="queryParams.postCode"
|
||||
placeholder="请输入岗位编码"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位名称" prop="postName">
|
||||
<el-input
|
||||
v-model="queryParams.postName"
|
||||
placeholder="请输入岗位名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:post:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Edit"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['system:post:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['system:post:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:post:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="岗位编号" align="center" prop="postId" />
|
||||
<el-table-column label="岗位编码" align="center" prop="postCode" />
|
||||
<el-table-column label="岗位名称" align="center" prop="postName" />
|
||||
<el-table-column label="岗位排序" align="center" prop="postSort" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改岗位对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="postRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="岗位名称" prop="postName">
|
||||
<el-input v-model="form.postName" placeholder="请输入岗位名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位编码" prop="postCode">
|
||||
<el-input v-model="form.postCode" placeholder="请输入编码名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位顺序" prop="postSort">
|
||||
<el-input-number v-model="form.postSort" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="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,
|
||||
status: undefined
|
||||
},
|
||||
rules: {
|
||||
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
|
||||
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
|
||||
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
|
||||
}
|
||||
})
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data)
|
||||
|
||||
/** 查询岗位列表 */
|
||||
function getList() {
|
||||
loading.value = true
|
||||
listPost(queryParams.value).then(response => {
|
||||
postList.value = response.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
postId: undefined,
|
||||
postCode: undefined,
|
||||
postName: undefined,
|
||||
postSort: 0,
|
||||
status: "0",
|
||||
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.postId)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset()
|
||||
open.value = true
|
||||
title.value = "添加岗位"
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset()
|
||||
const postId = row.postId || 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.postId != undefined) {
|
||||
updatePost(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addPost(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const postIds = row.postId || 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>
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true">
|
||||
<el-form-item label="用户名称" prop="userName">
|
||||
<el-input
|
||||
v-model="queryParams.userName"
|
||||
placeholder="请输入用户名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input
|
||||
v-model="queryParams.phonenumber"
|
||||
placeholder="请输入手机号码"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="openSelectUser"
|
||||
v-hasPermi="['system:role:add']"
|
||||
>添加用户</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="CircleClose"
|
||||
:disabled="multiple"
|
||||
@click="cancelAuthUserAll"
|
||||
v-hasPermi="['system:role:remove']"
|
||||
>批量取消授权</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Close"
|
||||
@click="handleClose"
|
||||
>关闭</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']">取消授权</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="AuthUser">
|
||||
import selectUser from "./selectUser"
|
||||
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>
|
||||
|
|
@ -0,0 +1,590 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
|
||||
<el-form-item label="角色名称" prop="roleName">
|
||||
<el-input
|
||||
v-model="queryParams.roleName"
|
||||
placeholder="请输入角色名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限字符" prop="roleKey">
|
||||
<el-input
|
||||
v-model="queryParams.roleKey"
|
||||
placeholder="请输入权限字符"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="角色状态"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" style="width: 308px">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
value-format="YYYY-MM-DD"
|
||||
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> -->
|
||||
</el-row>
|
||||
|
||||
<!-- 表格数据 -->
|
||||
<el-table v-loading="loading" :header-cell-style="headerStyle" :data="roleList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="角色编号" prop="roleId" width="120" />
|
||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
|
||||
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
||||
<el-table-column label="状态" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.status"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
@change="handleStatusChange(scope.row)"
|
||||
></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
|
||||
<el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
|
||||
<el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改角色配置对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="角色名称" prop="roleName">
|
||||
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="roleKey">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
权限字符
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.roleKey" placeholder="请输入权限字符" />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色顺序" prop="roleSort">
|
||||
<el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>{{ dict.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单权限">
|
||||
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
|
||||
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
||||
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
||||
<el-tree
|
||||
class="tree-border"
|
||||
:data="menuOptions"
|
||||
show-checkbox
|
||||
ref="menuRef"
|
||||
node-key="id"
|
||||
:check-strictly="!form.menuCheckStrictly"
|
||||
empty-text="加载中,请稍候"
|
||||
:props="{ label: 'label', children: 'children' }"
|
||||
></el-tree>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 分配角色数据权限对话框 -->
|
||||
<el-dialog :title="title" v-model="openDataScope" width="500px" append-to-body>
|
||||
<el-form :model="form" label-width="80px">
|
||||
<el-form-item label="角色名称">
|
||||
<el-input v-model="form.roleName" :disabled="true" />
|
||||
</el-form-item>
|
||||
<el-form-item label="权限字符">
|
||||
<el-input v-model="form.roleKey" :disabled="true" />
|
||||
</el-form-item>
|
||||
<el-form-item label="权限范围">
|
||||
<el-select v-model="form.dataScope" @change="dataScopeSelectChange">
|
||||
<el-option
|
||||
v-for="item in dataScopeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据权限" v-show="form.dataScope == 2">
|
||||
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
|
||||
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
||||
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
||||
<el-tree
|
||||
class="tree-border"
|
||||
:data="deptOptions"
|
||||
show-checkbox
|
||||
default-expand-all
|
||||
ref="deptRef"
|
||||
node-key="id"
|
||||
:check-strictly="!form.deptCheckStrictly"
|
||||
empty-text="加载中,请稍候"
|
||||
:props="{ label: 'label', children: 'children' }"
|
||||
></el-tree>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitDataScope">确 定</el-button>
|
||||
<el-button @click="cancelDataScope">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Role">
|
||||
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role"
|
||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
|
||||
|
||||
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(false)
|
||||
const menuNodeAll = ref(false)
|
||||
const deptExpand = ref(true)
|
||||
const deptNodeAll = ref(false)
|
||||
const deptOptions = ref([])
|
||||
const openDataScope = ref(false)
|
||||
const menuRef = ref(null)
|
||||
const deptRef = ref(null)
|
||||
|
||||
/** 数据范围选项*/
|
||||
const dataScopeOptions = ref([
|
||||
{ value: "1", label: "全部数据权限" },
|
||||
{ value: "2", label: "自定数据权限" },
|
||||
{ value: "3", label: "本部门数据权限" },
|
||||
{ value: "4", label: "本部门及以下数据权限" },
|
||||
{ value: "5", label: "仅本人数据权限" }
|
||||
])
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
roleName: undefined,
|
||||
roleKey: undefined,
|
||||
status: undefined
|
||||
},
|
||||
rules: {
|
||||
roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
|
||||
roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
|
||||
roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
|
||||
},
|
||||
})
|
||||
|
||||
// 表头样式(清新浅蓝主题)
|
||||
const headerStyle = {
|
||||
backgroundColor: "#f0f9ff",
|
||||
color: "#409eff",
|
||||
fontWeight: "500",
|
||||
};
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data)
|
||||
|
||||
/** 查询角色列表 */
|
||||
function getList() {
|
||||
loading.value = true
|
||||
listRole(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
|
||||
roleList.value = response.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm("queryRef")
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const roleIds = row.roleId || ids.value
|
||||
proxy.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function () {
|
||||
return delRole(roleIds)
|
||||
}).then(() => {
|
||||
getList()
|
||||
proxy.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download("system/role/export", {
|
||||
...queryParams.value,
|
||||
}, `role_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.roleId)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
/** 角色状态修改 */
|
||||
function handleStatusChange(row) {
|
||||
let text = row.status === "0" ? "启用" : "停用"
|
||||
proxy.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
|
||||
return changeRoleStatus(row.roleId, row.status)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess(text + "成功")
|
||||
}).catch(function () {
|
||||
row.status = row.status === "0" ? "1" : "0"
|
||||
})
|
||||
}
|
||||
|
||||
/** 更多操作 */
|
||||
function handleCommand(command, row) {
|
||||
switch (command) {
|
||||
case "handleDataScope":
|
||||
handleDataScope(row)
|
||||
break
|
||||
case "handleAuthUser":
|
||||
handleAuthUser(row)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/** 分配用户 */
|
||||
function handleAuthUser(row) {
|
||||
router.push("/system/role-auth/user/" + row.roleId)
|
||||
}
|
||||
|
||||
/** 查询菜单树结构 */
|
||||
function getMenuTreeselect() {
|
||||
menuTreeselect().then(response => {
|
||||
menuOptions.value = response.data
|
||||
})
|
||||
}
|
||||
|
||||
/** 所有部门节点数据 */
|
||||
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 = {
|
||||
roleId: undefined,
|
||||
roleName: undefined,
|
||||
roleKey: undefined,
|
||||
roleSort: 0,
|
||||
status: "0",
|
||||
menuIds: [],
|
||||
deptIds: [],
|
||||
menuCheckStrictly: true,
|
||||
deptCheckStrictly: true,
|
||||
remark: undefined
|
||||
}
|
||||
proxy.resetForm("roleRef")
|
||||
}
|
||||
|
||||
/** 添加角色 */
|
||||
function handleAdd() {
|
||||
reset()
|
||||
getMenuTreeselect()
|
||||
open.value = true
|
||||
title.value = "添加角色"
|
||||
}
|
||||
|
||||
/** 修改角色 */
|
||||
function handleUpdate(row) {
|
||||
reset()
|
||||
const roleId = row.roleId || ids.value
|
||||
const roleMenu = getRoleMenuTreeselect(roleId)
|
||||
getRole(roleId).then(response => {
|
||||
form.value = response.data
|
||||
form.value.roleSort = Number(form.value.roleSort)
|
||||
open.value = true
|
||||
nextTick(() => {
|
||||
roleMenu.then((res) => {
|
||||
let checkedKeys = res.checkedKeys
|
||||
checkedKeys.forEach((v) => {
|
||||
nextTick(() => {
|
||||
menuRef.value.setChecked(v, true, false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
title.value = "修改角色"
|
||||
}
|
||||
|
||||
/** 根据角色ID查询菜单树结构 */
|
||||
function getRoleMenuTreeselect(roleId) {
|
||||
return roleMenuTreeselect(roleId).then(response => {
|
||||
menuOptions.value = response.menus
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
/** 根据角色ID查询部门树结构 */
|
||||
function getDeptTree(roleId) {
|
||||
return deptTreeSelect(roleId).then(response => {
|
||||
deptOptions.value = response.depts
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
/** 树权限(展开/折叠)*/
|
||||
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.roleId != undefined) {
|
||||
form.value.menuIds = getMenuAllCheckedKeys()
|
||||
updateRole(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
form.value.menuIds = getMenuAllCheckedKeys()
|
||||
addRole(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 选择角色权限范围触发 */
|
||||
function dataScopeSelectChange(value) {
|
||||
if (value !== "2") {
|
||||
deptRef.value.setCheckedKeys([])
|
||||
}
|
||||
}
|
||||
|
||||
/** 分配数据权限操作 */
|
||||
function handleDataScope(row) {
|
||||
reset()
|
||||
const deptTreeSelect = getDeptTree(row.roleId)
|
||||
getRole(row.roleId).then(response => {
|
||||
form.value = response.data
|
||||
openDataScope.value = true
|
||||
nextTick(() => {
|
||||
deptTreeSelect.then(res => {
|
||||
nextTick(() => {
|
||||
if (deptRef.value) {
|
||||
deptRef.value.setCheckedKeys(res.checkedKeys)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
title.value = "分配数据权限"
|
||||
}
|
||||
|
||||
/** 提交按钮(数据权限) */
|
||||
function submitDataScope() {
|
||||
if (form.value.roleId != 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>
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<template>
|
||||
<!-- 授权用户 -->
|
||||
<el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true">
|
||||
<el-form-item label="用户名称" prop="userName">
|
||||
<el-input
|
||||
v-model="queryParams.userName"
|
||||
placeholder="请输入用户名称"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input
|
||||
v-model="queryParams.phonenumber"
|
||||
placeholder="请输入手机号码"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
@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)
|
||||
visible.value = false
|
||||
emit("ok")
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<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" :selectable="checkSelectable" 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) {
|
||||
if (checkSelectable(row)) {
|
||||
proxy.$refs["roleRef"].toggleRowSelection(row)
|
||||
}
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection) {
|
||||
roleIds.value = selection.map(item => item.roleId)
|
||||
}
|
||||
|
||||
/** 保存选中的数据编号 */
|
||||
function getRowKey(row) {
|
||||
return row.roleId
|
||||
}
|
||||
|
||||
// 检查角色状态
|
||||
function checkSelectable(row) {
|
||||
return row.status === "0" ? true : false
|
||||
}
|
||||
|
||||
/** 关闭按钮 */
|
||||
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>
|
||||
|
|
@ -0,0 +1,481 @@
|
|||
<template>
|
||||
<div class="meter-monitoring-page">
|
||||
<!-- 卡片容器:带悬浮阴影,圆角优化 -->
|
||||
<el-card class="page-card" shadow="hover">
|
||||
<!-- 搜索表单:时间选择 + 快捷按钮 -->
|
||||
<el-form inline :model="searchForm" class="search-form">
|
||||
<el-form-item label="账号:">
|
||||
<el-input></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名:">
|
||||
<el-input></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号:">
|
||||
<el-input></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item style="margin-left: 16px; float: right">
|
||||
<el-button plain @click="handleAdd">新增</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 电表数据表格:带边框、斑马纹 -->
|
||||
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:header-cell-style="headerStyle"
|
||||
border
|
||||
stripe
|
||||
class="meter-table"
|
||||
>
|
||||
<el-table-column
|
||||
prop="userName"
|
||||
label="账号/工号"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="姓名"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="sex"
|
||||
label="性别"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="phonenumber"
|
||||
label="手机号码"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="创建时间"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column label="状态" align="center" key="status">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.status"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
@change="handleStatusChange(scope.row)"
|
||||
></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
align="center"
|
||||
width="180"
|
||||
class-name="small-padding fixed-width"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tooltip
|
||||
content="修改"
|
||||
placement="top"
|
||||
v-if="scope.row.userId !== 1"
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="删除"
|
||||
placement="top"
|
||||
v-if="scope.row.userId !== 1"
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="重置密码"
|
||||
placement="top"
|
||||
v-if="scope.row.userId !== 1"
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Key"
|
||||
@click="handleResetPwd(scope.row)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
content="分配角色"
|
||||
placement="top"
|
||||
v-if="scope.row.userId !== 1"
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="CircleCheck"
|
||||
@click="handleAuthRole(scope.row)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 添加或修改用户配置对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="600px">
|
||||
<el-form :model="form" :rules="rules" ref="userRef" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="账号" prop="nickName">
|
||||
<el-input
|
||||
v-model="form.nickName"
|
||||
placeholder="请输入用户昵称"
|
||||
maxlength="30"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input
|
||||
v-model="form.phonenumber"
|
||||
placeholder="请输入手机号码"
|
||||
maxlength="11"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
v-if="form.userId == undefined"
|
||||
label="姓名"
|
||||
prop="userName"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.userName"
|
||||
placeholder="请输入用户名称"
|
||||
maxlength="30"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
v-if="form.userId == undefined"
|
||||
label="用户密码"
|
||||
prop="password"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.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.sex" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in sys_user_sex"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="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.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:value="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.roleIds" multiple placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in roleOptions"
|
||||
:key="item.roleId"
|
||||
:label="item.roleName"
|
||||
:value="item.roleId"
|
||||
:disabled="item.status == 1"
|
||||
></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.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">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const router = useRouter();
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
userName: undefined,
|
||||
phonenumber: undefined,
|
||||
status: undefined,
|
||||
deptId: undefined,
|
||||
},
|
||||
rules: {
|
||||
userName: [
|
||||
{ required: true, message: "用户名称不能为空", trigger: "blur" },
|
||||
{
|
||||
min: 2,
|
||||
max: 20,
|
||||
message: "用户名称长度必须介于 2 和 20 之间",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
nickName: [
|
||||
{ required: true, message: "用户昵称不能为空", trigger: "blur" },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "用户密码不能为空", trigger: "blur" },
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: "用户密码长度必须介于 5 和 20 之间",
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
pattern: /^[^<>"'|\\]+$/,
|
||||
message: "不能包含非法字符:< > \" ' \\ |",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
type: "email",
|
||||
message: "请输入正确的邮箱地址",
|
||||
trigger: ["blur", "change"],
|
||||
},
|
||||
],
|
||||
phonenumber: [
|
||||
{
|
||||
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||
message: "请输入正确的手机号码",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
const total = ref(10);
|
||||
const open = ref(false);
|
||||
const title = ref("添加用户");
|
||||
|
||||
const searchForm = ref({
|
||||
startTime: "", // 开始时间
|
||||
endTime: "", // 结束时间
|
||||
});
|
||||
|
||||
// 表头样式(清新浅蓝主题)
|
||||
const headerStyle = {
|
||||
backgroundColor: "#f0f9ff",
|
||||
color: "#409eff",
|
||||
fontWeight: "500",
|
||||
};
|
||||
|
||||
/** 重置操作表单 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
userId: undefined,
|
||||
deptId: undefined,
|
||||
userName: undefined,
|
||||
nickName: undefined,
|
||||
password: undefined,
|
||||
phonenumber: undefined,
|
||||
email: undefined,
|
||||
sex: undefined,
|
||||
status: "0",
|
||||
remark: undefined,
|
||||
postIds: [],
|
||||
roleIds: [],
|
||||
};
|
||||
}
|
||||
|
||||
/** 用户状态修改 */
|
||||
function handleStatusChange(row) {
|
||||
let text = row.status === "0" ? "启用" : "停用";
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "修改用户";
|
||||
const userId = row.userId || ids.value;
|
||||
getUser(userId).then((response) => {
|
||||
form.value = response.data;
|
||||
postOptions.value = response.posts;
|
||||
roleOptions.value = response.roles;
|
||||
form.value.postIds = response.postIds;
|
||||
form.value.roleIds = response.roleIds;
|
||||
form.password = "";
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
// const userIds = row.userId || ids.value;
|
||||
|
||||
ElMessageBox.confirm("是否确认删除用户?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(() => {
|
||||
ElMessage.success(`删除成功`);
|
||||
});
|
||||
}
|
||||
|
||||
/** 重置密码按钮操作 */
|
||||
function handleResetPwd(row) {
|
||||
proxy
|
||||
.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
closeOnClickModal: false,
|
||||
inputPattern: /^.{5,20}$/,
|
||||
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
|
||||
inputValidator: (value) => {
|
||||
if (/<|>|"|'|\||\\/.test(value)) {
|
||||
return "不能包含非法字符:< > \" ' \\ |";
|
||||
}
|
||||
},
|
||||
})
|
||||
.then(({ value }) => {
|
||||
resetUserPwd(row.userId, value).then((response) => {
|
||||
proxy.$modal.msgSuccess("修改成功,新密码是:" + value);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
/** 跳转角色分配 */
|
||||
function handleAuthRole(row) {
|
||||
const userId = row.userId;
|
||||
router.push("/system/user-auth/role/" + userId);
|
||||
}
|
||||
|
||||
// 模拟电表数据(与原型一致)
|
||||
const tableData = ref([
|
||||
{
|
||||
userName: "admin",
|
||||
name: "张三",
|
||||
sex: "男",
|
||||
phonenumber: "123456789",
|
||||
createTime: "2025-10-09",
|
||||
status: true,
|
||||
},
|
||||
]);
|
||||
|
||||
// 点击"查询"按钮
|
||||
const handleQuery = () => {
|
||||
console.log("查询条件:", searchForm.value);
|
||||
// 实际项目中,这里会调用接口,根据 startTime/endTime 筛选数据
|
||||
// 示例:tableData.value = 接口返回的筛选后数据
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
open.value = true;
|
||||
title.value = "添加用户";
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
const getList = () => {};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面整体:浅灰蓝背景,清新柔和 */
|
||||
.meter-monitoring-page {
|
||||
padding: 20px;
|
||||
background-color: #f8fafc;
|
||||
min-height: calc(100vh - 64px); /* 适配顶部导航高度 */
|
||||
}
|
||||
|
||||
/* 卡片样式:圆角 + 悬浮阴影,增强层次感 */
|
||||
.page-card {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 搜索表单:间距与对齐优化 */
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 日期选择器:宽度统一,视觉更整齐 */
|
||||
.el-date-picker {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
/* 按钮:间距调整,避免拥挤 */
|
||||
.el-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* 表格:宽度100%,充分利用空间 */
|
||||
.meter-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<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 />
|
||||
</div>
|
||||
<ul class="list-group list-group-striped">
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="user" />用户名称
|
||||
<div class="pull-right">{{ state.user.userName }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="phone" />手机号码
|
||||
<div class="pull-right">{{ state.user.phonenumber }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="email" />用户邮箱
|
||||
<div class="pull-right">{{ state.user.email }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="tree" />所属部门
|
||||
<div class="pull-right" v-if="state.user.dept">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="peoples" />所属角色
|
||||
<div class="pull-right">{{ state.roleGroup }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="date" />创建日期
|
||||
<div class="pull-right">{{ state.user.createTime }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="18" :xs="24">
|
||||
<el-card>
|
||||
<template v-slot:header>
|
||||
<div class="clearfix">
|
||||
<span>基本资料</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-tabs v-model="selectedTab">
|
||||
<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 route = useRoute()
|
||||
const selectedTab = ref("userinfo")
|
||||
const state = reactive({
|
||||
user: {},
|
||||
roleGroup: {},
|
||||
postGroup: {}
|
||||
})
|
||||
|
||||
function getUser() {
|
||||
getUserProfile().then(response => {
|
||||
state.user = response.data
|
||||
state.roleGroup = response.roleGroup
|
||||
state.postGroup = response.postGroup
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const activeTab = route.params && route.params.activeTab
|
||||
if (activeTab) {
|
||||
selectedTab.value = activeTab
|
||||
}
|
||||
getUser()
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<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" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", 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>
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
<template>
|
||||
<div class="user-info-head" @click="editCropper()">
|
||||
<img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
|
||||
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
|
||||
<el-row>
|
||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||
<vue-cropper
|
||||
ref="cropper"
|
||||
:img="options.img"
|
||||
:info="true"
|
||||
:autoCrop="options.autoCrop"
|
||||
:autoCropWidth="options.autoCropWidth"
|
||||
:autoCropHeight="options.autoCropHeight"
|
||||
:fixedBox="options.fixedBox"
|
||||
:outputType="options.outputType"
|
||||
@realTime="realTime"
|
||||
v-if="visible"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||
<div class="avatar-upload-preview">
|
||||
<img :src="options.previews.url" :style="options.previews.img" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<br />
|
||||
<el-row>
|
||||
<el-col :lg="2" :md="2">
|
||||
<el-upload
|
||||
action="#"
|
||||
:http-request="requestUpload"
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<el-button>
|
||||
选择
|
||||
<el-icon class="el-icon--right"><Upload /></el-icon>
|
||||
</el-button>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
|
||||
<el-button icon="Plus" @click="changeScale(1)"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
|
||||
<el-button type="primary" @click="uploadImg()">提 交</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import "vue-cropper/dist/index.css"
|
||||
import { VueCropper } from "vue-cropper"
|
||||
import { uploadAvatar } 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, // 固定截图框大小 不允许改变
|
||||
outputType: "png", // 默认生成截图为PNG格式
|
||||
filename: 'avatar', // 文件名称
|
||||
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("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。")
|
||||
} else {
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = () => {
|
||||
options.img = reader.result
|
||||
options.filename = file.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 上传图片 */
|
||||
function uploadImg() {
|
||||
proxy.$refs.cropper.getCropBlob(data => {
|
||||
let formData = new FormData()
|
||||
formData.append("avatarfile", data, options.filename)
|
||||
uploadAvatar(formData).then(response => {
|
||||
open.value = false
|
||||
options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl
|
||||
userStore.avatar = options.img
|
||||
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>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<el-form ref="userRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="用户昵称" prop="nickName">
|
||||
<el-input v-model="form.nickName" maxlength="30" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input v-model="form.phonenumber" maxlength="11" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="form.sex">
|
||||
<el-radio value="0">男</el-radio>
|
||||
<el-radio value="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 form = ref({})
|
||||
const rules = ref({
|
||||
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
||||
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
||||
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
|
||||
})
|
||||
|
||||
/** 提交按钮 */
|
||||
function submit() {
|
||||
proxy.$refs.userRef.validate(valid => {
|
||||
if (valid) {
|
||||
updateUserProfile(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
props.user.phonenumber = form.value.phonenumber
|
||||
props.user.email = form.value.email
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 关闭按钮 */
|
||||
function close() {
|
||||
proxy.$tab.closePage()
|
||||
}
|
||||
|
||||
// 回显当前登录用户信息
|
||||
watch(() => props.user, user => {
|
||||
if (user) {
|
||||
form.value = { nickName: user.nickName, phonenumber: user.phonenumber, email: user.email, sex: user.sex }
|
||||
}
|
||||
},{ immediate: true })
|
||||
</script>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<el-dialog v-model="open" width="500px" title="选择生成类型" @open="onOpen" @close="onClose">
|
||||
<el-form ref="codeTypeForm" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="生成类型" prop="type">
|
||||
<el-radio-group v-model="formData.type">
|
||||
<el-radio-button v-for="(item, index) in typeOptions" :key="index" :label="item.value">
|
||||
{{ item.label }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="showFileName" label="文件名" prop="fileName">
|
||||
<el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button type="primary" @click="handelConfirm">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const open = defineModel()
|
||||
const props = defineProps({
|
||||
showFileName: Boolean
|
||||
})
|
||||
const emit = defineEmits(['confirm'])
|
||||
const formData = ref({
|
||||
fileName: undefined,
|
||||
type: 'file'
|
||||
})
|
||||
const codeTypeForm = ref()
|
||||
const rules = {
|
||||
fileName: [{
|
||||
required: true,
|
||||
message: '请输入文件名',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
type: [{
|
||||
required: true,
|
||||
message: '生成类型不能为空',
|
||||
trigger: 'change'
|
||||
}]
|
||||
}
|
||||
const typeOptions = ref([
|
||||
{
|
||||
label: '页面',
|
||||
value: 'file'
|
||||
},
|
||||
{
|
||||
label: '弹窗',
|
||||
value: 'dialog'
|
||||
}
|
||||
])
|
||||
function onOpen() {
|
||||
if (props.showFileName) {
|
||||
formData.value.fileName = `${+new Date()}.vue`
|
||||
}
|
||||
}
|
||||
function onClose() {
|
||||
open.value = false
|
||||
}
|
||||
function handelConfirm() {
|
||||
codeTypeForm.value.validate(valid => {
|
||||
if (!valid) return
|
||||
emit('confirm', { ...formData.value })
|
||||
onClose()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<template>
|
||||
<el-col :span="element.span" :class="className" @click.stop="activeItem(element)">
|
||||
<el-form-item :label="element.label" :label-width="element.labelWidth ? element.labelWidth + 'px' : null"
|
||||
:required="element.required" v-if="element.layout === 'colFormItem'">
|
||||
<render :key="element.tag" :conf="element" v-model="element.defaultValue" />
|
||||
</el-form-item>
|
||||
<el-row :gutter="element.gutter" :class="element.class" @click.stop="activeItem(element)" v-else>
|
||||
<span class="component-name"> {{ element.componentName }} </span>
|
||||
<draggable group="componentsGroup" :animation="340" :list="element.children" class="drag-wrapper" item-key="label"
|
||||
ref="draggableItemRef" :component-data="getComponentData()">
|
||||
<template #item="scoped">
|
||||
<draggable-item :key="scoped.element.renderKey" :drawing-list="element.children" :element="scoped.element"
|
||||
:index="index" :active-id="activeId" :form-conf="formConf" @activeItem="activeItem(scoped.element)"
|
||||
@copyItem="copyItem(scoped.element, element.children)"
|
||||
@deleteItem="deleteItem(scoped.index, element.children)" />
|
||||
</template>
|
||||
</draggable>
|
||||
</el-row>
|
||||
<span class="drawing-item-copy" title="复制" @click.stop="copyItem(element)">
|
||||
<el-icon><CopyDocument /></el-icon>
|
||||
</span>
|
||||
<span class="drawing-item-delete" title="删除" @click.stop="deleteItem(index)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</span>
|
||||
</el-col>
|
||||
</template>
|
||||
<script setup name="DraggableItem">
|
||||
import draggable from "vuedraggable/dist/vuedraggable.common"
|
||||
import render from '@/utils/generator/render'
|
||||
|
||||
const props = defineProps({
|
||||
element: Object,
|
||||
index: Number,
|
||||
drawingList: Array,
|
||||
activeId: {
|
||||
type: [String, Number]
|
||||
},
|
||||
formConf: Object
|
||||
})
|
||||
const className = ref('')
|
||||
const draggableItemRef = ref(null)
|
||||
const emits = defineEmits(['activeItem', 'copyItem', 'deleteItem'])
|
||||
|
||||
function activeItem(item) {
|
||||
emits('activeItem', item)
|
||||
}
|
||||
function copyItem(item, parent) {
|
||||
emits('copyItem', item, parent ?? props.drawingList)
|
||||
}
|
||||
function deleteItem(item, parent) {
|
||||
emits('deleteItem', item, parent ?? props.drawingList)
|
||||
}
|
||||
|
||||
function getComponentData() {
|
||||
return {
|
||||
gutter: props.element.gutter,
|
||||
justify: props.element.justify,
|
||||
align: props.element.align
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.activeId, (val) => {
|
||||
className.value = (props.element.layout === 'rowFormItem' ? 'drawing-row-item' : 'drawing-item') + (val === props.element.formId ? ' active-from-item' : '')
|
||||
if (props.formConf.unFocusedComponentBorder) {
|
||||
className.value += ' unfocus-bordered'
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<template>
|
||||
<div class="icon-dialog">
|
||||
<el-dialog v-model="value" width="980px" :close-on-click-modal="false" :modal-append-to-body="false" @open="onOpen"
|
||||
@close="onClose">
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
选择图标
|
||||
<el-input v-model="key" size="small" :style="{ width: '260px' }" placeholder="请输入图标名称" prefix-icon="Search"
|
||||
clearable />
|
||||
</template>
|
||||
<ul class="icon-ul">
|
||||
<li v-for="icon in iconList" :key="icon" :class="active === icon ? 'active-item' : ''" @click="onSelect(icon)">
|
||||
<div>
|
||||
<el-icon :size="30">
|
||||
<component :is="icon" />
|
||||
</el-icon>
|
||||
<div>{{ icon }}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import { watch } from 'vue'
|
||||
|
||||
const iconList = ref([])
|
||||
const originList = []
|
||||
const key = ref('')
|
||||
const active = ref('')
|
||||
const emit = defineEmits(['select'])
|
||||
const value = defineModel()
|
||||
for (const [key] of Object.entries(ElementPlusIconsVue)) {
|
||||
iconList.value.push(key)
|
||||
originList.push(key)
|
||||
}
|
||||
|
||||
function onOpen() { }
|
||||
function onClose() { }
|
||||
function onSelect(icon) {
|
||||
active.value = icon
|
||||
emit('select', icon)
|
||||
value.value = false
|
||||
}
|
||||
|
||||
watch(key, (val) => {
|
||||
if (val) {
|
||||
iconList.value = originList.filter(name => name.indexOf(val) > -1)
|
||||
} else {
|
||||
iconList.value = originList
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.icon-ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0;
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
display: inline-flex;
|
||||
width: 16.66%;
|
||||
box-sizing: border-box;
|
||||
height: 108px;
|
||||
padding: 6px 6px 6px 6px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
&.active-item {
|
||||
background: #e1f3fb;
|
||||
color: #7a6df0
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 30px;
|
||||
line-height: 50px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon-dialog {
|
||||
:deep() {
|
||||
.el-dialog {
|
||||
border-radius: 8px;
|
||||
margin-bottom: 0;
|
||||
margin-top: 4vh !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 92vh;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
.el-dialog__header {
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
margin: 0 20px 20px 20px;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,906 @@
|
|||
<template>
|
||||
<div class="right-board">
|
||||
<el-tabs v-model="currentTab" stretch class="center-tabs">
|
||||
<el-tab-pane label="组件属性" name="field" />
|
||||
<el-tab-pane label="表单属性" name="form" />
|
||||
</el-tabs>
|
||||
<div class="field-box">
|
||||
<a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
|
||||
<el-icon>
|
||||
<Link />
|
||||
</el-icon>
|
||||
</a>
|
||||
<el-scrollbar class="right-scrollbar">
|
||||
<!-- 组件属性 -->
|
||||
<el-form v-show="currentTab === 'field' && showField" size="default" label-width="90px" label-position="top"
|
||||
style="">
|
||||
<el-form-item v-if="activeData.changeTag" label="组件类型">
|
||||
<el-select v-model="activeData.tagIcon" placeholder="请选择组件类型" :style="{ width: '100%' }" @change="tagChange">
|
||||
<el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
|
||||
<el-option v-for="item in group.options" :key="item.label" :label="item.label" :value="item.tagIcon">
|
||||
<svg-icon class="node-icon" :icon-class="item.tagIcon" style="margin-right: 10px;" />
|
||||
<span> {{ item.label }}</span>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.vModel !== undefined" label="字段名">
|
||||
<el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.componentName !== undefined" label="组件名">
|
||||
{{ activeData.componentName }}
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.label !== undefined" label="标题">
|
||||
<el-input v-model="activeData.label" placeholder="请输入标题" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.placeholder !== undefined" label="占位提示">
|
||||
<el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['start-placeholder'] !== undefined" label="开始占位">
|
||||
<el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['end-placeholder'] !== undefined" label="结束占位">
|
||||
<el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.span !== undefined" label="表单栅格">
|
||||
<el-slider v-model="activeData.span" :max="24" :min="1" :marks="{ 12: '' }" @change="spanChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.layout === 'rowFormItem'" label="栅格间隔">
|
||||
<el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="activeData.justify !== undefined" label="水平排列">
|
||||
<el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{ width: '100%' }">
|
||||
<el-option v-for="(item, index) in justifyOptions" :key="index" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.align !== undefined" label="垂直排列">
|
||||
<el-radio-group v-model="activeData.align">
|
||||
<el-radio-button label="top" />
|
||||
<el-radio-button label="middle" />
|
||||
<el-radio-button label="bottom" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.labelWidth !== undefined" label="标签宽度">
|
||||
<el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.style && activeData.style.width !== undefined" label="组件宽度">
|
||||
<el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.vModel !== undefined" label="默认值">
|
||||
<el-input :value="setDefaultValue(activeData.defaultValue)" placeholder="请输入默认值"
|
||||
@input="onDefaultValueInput" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-checkbox-group'" label="至少应选">
|
||||
<el-input-number :value="activeData.min" :min="0" placeholder="至少应选"
|
||||
@input="$set(activeData, 'min', $event ? $event : undefined)" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-checkbox-group'" label="最多可选">
|
||||
<el-input-number :value="activeData.max" :min="0" placeholder="最多可选"
|
||||
@input="$set(activeData, 'max', $event ? $event : undefined)" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.prepend !== undefined" label="前缀">
|
||||
<el-input v-model="activeData.prepend" placeholder="请输入前缀" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.append !== undefined" label="后缀">
|
||||
<el-input v-model="activeData.append" placeholder="请输入后缀" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['prefix-icon'] !== undefined" label="前图标">
|
||||
<el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
|
||||
<template #append>
|
||||
<el-button icon="Pointer" @click="openIconsDialog('prefix-icon')">
|
||||
选择
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标">
|
||||
<el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称">
|
||||
<template #append>
|
||||
<el-button icon="Pointer" @click="openIconsDialog('suffix-icon')">
|
||||
选择
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
|
||||
<el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
|
||||
<el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
|
||||
<el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.min !== undefined" label="最小值">
|
||||
<el-input-number v-model="activeData.min" placeholder="最小值" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.max !== undefined" label="最大值">
|
||||
<el-input-number v-model="activeData.max" placeholder="最大值" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.step !== undefined" label="步长">
|
||||
<el-input-number v-model="activeData.step" placeholder="步数" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
|
||||
<el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
|
||||
<el-radio-group v-model="activeData['controls-position']">
|
||||
<el-radio-button label="">
|
||||
默认
|
||||
</el-radio-button>
|
||||
<el-radio-button label="right">
|
||||
右侧
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.maxlength !== undefined" label="最多输入">
|
||||
<el-input v-model="activeData.maxlength" placeholder="请输入字符长度">
|
||||
<template slot="append">
|
||||
个字符
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示">
|
||||
<el-input v-model="activeData['active-text']" placeholder="请输入开启提示" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示">
|
||||
<el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['active-value'] !== undefined" label="开启值">
|
||||
<el-input :value="setDefaultValue(activeData['active-value'])" placeholder="请输入开启值"
|
||||
@input="onSwitchValueInput($event, 'active-value')" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值">
|
||||
<el-input :value="setDefaultValue(activeData['inactive-value'])" placeholder="请输入关闭值"
|
||||
@input="onSwitchValueInput($event, 'inactive-value')" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag" label="时间类型">
|
||||
<el-select v-model="activeData.type" placeholder="请选择时间类型" :style="{ width: '100%' }"
|
||||
@change="dateTypeChange">
|
||||
<el-option v-for="(item, index) in dateOptions" :key="index" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.name !== undefined" label="文件字段名">
|
||||
<el-input v-model="activeData.name" placeholder="请输入上传文件字段名" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.accept !== undefined" label="文件类型">
|
||||
<el-select v-model="activeData.accept" placeholder="请选择文件类型" :style="{ width: '100%' }" clearable>
|
||||
<el-option label="图片" value="image/*" />
|
||||
<el-option label="视频" value="video/*" />
|
||||
<el-option label="音频" value="audio/*" />
|
||||
<el-option label="excel" value=".xls,.xlsx" />
|
||||
<el-option label="word" value=".doc,.docx" />
|
||||
<el-option label="pdf" value=".pdf" />
|
||||
<el-option label="txt" value=".txt" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
|
||||
<el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
|
||||
<el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
|
||||
<el-option label="KB" value="KB" />
|
||||
<el-option label="MB" value="MB" />
|
||||
<el-option label="GB" value="GB" />
|
||||
</el-select>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.action !== undefined" label="上传地址">
|
||||
<el-input v-model="activeData.action" placeholder="请输入上传地址" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型">
|
||||
<el-radio-group v-model="activeData['list-type']" size="small">
|
||||
<el-radio-button label="text">
|
||||
text
|
||||
</el-radio-button>
|
||||
<el-radio-button label="picture">
|
||||
picture
|
||||
</el-radio-button>
|
||||
<el-radio-button label="picture-card">
|
||||
picture-card
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.buttonText !== undefined" v-show="'picture-card' !== activeData['list-type']"
|
||||
label="按钮文字">
|
||||
<el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
|
||||
<el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段">
|
||||
<el-input v-model="activeData['picker-options'].selectableRange" placeholder="请输入时间段" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.format !== undefined" label="时间格式">
|
||||
<el-input :value="activeData.format" placeholder="请输入时间格式" @input="setTimeValue($event)" />
|
||||
</el-form-item>
|
||||
<template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
|
||||
<el-divider>选项</el-divider>
|
||||
<draggable :list="activeData.options" :animation="340" group="selectItem" handle=".option-drag"
|
||||
item-key="label">
|
||||
<template #item="{ element, index }">
|
||||
<div :key="index" class="select-item">
|
||||
<div class="select-line-icon option-drag">
|
||||
<i class="el-icon-s-operation" />
|
||||
</div>
|
||||
<el-input v-model="element.label" placeholder="选项名" size="small" />
|
||||
<el-input placeholder="选项值" size="small" :value="element.value"
|
||||
@input="setOptionValue(element, $event)" />
|
||||
<div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
|
||||
<el-icon>
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<div>
|
||||
<el-button icon="CirclePlus" style="margin-left: 8px; margin-top: 10px;" text bg type="primary"
|
||||
@click="addSelectItem">
|
||||
添加选项
|
||||
</el-button>
|
||||
</div>
|
||||
<el-divider />
|
||||
</template>
|
||||
|
||||
<template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
|
||||
<el-divider>选项</el-divider>
|
||||
<el-form-item label="数据类型">
|
||||
<el-radio-group v-model="activeData.dataType" size="small">
|
||||
<el-radio-button label="dynamic">
|
||||
动态数据
|
||||
</el-radio-button>
|
||||
<el-radio-button label="static">
|
||||
静态数据
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="activeData.dataType === 'dynamic'">
|
||||
<el-form-item label="标签键名">
|
||||
<el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="值键名">
|
||||
<el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="子级键名">
|
||||
<el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-tree v-if="activeData.dataType === 'static'" draggable :data="activeData.options" node-key="id"
|
||||
:expand-on-click-node="false" :render-content="renderContent" />
|
||||
<div v-if="activeData.dataType === 'static'">
|
||||
<el-button icon="CirclePlus" style="margin-left: 0; margin-top: 10px;" type="primary" text bg
|
||||
@click="addTreeItem">
|
||||
添加父级
|
||||
</el-button>
|
||||
</div>
|
||||
<el-divider />
|
||||
</template>
|
||||
|
||||
<el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
|
||||
<el-radio-group v-model="activeData.optionType">
|
||||
<el-radio-button label="default">
|
||||
默认
|
||||
</el-radio-button>
|
||||
<el-radio-button label="button">
|
||||
按钮
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色">
|
||||
<el-color-picker v-model="activeData['active-color']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色">
|
||||
<el-color-picker v-model="activeData['inactive-color']" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
|
||||
<el-switch v-model="activeData['allow-half']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字">
|
||||
<el-switch v-model="activeData['show-text']" @change="rateTextChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数">
|
||||
<el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点">
|
||||
<el-switch v-model="activeData['show-stops']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.range !== undefined" label="范围选择">
|
||||
<el-switch v-model="activeData.range" @change="rangeChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.border !== undefined && activeData.optionType === 'default'" label="是否带边框">
|
||||
<el-switch v-model="activeData.border" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
|
||||
<el-select v-model="activeData['color-format']" placeholder="请选择颜色格式" :style="{ width: '100%' }"
|
||||
@change="colorFormatChange">
|
||||
<el-option v-for="(item, index) in colorFormatOptions" :key="index" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.size !== undefined &&
|
||||
(activeData.optionType === 'button' ||
|
||||
activeData.border ||
|
||||
activeData.tag === 'el-color-picker')" label="选项尺寸">
|
||||
<el-radio-group v-model="activeData.size">
|
||||
<el-radio-button label="large">
|
||||
较大
|
||||
</el-radio-button>
|
||||
<el-radio-button label="default">
|
||||
默认
|
||||
</el-radio-button>
|
||||
<el-radio-button label="small">
|
||||
较小
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
|
||||
<el-switch v-model="activeData['show-word-limit']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
|
||||
<el-switch v-model="activeData['step-strictly']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
|
||||
<el-switch v-model="activeData.props.props.multiple" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
|
||||
<el-switch v-model="activeData['show-all-levels']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
|
||||
<el-switch v-model="activeData.filterable" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
|
||||
<el-switch v-model="activeData.clearable" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
|
||||
<el-switch v-model="activeData.showTip" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
|
||||
<el-switch v-model="activeData.multiple" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
|
||||
<el-switch v-model="activeData['auto-upload']" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.readonly !== undefined" label="是否只读">
|
||||
<el-switch v-model="activeData.readonly" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
|
||||
<el-switch v-model="activeData.disabled" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
|
||||
<el-switch v-model="activeData.filterable" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
|
||||
<el-switch v-model="activeData.multiple" @change="multipleChange" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeData.required !== undefined" label="是否必填">
|
||||
<el-switch v-model="activeData.required" />
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="activeData.layoutTree">
|
||||
<el-divider>布局结构树</el-divider>
|
||||
<el-tree :data="[activeData]" :props="layoutTreeProps" node-key="renderKey" default-expand-all draggable>
|
||||
<template #default="{ node, data }">
|
||||
<span class="node-label">
|
||||
<svg-icon class="node-icon" :icon-class="data.tagIcon" style="margin-right: 5px;" />
|
||||
{{ node.label }}
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</template>
|
||||
|
||||
<template v-if="activeData.layout === 'colFormItem'">
|
||||
<el-divider>正则校验</el-divider>
|
||||
<div v-for="(item, index) in activeData.regList" :key="index" class="reg-item">
|
||||
<span class="close-btn" @click="activeData.regList.splice(index, 1)">
|
||||
<el-icon>
|
||||
<Close />
|
||||
</el-icon>
|
||||
</span>
|
||||
<el-form-item label="表达式">
|
||||
<el-input v-model="item.pattern" placeholder="请输入正则" />
|
||||
</el-form-item>
|
||||
<el-form-item label="错误提示" style="margin-bottom:0">
|
||||
<el-input v-model="item.message" placeholder="请输入错误提示" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-button icon="CirclePlus" style="margin-left: 0; margin-top: 10px;" type="primary" text bg
|
||||
@click="addReg">
|
||||
添加规则
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-form>
|
||||
<!-- 表单属性 -->
|
||||
<el-form v-show="currentTab === 'form'" label-width="90px" label-position="top">
|
||||
<el-form-item label="表单名">
|
||||
<el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="表单模型">
|
||||
<el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
|
||||
</el-form-item>
|
||||
<el-form-item label="校验模型">
|
||||
<el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
|
||||
</el-form-item>
|
||||
<el-form-item label="表单尺寸">
|
||||
<el-radio-group v-model="formConf.size">
|
||||
<el-radio-button label="large" value="较大" />
|
||||
<el-radio-button label="default" value="默认" />
|
||||
<el-radio-button label="small" value="较小" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签对齐">
|
||||
<el-radio-group v-model="formConf.labelPosition">
|
||||
<el-radio-button label="left" value="左对齐" />
|
||||
<el-radio-button label="right" value="右对齐" />
|
||||
<el-radio-button label="top" value="顶部对齐" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签宽度">
|
||||
<el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
|
||||
</el-form-item>
|
||||
<el-form-item label="栅格间隔">
|
||||
<el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
|
||||
</el-form-item>
|
||||
<el-form-item label="禁用表单">
|
||||
<el-switch v-model="formConf.disabled" />
|
||||
</el-form-item>
|
||||
<el-form-item label="表单按钮">
|
||||
<el-switch v-model="formConf.formBtns" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示未选中组件边框">
|
||||
<el-switch v-model="formConf.unFocusedComponentBorder" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<icons-dialog v-model="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
|
||||
<treeNode-dialog v-model="dialogVisible" @commit="addNode" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import draggable from "vuedraggable/dist/vuedraggable.common"
|
||||
import { isNumberStr } from '@/utils/index'
|
||||
import IconsDialog from './IconsDialog'
|
||||
import TreeNodeDialog from './TreeNodeDialog'
|
||||
import { inputComponents, selectComponents } from '@/utils/generator/config'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const dateTimeFormat = {
|
||||
date: 'YYYY-MM-DD',
|
||||
week: 'YYYY 第 ww 周',
|
||||
month: 'YYYY-MM',
|
||||
year: 'YYYY',
|
||||
datetime: 'YYYY-MM-DD HH:mm:ss',
|
||||
daterange: 'YYYY-MM-DD',
|
||||
monthrange: 'YYYY-MM',
|
||||
datetimerange: 'YYYY-MM-DD HH:mm:ss'
|
||||
}
|
||||
const props = defineProps({
|
||||
showField: Boolean,
|
||||
activeData: Object,
|
||||
formConf: Object
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
currentTab: 'field',
|
||||
currentNode: null,
|
||||
dialogVisible: false,
|
||||
iconsVisible: false,
|
||||
currentIconModel: null,
|
||||
dateTypeOptions: [
|
||||
{
|
||||
label: '日(date)',
|
||||
value: 'date'
|
||||
},
|
||||
{
|
||||
label: '周(week)',
|
||||
value: 'week'
|
||||
},
|
||||
{
|
||||
label: '月(month)',
|
||||
value: 'month'
|
||||
},
|
||||
{
|
||||
label: '年(year)',
|
||||
value: 'year'
|
||||
},
|
||||
{
|
||||
label: '日期时间(datetime)',
|
||||
value: 'datetime'
|
||||
}
|
||||
],
|
||||
dateRangeTypeOptions: [
|
||||
{
|
||||
label: '日期范围(daterange)',
|
||||
value: 'daterange'
|
||||
},
|
||||
{
|
||||
label: '月范围(monthrange)',
|
||||
value: 'monthrange'
|
||||
},
|
||||
{
|
||||
label: '日期时间范围(datetimerange)',
|
||||
value: 'datetimerange'
|
||||
}
|
||||
],
|
||||
colorFormatOptions: [
|
||||
{
|
||||
label: 'hex',
|
||||
value: 'hex'
|
||||
},
|
||||
{
|
||||
label: 'rgb',
|
||||
value: 'rgb'
|
||||
},
|
||||
{
|
||||
label: 'rgba',
|
||||
value: 'rgba'
|
||||
},
|
||||
{
|
||||
label: 'hsv',
|
||||
value: 'hsv'
|
||||
},
|
||||
{
|
||||
label: 'hsl',
|
||||
value: 'hsl'
|
||||
}
|
||||
],
|
||||
justifyOptions: [
|
||||
{
|
||||
label: 'start',
|
||||
value: 'start'
|
||||
},
|
||||
{
|
||||
label: 'end',
|
||||
value: 'end'
|
||||
},
|
||||
{
|
||||
label: 'center',
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
label: 'space-around',
|
||||
value: 'space-around'
|
||||
},
|
||||
{
|
||||
label: 'space-between',
|
||||
value: 'space-between'
|
||||
}
|
||||
],
|
||||
layoutTreeProps: {
|
||||
label(data, node) {
|
||||
return data.componentName || `${data.label}: ${data.vModel}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { currentTab, currentNode, dialogVisible, iconsVisible, currentIconModel, dateTypeOptions, dateRangeTypeOptions, colorFormatOptions, justifyOptions, layoutTreeProps } = toRefs(data)
|
||||
|
||||
const documentLink = computed(() => props.activeData.document || 'https://element-plus.org/zh-CN/guide/installation')
|
||||
|
||||
const dateOptions = computed(() => {
|
||||
if (props.activeData.type !== undefined && props.activeData.tag === 'el-date-picker') {
|
||||
if (props.activeData['start-placeholder'] === undefined) {
|
||||
return dateTypeOptions.value
|
||||
}
|
||||
return dateRangeTypeOptions.value
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const tagList = ref([
|
||||
{
|
||||
label: '输入型组件',
|
||||
options: inputComponents
|
||||
},
|
||||
{
|
||||
label: '选择型组件',
|
||||
options: selectComponents
|
||||
}
|
||||
])
|
||||
|
||||
const emit = defineEmits(['tag-change'])
|
||||
|
||||
function addReg() {
|
||||
props.activeData.regList.push({
|
||||
pattern: '',
|
||||
message: ''
|
||||
})
|
||||
}
|
||||
function addSelectItem() {
|
||||
props.activeData.options.push({
|
||||
label: '',
|
||||
value: ''
|
||||
})
|
||||
}
|
||||
|
||||
function addTreeItem() {
|
||||
++proxy.idGlobal
|
||||
dialogVisible.value = true
|
||||
currentNode.value = props.activeData.options
|
||||
}
|
||||
|
||||
function renderContent(h, { node, data, store }) {
|
||||
return h('div', {
|
||||
class: "custom-tree-node"
|
||||
}, [
|
||||
h('span', node.label),
|
||||
h('span', {
|
||||
class: "node-operation"
|
||||
}, [
|
||||
h(resolveComponent('el-link'), {
|
||||
type: "primary",
|
||||
icon: "Plus",
|
||||
underline: false,
|
||||
onClick: () => {
|
||||
append(data)
|
||||
|
||||
}
|
||||
}),
|
||||
h(resolveComponent('el-link'), {
|
||||
type: "danger",
|
||||
icon: "Delete",
|
||||
underline: false,
|
||||
style: "margin-left: 5px;",
|
||||
onClick: () => {
|
||||
remove(node, data)
|
||||
}
|
||||
})
|
||||
])
|
||||
])
|
||||
}
|
||||
function append(data) {
|
||||
if (!data.children) {
|
||||
data.children = []
|
||||
}
|
||||
dialogVisible.value = true
|
||||
currentNode.value = data.children
|
||||
}
|
||||
function remove(node, data) {
|
||||
const { parent } = node
|
||||
const children = parent.data.children || parent.data
|
||||
const index = children.findIndex(d => d.id === data.id)
|
||||
children.splice(index, 1)
|
||||
}
|
||||
function addNode(data) {
|
||||
currentNode.value.push(data)
|
||||
}
|
||||
|
||||
function setOptionValue(item, val) {
|
||||
item.value = isNumberStr(val) ? +val : val
|
||||
}
|
||||
function setDefaultValue(val) {
|
||||
if (Array.isArray(val)) {
|
||||
return val.join(',')
|
||||
}
|
||||
if (['string', 'number'].indexOf(val) > -1) {
|
||||
return val
|
||||
}
|
||||
if (typeof val === 'boolean') {
|
||||
return `${val}`
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
function onDefaultValueInput(str) {
|
||||
if (Array.isArray(props.activeData.defaultValue)) {
|
||||
// 数组
|
||||
props.activeData.defaultValue = str.split(',').map(val => (isNumberStr(val) ? +val : val))
|
||||
} else if (['true', 'false'].indexOf(str) > -1) {
|
||||
// 布尔
|
||||
props.activeData.defaultValue = JSON.parse(str)
|
||||
} else {
|
||||
// 字符串和数字
|
||||
props.activeData.defaultValue = isNumberStr(str) ? +str : str
|
||||
}
|
||||
}
|
||||
|
||||
function onSwitchValueInput(val, name) {
|
||||
if (['true', 'false'].indexOf(val) > -1) {
|
||||
props.activeData[name] = JSON.parse(val)
|
||||
} else {
|
||||
props.activeData[name] = isNumberStr(val) ? +val : val
|
||||
}
|
||||
}
|
||||
|
||||
function setTimeValue(val, type) {
|
||||
const valueFormat = type === 'week' ? dateTimeFormat.date : val
|
||||
props.activeData.defaultValue = null
|
||||
props.activeData['value-format'] = valueFormat
|
||||
props.activeData.format = val
|
||||
}
|
||||
|
||||
function spanChange(val) {
|
||||
props.formConf.span = val
|
||||
}
|
||||
|
||||
function multipleChange(val) {
|
||||
props.activeData.defaultValue = val ? [] : ''
|
||||
}
|
||||
|
||||
function dateTypeChange(val) {
|
||||
setTimeValue(dateTimeFormat[val], val)
|
||||
}
|
||||
|
||||
function rangeChange(val) {
|
||||
props.activeData.defaultValue = val ? [props.activeData.min, props.activeData.max] : props.activeData.min
|
||||
}
|
||||
|
||||
function rateTextChange(val) {
|
||||
if (val) props.activeData['show-score'] = false
|
||||
}
|
||||
|
||||
function rateScoreChange(val) {
|
||||
if (val) props.activeData['show-text'] = false
|
||||
}
|
||||
|
||||
function colorFormatChange(val) {
|
||||
props.activeData.defaultValue = null
|
||||
props.activeData['show-alpha'] = val.indexOf('a') > -1
|
||||
props.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
|
||||
}
|
||||
|
||||
function openIconsDialog(model) {
|
||||
iconsVisible.value = true
|
||||
currentIconModel.value = model
|
||||
}
|
||||
|
||||
function setIcon(val) {
|
||||
props.activeData[currentIconModel.value] = val
|
||||
}
|
||||
|
||||
function tagChange(tagIcon) {
|
||||
let target = inputComponents.find(item => item.tagIcon === tagIcon)
|
||||
if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
|
||||
emit('tag-change', target)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.right-board {
|
||||
width: 350px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding-top: 3px;
|
||||
|
||||
&:deep() {
|
||||
.el-tabs__header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-input-group__append .el-button {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.field-box {
|
||||
position: relative;
|
||||
height: calc(100vh - 50px - 40px - 42px);
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
|
||||
&:deep() {
|
||||
.el-scrollbar__view {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reg-item {
|
||||
padding: 12px 6px;
|
||||
background: var(--el-border-color-extra-light);
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: -6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
background: rgba(0, 0, 0, .2);
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-item {
|
||||
display: flex;
|
||||
border: 1px dashed #fff;
|
||||
box-sizing: border-box;
|
||||
|
||||
& .close-btn {
|
||||
cursor: pointer;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
& .el-input+.el-input {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-item+.select-item {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.select-item.sortable-chosen {
|
||||
border: 1px dashed #409eff;
|
||||
}
|
||||
|
||||
.select-line-icon {
|
||||
line-height: 32px;
|
||||
font-size: 22px;
|
||||
padding: 0 4px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.option-drag {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.time-range {
|
||||
.el-date-editor {
|
||||
width: 227px;
|
||||
}
|
||||
|
||||
:deep() {
|
||||
.el-icon-time {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.document-link {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: pointer;
|
||||
background: #409eff;
|
||||
z-index: 1;
|
||||
border-radius: 0 0 6px 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.node-label {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.node-icon {
|
||||
color: #bebfc3;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="添加选项" v-model="open" width="800px" :close-on-click-modal="false" :modal-append-to-body="false"
|
||||
@open="onOpen" @close="onClose">
|
||||
<el-form ref="treeNodeForm" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="选项名" prop="label">
|
||||
<el-input v-model="formData.label" placeholder="请输入选项名" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="选项值" prop="value">
|
||||
<el-input v-model="formData.value" placeholder="请输入选项值" clearable>
|
||||
<template #append>
|
||||
<el-select v-model="dataType" :style="{ width: '100px' }">
|
||||
<el-option v-for="(item, index) in dataTypeOptions" :key="index" :label="item.label" :value="item.value"
|
||||
:disabled="item.disabled" />
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handelConfirm">确 定</el-button>
|
||||
<el-button @click="onClose">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
const open = defineModel()
|
||||
const emit = defineEmits(['confirm'])
|
||||
const formData = ref({
|
||||
label: undefined,
|
||||
value: undefined
|
||||
})
|
||||
const rules = {
|
||||
label: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入选项名',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
value: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入选项值',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
const dataType = ref('string')
|
||||
const dataTypeOptions = ref([
|
||||
{
|
||||
label: '字符串',
|
||||
value: 'string'
|
||||
},
|
||||
{
|
||||
label: '数字',
|
||||
value: 'number'
|
||||
}
|
||||
])
|
||||
const id = ref(100)
|
||||
const treeNodeForm = ref()
|
||||
|
||||
function onOpen() {
|
||||
formData.value = {
|
||||
label: undefined,
|
||||
value: undefined
|
||||
}
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
open.value = false
|
||||
}
|
||||
|
||||
function handelConfirm() {
|
||||
treeNodeForm.value.validate(valid => {
|
||||
if (!valid) return
|
||||
if (dataType.value === 'number') {
|
||||
formData.value.value = parseFloat(formData.value.value)
|
||||
}
|
||||
formData.value.id = id.value++
|
||||
emit('commit', formData.value)
|
||||
onClose()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,653 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="left-board">
|
||||
<div class="logo-wrapper">
|
||||
<div class="logo">
|
||||
<img :src="logo" alt="logo"> Form Generator
|
||||
</div>
|
||||
</div>
|
||||
<el-scrollbar class="left-scrollbar">
|
||||
<div class="components-list">
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" />输入型组件
|
||||
</div>
|
||||
<draggable class="components-draggable" :list="inputComponents"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
|
||||
draggable=".components-item" :sort="false" @end="onEnd" item-key="label">
|
||||
<template #item="{ element, index }">
|
||||
<div :key="index" class="components-item" @click="addComponent(element)">
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.tagIcon" />
|
||||
{{ element.label }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" />选择型组件
|
||||
</div>
|
||||
<draggable class="components-draggable" :list="selectComponents"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
|
||||
draggable=".components-item" :sort="false" @end="onEnd" item-key="label">
|
||||
<template #item="{ element, index }">
|
||||
<div :key="index" class="components-item" @click="addComponent(element)">
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.tagIcon" />
|
||||
{{ element.label }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<div class="components-title">
|
||||
<svg-icon icon-class="component" /> 布局型组件
|
||||
</div>
|
||||
<draggable class="components-draggable" :list="layoutComponents"
|
||||
:group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
|
||||
draggable=".components-item" :sort="false" @end="onEnd" item-key="label">
|
||||
<template #item="{ element, index }">
|
||||
<div :key="index" class="components-item" @click="addComponent(element)">
|
||||
<div class="components-body">
|
||||
<svg-icon :icon-class="element.tagIcon" />
|
||||
{{ element.label }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<div class="center-board">
|
||||
<div class="action-bar">
|
||||
<el-button icon="Download" type="primary" text @click="download">
|
||||
导出vue文件
|
||||
</el-button>
|
||||
<el-button class="copy-btn-main" icon="DocumentCopy" type="primary" text @click="copy">
|
||||
复制代码
|
||||
</el-button>
|
||||
<el-button class="delete-btn" icon="Delete" text @click="empty" type="danger">
|
||||
清空
|
||||
</el-button>
|
||||
</div>
|
||||
<el-scrollbar class="center-scrollbar">
|
||||
<el-row class="center-board-row" :gutter="formConf.gutter">
|
||||
<el-form :size="formConf.size" :label-position="formConf.labelPosition" :disabled="formConf.disabled"
|
||||
:label-width="formConf.labelWidth + 'px'">
|
||||
<draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup"
|
||||
item-key="label">
|
||||
<template #item="{ element, index }">
|
||||
<draggable-item :key="element.renderKey" :drawing-list="drawingList" :element="element" :index="index"
|
||||
:active-id="activeId" :form-conf="formConf" @activeItem="activeFormItem" @copyItem="drawingItemCopy"
|
||||
@deleteItem="drawingItemDelete" />
|
||||
</template>
|
||||
</draggable>
|
||||
<div v-show="!drawingList.length" class="empty-info">
|
||||
从左侧拖入或点选组件进行表单设计
|
||||
</div>
|
||||
</el-form>
|
||||
</el-row>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<right-panel :active-data="activeData" :form-conf="formConf" :show-field="!!drawingList.length"
|
||||
@tag-change="tagChange" />
|
||||
|
||||
<code-type-dialog v-model="dialogVisible" title="选择生成类型" :showFileName="showFileName" @confirm="generate" />
|
||||
<input id="copyNode" type="hidden">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import draggable from "vuedraggable/dist/vuedraggable.common"
|
||||
import ClipboardJS from 'clipboard'
|
||||
import beautifier from 'js-beautify'
|
||||
import logo from '@/assets/logo/logo.png'
|
||||
import { inputComponents, selectComponents, layoutComponents, formConf as formConfData } from '@/utils/generator/config'
|
||||
import { beautifierConf } from '@/utils/index'
|
||||
import drawingDefalut from '@/utils/generator/drawingDefalut'
|
||||
import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
|
||||
import { makeUpJs } from '@/utils/generator/js'
|
||||
import { makeUpCss } from '@/utils/generator/css'
|
||||
import Download from '@/plugins/download'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import DraggableItem from './DraggableItem'
|
||||
import RightPanel from './RightPanel'
|
||||
import CodeTypeDialog from './CodeTypeDialog'
|
||||
import { onMounted, watch } from 'vue'
|
||||
|
||||
const drawingList = ref(drawingDefalut)
|
||||
const { proxy } = getCurrentInstance()
|
||||
const dialogVisible = ref(false)
|
||||
const showFileName = ref(false)
|
||||
const operationType = ref('')
|
||||
const idGlobal = ref(100)
|
||||
const activeData = ref(drawingDefalut[0])
|
||||
const activeId = ref(drawingDefalut[0].formId)
|
||||
const generateConf = ref(null)
|
||||
const formData = ref({})
|
||||
const formConf = ref(formConfData)
|
||||
let oldActiveId
|
||||
let tempActiveData
|
||||
|
||||
function activeFormItem(element) {
|
||||
activeData.value = element
|
||||
activeId.value = element.formId
|
||||
}
|
||||
function copy() {
|
||||
dialogVisible.value = true
|
||||
showFileName.value = false
|
||||
operationType.value = 'copy'
|
||||
}
|
||||
function download() {
|
||||
dialogVisible.value = true
|
||||
showFileName.value = true
|
||||
operationType.value = 'download'
|
||||
}
|
||||
function empty() {
|
||||
proxy.$modal.confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(() => {
|
||||
idGlobal.value = 100
|
||||
drawingList.value = []
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function onEnd(obj, a) {
|
||||
if (obj.from !== obj.to) {
|
||||
activeData.value = tempActiveData
|
||||
activeId.value = idGlobal.value
|
||||
}
|
||||
}
|
||||
|
||||
function addComponent(item) {
|
||||
const clone = cloneComponent(item)
|
||||
drawingList.value.push(clone)
|
||||
activeFormItem(clone)
|
||||
}
|
||||
|
||||
function cloneComponent(origin) {
|
||||
const clone = JSON.parse(JSON.stringify(origin))
|
||||
clone.formId = ++idGlobal.value
|
||||
clone.span = formConf.value.span
|
||||
clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
|
||||
if (!clone.layout) clone.layout = 'colFormItem'
|
||||
if (clone.layout === 'colFormItem') {
|
||||
clone.vModel = `field${idGlobal.value}`
|
||||
clone.placeholder !== undefined && (clone.placeholder += clone.label)
|
||||
tempActiveData = clone
|
||||
} else if (clone.layout === 'rowFormItem') {
|
||||
delete clone.label
|
||||
clone.componentName = `row${idGlobal.value}`
|
||||
clone.gutter = formConf.value.gutter
|
||||
tempActiveData = clone
|
||||
}
|
||||
return tempActiveData
|
||||
}
|
||||
|
||||
function drawingItemCopy(item, parent) {
|
||||
let clone = JSON.parse(JSON.stringify(item))
|
||||
clone = createIdAndKey(clone)
|
||||
parent.push(clone)
|
||||
activeFormItem(clone)
|
||||
}
|
||||
|
||||
|
||||
function createIdAndKey(item) {
|
||||
item.formId = ++idGlobal.value
|
||||
item.renderKey = +new Date()
|
||||
if (item.layout === 'colFormItem') {
|
||||
item.vModel = `field${idGlobal.value}`
|
||||
} else if (item.layout === 'rowFormItem') {
|
||||
item.componentName = `row${idGlobal.value}`
|
||||
}
|
||||
if (Array.isArray(item.children)) {
|
||||
item.children = item.children.map(childItem => createIdAndKey(childItem))
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
function drawingItemDelete(index, parent) {
|
||||
parent.splice(index, 1)
|
||||
nextTick(() => {
|
||||
const len = drawingList.value.length
|
||||
if (len) {
|
||||
activeFormItem(drawingList.value[len - 1])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function tagChange(newTag) {
|
||||
newTag = cloneComponent(newTag)
|
||||
newTag.vModel = activeData.value.vModel
|
||||
newTag.formId = activeId.value
|
||||
newTag.span = activeData.value.span
|
||||
delete activeData.value.tag
|
||||
delete activeData.value.tagIcon
|
||||
delete activeData.value.document
|
||||
Object.keys(newTag).forEach(key => {
|
||||
if (activeData.value[key] !== undefined
|
||||
&& typeof activeData.value[key] === typeof newTag[key]) {
|
||||
newTag[key] = activeData.value[key]
|
||||
}
|
||||
})
|
||||
activeData.value = newTag
|
||||
updateDrawingList(newTag, drawingList.value)
|
||||
}
|
||||
|
||||
|
||||
function updateDrawingList(newTag, list) {
|
||||
const index = list.findIndex(item => item.formId === activeId.value)
|
||||
if (index > -1) {
|
||||
list.splice(index, 1, newTag)
|
||||
} else {
|
||||
list.forEach(item => {
|
||||
if (Array.isArray(item.children)) updateDrawingList(newTag, item.children)
|
||||
})
|
||||
}
|
||||
}
|
||||
function generate(data) {
|
||||
generateConf.value = data
|
||||
nextTick(() => {
|
||||
switch (operationType.value) {
|
||||
case 'copy':
|
||||
execCopy(data)
|
||||
break
|
||||
case 'download':
|
||||
execDownload(data)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function execDownload(data) {
|
||||
const codeStr = generateCode()
|
||||
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
|
||||
Download.saveAs(blob, data.fileName)
|
||||
}
|
||||
|
||||
function execCopy(data) {
|
||||
document.getElementById('copyNode').click()
|
||||
}
|
||||
function AssembleFormData() {
|
||||
formData.value = { fields: JSON.parse(JSON.stringify(drawingList.value)), ...formConf.value }
|
||||
}
|
||||
function generateCode() {
|
||||
const { type } = generateConf.value
|
||||
AssembleFormData()
|
||||
const script = vueScript(makeUpJs(formData.value, type))
|
||||
const html = vueTemplate(makeUpHtml(formData.value, type))
|
||||
const css = cssStyle(makeUpCss(formData.value))
|
||||
return beautifier.html(html + script + css, beautifierConf.html)
|
||||
}
|
||||
watch(() => activeData.value.label, (val, oldVal) => {
|
||||
if (
|
||||
activeData.value.placeholder === undefined
|
||||
|| !activeData.value.tag
|
||||
|| oldActiveId !== activeId.value
|
||||
) {
|
||||
return
|
||||
}
|
||||
activeData.value.placeholder = activeData.value.placeholder.replace(oldVal, '') + val
|
||||
})
|
||||
watch(activeId, (val) => {
|
||||
oldActiveId = val
|
||||
}, { immediate: true })
|
||||
|
||||
onMounted(() => {
|
||||
const clipboard = new ClipboardJS('#copyNode', {
|
||||
text: trigger => {
|
||||
const codeStr = generateCode()
|
||||
ElNotification({ title: '成功', message: '代码已复制到剪切板,可粘贴。', type: 'success' })
|
||||
return codeStr
|
||||
}
|
||||
})
|
||||
clipboard.on('error', e => {
|
||||
proxy.$modal.msgError('代码复制失败')
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
$lighterBlue: #409EFF;
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background-color: var(--el-bg-color-overlay);
|
||||
height: calc(100vh - 50px - 40px);
|
||||
overflow: hidden;
|
||||
|
||||
.left-board {
|
||||
width: 260px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: calc(100vh - 50px - 40px);
|
||||
|
||||
.logo-wrapper {
|
||||
position: relative;
|
||||
height: 42px;
|
||||
border-bottom: 1px solid var(--el-border-color-extra-light);
|
||||
box-sizing: border-box;
|
||||
|
||||
.logo {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 6px;
|
||||
line-height: 30px;
|
||||
color: #00afff;
|
||||
font-weight: 600;
|
||||
font-size: 17px;
|
||||
white-space: nowrap;
|
||||
|
||||
>img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.github {
|
||||
display: inline-block;
|
||||
vertical-align: sub;
|
||||
margin-left: 15px;
|
||||
|
||||
>img {
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left-scrollbar {
|
||||
.el-scrollbar__wrap {
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden !important;
|
||||
margin-bottom: 0 !important;
|
||||
|
||||
.components-list {
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
|
||||
.components-title {
|
||||
font-size: 14px;
|
||||
// color: #222;
|
||||
margin: 6px 2px;
|
||||
|
||||
.svg-icon {
|
||||
// color: #666;
|
||||
font-size: 18px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.components-draggable {
|
||||
padding-bottom: 20px;
|
||||
|
||||
.components-item {
|
||||
display: inline-block;
|
||||
width: 48%;
|
||||
margin: 1%;
|
||||
transition: transform 0ms !important;
|
||||
|
||||
.components-body {
|
||||
padding: 8px 10px;
|
||||
background: var(--el-border-color-extra-light);
|
||||
font-size: 12px;
|
||||
cursor: move;
|
||||
border: 1px dashed var(--el-border-color-extra-light);
|
||||
border-radius: 3px;
|
||||
|
||||
.svg-icon {
|
||||
// color: #777;
|
||||
font-size: 15px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed #787be8;
|
||||
color: #787be8;
|
||||
|
||||
.svg-icon {
|
||||
color: #787be8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center-board {
|
||||
height: calc(100vh - 50px - 40px);
|
||||
width: auto;
|
||||
margin: 0 350px 0 260px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.action-bar {
|
||||
position: relative;
|
||||
height: 42px;
|
||||
padding: 0 15px;
|
||||
box-sizing: border-box;
|
||||
;
|
||||
border: 1px solid var(--el-border-color-extra-light);
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
u .delete-btn {
|
||||
color: #F56C6C;
|
||||
}
|
||||
}
|
||||
|
||||
.center-scrollbar {
|
||||
height: calc(100vh - 50px - 40px - 42px);
|
||||
overflow: hidden;
|
||||
border-left: 1px solid var(--el-border-color-extra-light);
|
||||
border-right: 1px solid var(--el-border-color-extra-light);
|
||||
box-sizing: border-box;
|
||||
|
||||
.el-scrollbar__view {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.center-board-row {
|
||||
padding: 12px 12px 15px 12px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&>.el-form {
|
||||
// 69 = 12+15+42
|
||||
height: calc(100vh - 50px - 40px - 69px);
|
||||
flex: 1;
|
||||
|
||||
.drawing-board {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.components-body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.sortable-ghost {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 3px;
|
||||
background: rgb(89, 89, 223);
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.components-item.sortable-ghost {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: var(--el-border-color-extra-light);
|
||||
}
|
||||
|
||||
.active-from-item {
|
||||
&>.el-form-item {
|
||||
background: var(--el-border-color-extra-light);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&>.drawing-item-copy,
|
||||
&>.drawing-item-delete {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
&>.component-name {
|
||||
color: $lighterBlue;
|
||||
}
|
||||
|
||||
.el-input__wrapper {
|
||||
box-shadow: 0 0 0 1px var(--el-input-hover-border-color) inset;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawing-item {
|
||||
position: relative;
|
||||
cursor: move;
|
||||
|
||||
&.unfocus-bordered:not(.activeFromItem)>div:first-child {
|
||||
border: 1px dashed #ccc;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
padding: 12px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawing-row-item {
|
||||
position: relative;
|
||||
cursor: move;
|
||||
box-sizing: border-box;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 3px;
|
||||
padding: 0 2px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.drawing-row-item {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.el-col {
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.drag-wrapper {
|
||||
min-height: 80px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&.active-from-item {
|
||||
border: 1px dashed $lighterBlue;
|
||||
}
|
||||
|
||||
.component-name {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
font-size: 12px;
|
||||
color: #bbb;
|
||||
display: inline-block;
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawing-item,
|
||||
.drawing-row-item {
|
||||
&:hover {
|
||||
&>.el-form-item {
|
||||
background: var(--el-border-color-extra-light);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&>.drawing-item-copy,
|
||||
&>.drawing-item-delete {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
||||
&>.drawing-item-copy,
|
||||
&>.drawing-item-delete {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
font-size: 12px;
|
||||
border: 1px solid;
|
||||
cursor: pointer;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&>.drawing-item-copy {
|
||||
right: 56px;
|
||||
border-color: $lighterBlue;
|
||||
color: $lighterBlue;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
background: $lighterBlue;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&>.drawing-item-delete {
|
||||
right: 24px;
|
||||
border-color: #F56C6C;
|
||||
color: #F56C6C;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
background: #F56C6C;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-info {
|
||||
position: absolute;
|
||||
top: 46%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #ccb1ea;
|
||||
letter-spacing: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<!-- 创建表 -->
|
||||
<el-dialog title="创建表" v-model="visible" width="800px" top="5vh" append-to-body>
|
||||
<span>创建表语句(支持多个建表语句):</span>
|
||||
<el-input type="textarea" :rows="10" placeholder="请输入文本" v-model="content"></el-input>
|
||||
<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 { createTable } from "@/api/tool/gen"
|
||||
|
||||
const visible = ref(false)
|
||||
const content = ref("")
|
||||
const { proxy } = getCurrentInstance()
|
||||
const emit = defineEmits(["ok"])
|
||||
|
||||
/** 显示弹框 */
|
||||
function show() {
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
/** 导入按钮操作 */
|
||||
function handleImportTable() {
|
||||
if (content.value === "") {
|
||||
proxy.$modal.msgError("请输入建表语句")
|
||||
return
|
||||
}
|
||||
createTable({ sql: content.value }).then(res => {
|
||||
proxy.$modal.msgSuccess(res.msg)
|
||||
if (res.code === 200) {
|
||||
visible.value = false
|
||||
emit("ok")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
<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%" class-name="allowDrag"/>
|
||||
<el-table-column label="字段列名" prop="columnName" min-width="10%" :show-overflow-tooltip="true" class-name="allowDrag"/>
|
||||
<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-value="1" false-value="0" v-model="scope.row.isInsert"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="编辑" min-width="5%">
|
||||
<template #default="scope">
|
||||
<el-checkbox true-value="1" false-value="0" v-model="scope.row.isEdit"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="列表" min-width="5%">
|
||||
<template #default="scope">
|
||||
<el-checkbox true-value="1" false-value="0" v-model="scope.row.isList"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="查询" min-width="5%">
|
||||
<template #default="scope">
|
||||
<el-checkbox true-value="1" false-value="0" v-model="scope.row.isQuery"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="查询方式" min-width="10%">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.queryType">
|
||||
<el-option label="=" value="EQ" />
|
||||
<el-option label="!=" value="NE" />
|
||||
<el-option label=">" value="GT" />
|
||||
<el-option label=">=" value="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-value="1" false-value="0" v-model="scope.row.isRequired"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="显示类型" min-width="12%">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.htmlType">
|
||||
<el-option label="文本框" value="input" />
|
||||
<el-option label="文本域" value="textarea" />
|
||||
<el-option label="下拉框" value="select" />
|
||||
<el-option label="单选框" value="radio" />
|
||||
<el-option label="复选框" value="checkbox" />
|
||||
<el-option label="日期控件" value="datetime" />
|
||||
<el-option label="图片上传" value="imageUpload" />
|
||||
<el-option label="文件上传" value="fileUpload" />
|
||||
<el-option label="富文本控件" value="editor" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字典类型" min-width="12%">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in dictOptions"
|
||||
:key="dict.dictType"
|
||||
:label="dict.dictName"
|
||||
:value="dict.dictType">
|
||||
<span style="float: left">{{ dict.dictName }}</span>
|
||||
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="生成信息" name="genInfo">
|
||||
<gen-info-form ref="genInfo" :info="info" :tables="tables" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form label-width="100px">
|
||||
<div style="text-align: center;margin-left:-100px;margin-top:10px;">
|
||||
<el-button type="primary" @click="submitForm()">提交</el-button>
|
||||
<el-button @click="close()">返回</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup name="GenEdit">
|
||||
import { getGenTable, updateGenTable } from "@/api/tool/gen"
|
||||
import { optionselect as getDictOptionselect } from "@/api/system/dict/type"
|
||||
import basicInfoForm from "./basicInfoForm"
|
||||
import genInfoForm from "./genInfoForm"
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
})()
|
||||
|
||||
// 拖动排序
|
||||
onMounted(() => {
|
||||
const element = document.querySelector('.el-table__body > tbody')
|
||||
Sortable.create(element, {
|
||||
handle: ".allowDrag",
|
||||
onEnd: (evt) => {
|
||||
const targetRow = columns.value.splice(evt.oldIndex, 1)[0]
|
||||
columns.value.splice(evt.newIndex, 0, targetRow)
|
||||
for (const index in columns.value) {
|
||||
columns.value[index].sort = parseInt(index) + 1
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
<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="tplWebType">
|
||||
<template #label>前端类型</template>
|
||||
<el-select v-model="info.tplWebType">
|
||||
<el-option label="Vue2 Element UI 模版" value="element-ui" />
|
||||
<el-option label="Vue3 Element Plus 模版" value="element-plus" />
|
||||
</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 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" value="0">zip压缩包</el-radio>
|
||||
<el-radio v-model="info.genType" value="1">自定义路径</el-radio>
|
||||
</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>
|
||||
<el-tree-select
|
||||
v-model="info.parentMenuId"
|
||||
:data="menuOptions"
|
||||
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
||||
value-key="menuId"
|
||||
placeholder="请选择系统菜单"
|
||||
check-strictly
|
||||
/>
|
||||
</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
|
||||