字典管理

This commit is contained in:
zhang zhuo 2025-12-01 16:25:16 +08:00
parent ceb69f9f45
commit b293209126
9 changed files with 516 additions and 11 deletions

View File

@ -178,4 +178,44 @@ export default {
return await http.get("system_config/option", data);
},
},
dict: {
list: async function (data = {}) {
return await http.get("dict/list", data);
},
info: async function (data = {}) {
return await http.get("dict/list", data);
},
add: async function (data = {}) {
return await http.post("dict/add", data);
},
edit: async function (data = {}) {
return await http.put("dict/edit", data);
},
del: async function (data = {}) {
return await http.delete("dict/del", data);
},
option: async function (data = {}) {
return await http.get("dict/option", data);
},
},
dict_data: {
list: async function (data = {}) {
return await http.get("dict_data/list", data);
},
info: async function (data = {}) {
return await http.get("dict_data/list", data);
},
add: async function (data = {}) {
return await http.post("dict_data/add", data);
},
edit: async function (data = {}) {
return await http.put("dict_data/edit", data);
},
del: async function (data = {}) {
return await http.delete("dict_data/del", data);
},
option: async function (data = {}) {
return await http.get("dict_data/option", data);
},
},
}

View File

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -71,15 +71,18 @@ function add() {
}
//
async function edit(row) {
function edit(row) {
dialogShow.value = true
nextTick(() => {
dialogRef.value.open('edit', row)
if (row instanceof PointerEvent) {
row = selection.value[0]
}
dialogRef.value.open('edit', row || selection.value[0])
})
}
//
async function show(row) {
function show(row) {
dialogShow.value = true
nextTick(() => {
dialogRef.value.open('show', row)

View File

@ -47,7 +47,14 @@ let form = ref({
config_value: null,
remark: null
})
const rules = ref({})
const rules = ref({
config_name: [
{required: true, message: '请填写参数名称'}
],
config_key: [
{required: true, message: '请填写参数键名'}
]
})
function open(m = 'add', data = null) {
mode.value = m

View File

@ -0,0 +1,124 @@
<template>
<pi-table ref="tableRef" :apiObj="api.system.dict.list" @selection-change="selectionChange">
<template #do>
<el-button v-auth="'dict:add'" type="primary" icon="el-icon-plus" @click="add"></el-button>
<el-button v-auth="'dict:edit'" type="success" icon="el-icon-edit" @click="edit"
:disabled="selection.length!==1"></el-button>
<el-button v-auth="'dict:del'" type="danger" plain icon="el-icon-delete"
:disabled="selection.length===0" @click="batch_del"></el-button>
</template>
<template #search>
<el-input v-model="search.dict_name" placeholder="字典名称" clearable style="width: 200px;"></el-input>
<el-input v-model="search.dict_type" placeholder="字典类型" clearable style="width: 200px;"></el-input>
<el-button type="primary" icon="el-icon-search" @click="upsearch"></el-button>
</template>
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column label="ID" prop="dict_id"></el-table-column>
<el-table-column label="字典名称" prop="dict_name"></el-table-column>
<el-table-column label="字典类型" prop="dict_type">
<template #default="scope">
<el-link type="primary" :underline="'never'" :href="`#/system/dict_data?id=${scope.row.dict_id}`">{{scope.row.dict_type}}</el-link>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="创建时间" prop="create_time"></el-table-column>
<el-table-column label="更新时间" prop="update_time"></el-table-column>
<el-table-column label="操作" fixed="right" align="right" width="170">
<template #default="scope">
<el-button-group>
<el-button text type="primary" size="small" @click="show(scope.row, scope.$index)">查看
</el-button>
<el-button v-auth="'dict:edit'" text type="success" size="small"
@click="edit(scope.row, scope.$index)">编辑
</el-button>
<el-popconfirm title="确定删除吗?" @confirm="del(scope.row, scope.$index)">
<template #reference>
<el-button v-auth="'dict:del'" text type="danger" size="small">删除</el-button>
</template>
</el-popconfirm>
</el-button-group>
</template>
</el-table-column>
</pi-table>
<save-dialog v-if="dialogShow" ref="dialogRef" @success="tableRef.refresh()" @closed="dialogShow=false"></save-dialog>
</template>
<script setup>
import saveDialog from './save'
import api from "@/api/index"
import {getCurrentInstance, nextTick, ref} from "vue";
defineOptions({
name: "dict"
})
const {proxy} = getCurrentInstance()
const tableRef = ref(null)
const dialogRef = ref(null)
let dialogShow = ref(false)
let selection = ref([])
let search = ref({
dict_name: null,
dict_type: null
})
//
function add() {
dialogShow.value = true
nextTick(() => {
dialogRef.value.open()
})
}
//
function edit(row) {
dialogShow.value = true
nextTick(() => {
if (row instanceof PointerEvent) {
row = selection.value[0]
}
dialogRef.value.open('edit', row)
})
}
//
function show(row) {
dialogShow.value = true
nextTick(() => {
dialogRef.value.open('show', row)
})
}
//
async function del(row) {
const loading = proxy.$loading();
const res = await api.system.dict.del({ids: [row.dict_id]});
tableRef.value.refresh()
loading.close();
proxy.$message.success(res.msg)
}
//
async function batch_del() {
proxy.$confirm(`确定删除选中的 ${selection.value.length} 项吗?如果删除项中含有子集将会被一并删除`, '提示', {
type: 'warning'
}).then(async () => {
const loading = proxy.$loading();
const res = await api.dict.system.del({ids: selection.value.map(item => item.dict_id)});
tableRef.value.refresh()
loading.close();
proxy.$message.success(res.msg)
})
}
//
function selectionChange(e) {
selection.value = e;
}
//
function upsearch() {
tableRef.value.upData(search.value)
}
</script>

View File

@ -0,0 +1,75 @@
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode==='show'" ref="formRef" label-width="100px">
<el-form-item label="字典名称" prop="dict_name">
<el-input type="text" v-model="form.dict_name" placeholder="请输入字典名称" clearable></el-input>
</el-form-item>
<el-form-item label="字典类型" prop="dict_type">
<el-input type="text" v-model="form.dict_type" placeholder="请输入字典类型" clearable></el-input>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="form.remark" placeholder="请输入备注" clearable></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible=false"> </el-button>
<el-button v-if="mode!=='show'" type="primary" :loading="isSaveing" @click="submit()"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import {getCurrentInstance, ref} from 'vue'
import api from "@/api/index"
defineExpose({
open
})
const emit = defineEmits(['success', 'closed'])
const formRef = ref(null)
const {proxy} = getCurrentInstance()
let mode = ref('add')
let titleMap = ref({
add: '新增',
edit: '编辑',
show: '查看'
})
let visible = ref(false)
let isSaveing = ref(false)
let form = ref({
dict_id: null,
dict_name: null,
dict_type: null,
remark: null
})
const rules = ref({
dict_name: [
{required: true, message: '请填写字典名称'}
],
dict_type: [
{required: true, message: '请填写字典类型'}
]
})
function open(m = 'add', data = null) {
mode.value = m
visible.value = true
Object.assign(form.value, data)
}
async function submit() {
//
const validate = await formRef.value.validate().catch(() => {
});
if (!validate) {
return false
}
isSaveing.value = true;
const res = form.value.dict_id ? await api.system.dict.edit(form.value) : await api.system.dict.add(form.value);
isSaveing.value = false;
emit('success')
visible.value = false;
proxy.$message.success(res.msg)
}
</script>

View File

@ -0,0 +1,155 @@
<template>
<pi-table ref="tableRef" :params="search" :apiObj="api.system.dict_data.list" @selection-change="selectionChange">
<template #extend>
<el-select v-model="search.status" style="width: 200px;" placeholder="是否启用" clearable>
<el-option label="启用" :value="1"></el-option>
<el-option label="禁用" :value="0"></el-option>
</el-select>
</template>
<template #do>
<el-button v-auth="'dict_data:add'" type="primary" icon="el-icon-plus" @click="add"></el-button>
<el-button v-auth="'dict_data:edit'" type="success" icon="el-icon-edit" @click="edit"
:disabled="selection.length!==1"></el-button>
<el-button v-auth="'dict_data:del'" type="danger" plain icon="el-icon-delete"
:disabled="selection.length===0" @click="batch_del"></el-button>
</template>
<template #search>
<el-select v-model="search.dict_id" style="width: 200px;" placeholder="字典ID" clearable>
<el-option v-for="item in dict" :label="item.dict_name" :value="item.dict_id"></el-option>
</el-select>
<el-input v-model="search.dict_label" placeholder="字典标签" clearable style="width: 200px;"></el-input>
<el-button type="primary" icon="el-icon-search" @click="upsearch"></el-button>
</template>
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column label="ID" prop="data_id"></el-table-column>
<el-table-column label="字典标签" prop="dict_label"></el-table-column>
<el-table-column label="字典键值" prop="dict_value"></el-table-column>
<el-table-column label="是否启用" prop="status">
<template #default="scope">
<el-tag v-if="scope.row.status" type="primary"></el-tag>
<el-tag v-else type="info"></el-tag>
</template>
</el-table-column>
<el-table-column label="是否默认" prop="is_default">
<template #default="scope">
<el-tag v-if="scope.row.is_default" type="primary"></el-tag>
<el-tag v-else type="info"></el-tag>
</template>
</el-table-column>
<el-table-column label="排序" prop="rank"></el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
<el-table-column label="创建时间" prop="create_time"></el-table-column>
<el-table-column label="更新时间" prop="update_time"></el-table-column>
<el-table-column label="操作" fixed="right" align="right" width="170">
<template #default="scope">
<el-button-group>
<el-button text type="primary" size="small" @click="show(scope.row, scope.$index)">查看
</el-button>
<el-button v-auth="'dict_data:edit'" text type="success" size="small"
@click="edit(scope.row, scope.$index)">编辑
</el-button>
<el-popconfirm title="确定删除吗?" @confirm="del(scope.row, scope.$index)">
<template #reference>
<el-button v-auth="'dict_data:del'" text type="danger" size="small">删除</el-button>
</template>
</el-popconfirm>
</el-button-group>
</template>
</el-table-column>
</pi-table>
<save-dialog v-if="dialogShow" ref="dialogRef" @success="tableRef.refresh()"
@closed="dialogShow=false"></save-dialog>
</template>
<script setup>
import saveDialog from './save'
import api from "@/api/index";
import {getCurrentInstance, nextTick, ref, onMounted} from "vue";
import {useRoute} from 'vue-router'
defineOptions({
name: "dictData"
})
const {proxy} = getCurrentInstance()
const tableRef = ref(null)
const dialogRef = ref(null)
const route = useRoute()
let dialogShow = ref(false)
let selection = ref([])
let search = ref({
dict_id: route.query.id ? parseInt(route.query.id) : null,
dict_label: null,
status: null,
})
let dict = ref([])
onMounted(() => {
loadDict()
})
async function loadDict() {
const res = await api.system.dict.option()
dict.value = res.data
}
//
function add() {
dialogShow.value = true
nextTick(() => {
dialogRef.value.setDicts(dict.value).open('add', {dict_id: search.value.dict_id})
})
}
//
function edit(row) {
dialogShow.value = true
nextTick(() => {
if (row instanceof PointerEvent) {
row = selection.value[0]
}
dialogRef.value.setDicts(dict.value).open('edit', row)
})
}
//
function show(row) {
dialogShow.value = true
nextTick(() => {
dialogRef.value.setDicts(dict.value).open('show', row)
})
}
//
async function del(row) {
const loading = proxy.$loading();
const res = await api.system.dict_data.del({ids: [row.data_id]});
tableRef.value.refresh()
loading.close();
proxy.$message.success(res.msg)
}
//
async function batch_del() {
proxy.$confirm(`确定删除选中的 ${selection.value.length} 项吗?如果删除项中含有子集将会被一并删除`, '提示', {
type: 'warning'
}).then(async () => {
const loading = proxy.$loading();
const res = await api.system.dict_data.del({ids: selection.value.map(item => item.data_id)});
tableRef.value.refresh()
loading.close();
proxy.$message.success(res.msg)
})
}
//
function selectionChange(e) {
selection.value = e;
}
//
function upsearch() {
tableRef.value.upData(search.value)
}
</script>

View File

@ -0,0 +1,103 @@
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode==='show'" ref="formRef" label-width="100px">
<el-form-item label="字典ID" prop="dict_id">
<el-select v-model="form.dict_id" style="width: 100%" disabled placeholder="请选择字典ID">
<el-option v-for="item in dicts" :value="item.dict_id" :label="item.dict_name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="字典标签" prop="dict_label">
<el-input type="text" v-model="form.dict_label" placeholder="请输入字典标签" clearable></el-input>
</el-form-item>
<el-form-item label="字典键值" prop="dict_value">
<el-input type="text" v-model="form.dict_value" placeholder="请输入字典键值" clearable></el-input>
</el-form-item>
<el-form-item label="是否启用" prop="status">
<el-switch v-model="form.status" :active-value="1" :inactive-value="0"/>
</el-form-item>
<el-form-item label="是否默认" prop="is_default">
<el-switch v-model="form.is_default" :active-value="1" :inactive-value="0"/>
</el-form-item>
<el-form-item label="排序" prop="rank">
<el-input type="number" v-model="form.rank" placeholder="请输入排序" clearable></el-input>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注" :rows="3" clearable></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible=false"> </el-button>
<el-button v-if="mode!=='show'" type="primary" :loading="isSaveing" @click="submit()"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import {getCurrentInstance, ref} from 'vue'
import api from "@/api/index"
defineExpose({
open,
setDicts
})
const emit = defineEmits(['success', 'closed'])
const formRef = ref(null)
const {proxy} = getCurrentInstance()
const dicts = ref([])
let mode = ref('add')
let titleMap = ref({
add: '新增',
edit: '编辑',
show: '查看'
})
let visible = ref(false)
let isSaveing = ref(false)
let form = ref({
data_id: null,
dict_id: null,
dict_label: null,
dict_value: null,
is_default: 0,
rank: 1,
status: 1,
remark: null,
})
const rules = ref({
dict_id: [
{required: true, message: '请填写字典ID'}
],
dict_label: [
{required: true, message: '请填写字典标签'}
],
dict_value: [
{required: true, message: '请填写字典数值'}
],
})
function open(m = 'add', data = null) {
mode.value = m
visible.value = true
Object.assign(form.value, data)
}
function setDicts(data) {
dicts.value = data
return {open}
}
async function submit() {
//
const validate = await formRef.value.validate().catch(() => {
});
if (!validate) {
return false
}
isSaveing.value = true;
const res = form.value.data_id ? await api.system.dict_data.edit(form.value) : await api.system.dict_data.add(form.value);
isSaveing.value = false;
emit('success')
visible.value = false;
proxy.$message.success(res.msg)
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<div class="login_bg">
<div class="login_adv" style="background-image: url('./images/bg.jpg');">
<div class="login_adv" :style="{ backgroundImage: `url(${bg})` }">
</div>
<div class="login_main">
<div class="login_config">
@ -56,9 +56,6 @@
<el-col :span="12">
<el-checkbox :label="t('login.rememberMe')" v-model="form.autologin"></el-checkbox>
</el-col>
<!-- <el-col :span="12" class="login-forgot">-->
<!-- <router-link to="/reset_password">{{ t('login.forgetPassword') }}</router-link>-->
<!-- </el-col>-->
</el-form-item>
<el-form-item>
<el-button type="primary" style="width: 100%;" :loading="isLogin" round @click="login">
@ -74,10 +71,10 @@
<script setup>
import {getCurrentInstance, ref, onMounted, watch} from 'vue'
import {useI18n} from 'vue-i18n'
import {useRouter, useRoute} from 'vue-router';
import {useRouter, useRoute} from 'vue-router'
import tools from "@/utils/tools";
import sysConfig from "@/config/index";
import api from "@/api/index";
import sysConfig from "@/config/index"
import api from "@/api/index"
defineOptions({
name: 'login'
@ -87,6 +84,7 @@ const {proxy} = getCurrentInstance()
const {t, locale} = useI18n()
const router = useRouter()
const route = useRoute()
import bg from '@/assets/images/bg.jpg'
let lang = ref(tools.data.get('APP_LANG') || sysConfig.LANG)
let dark = ref(false)