feat: 封装公共表单/表格组件 BasicForm/BasicTable,并替换业务页面表格

- 新增 BasicForm 配置驱动表单组件,支持多种控件、字典自动加载、校验、插槽扩展
- 新增 BasicTable 公共表格组件,集成搜索栏+工具栏+表格+分页,基于 columns/searchColumns 配置驱动
- 替换 18 个业务页面 el-table 为 BasicTable(post/user/role/dict/config/notice/job/log/logininfor/operlog/online/gen 等)
- 全局注册 BasicForm、BasicTable 组件
- 项目标题由若依管理系统改为 BMS
This commit is contained in:
wuweihua
2026-08-28 11:35:26 +08:00
parent 838965c5a1
commit 3e9b34e0fd
27 changed files with 4593 additions and 4916 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
# 页面标题
VITE_APP_TITLE = 若依管理系统
VITE_APP_TITLE = BMS
# 开发环境配置
VITE_APP_ENV = 'development'
# 若依管理系统/开发环境
# BMS/开发环境
VITE_APP_BASE_API = '/dev-api'
+2 -2
View File
@@ -1,10 +1,10 @@
# 页面标题
VITE_APP_TITLE = 若依管理系统
VITE_APP_TITLE = BMS
# 生产环境配置
VITE_APP_ENV = 'production'
# 若依管理系统/生产环境
# BMS/生产环境
VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
+2 -2
View File
@@ -1,10 +1,10 @@
# 页面标题
VITE_APP_TITLE = 若依管理系统
VITE_APP_TITLE = BMS
# 生产环境配置
VITE_APP_ENV = 'staging'
# 若依管理系统/生产环境
# BMS/生产环境
VITE_APP_BASE_API = '/stage-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "ruoyi",
"version": "3.9.2",
"description": "若依管理系统",
"description": "BMS",
"author": "若依",
"license": "MIT",
"type": "module",
+182
View File
@@ -0,0 +1,182 @@
<template>
<!-- 输入框 -->
<el-input
v-if="comp === 'input'"
v-model="model[item.prop]"
:placeholder="placeholder"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 文本域 -->
<el-input
v-else-if="comp === 'textarea'"
v-model="model[item.prop]"
type="textarea"
:placeholder="placeholder"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 数字输入 -->
<el-input-number
v-else-if="comp === 'inputNumber'"
v-model="model[item.prop]"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 下拉选择 -->
<el-select
v-else-if="comp === 'select'"
v-model="model[item.prop]"
:placeholder="placeholder || '请选择'"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
>
<el-option
v-for="opt in options"
:key="opt[valueKey]"
:label="opt[labelKey]"
:value="opt[valueKey]"
/>
</el-select>
<!-- 单选组 -->
<el-radio-group
v-else-if="comp === 'radio'"
v-model="model[item.prop]"
:disabled="item.disabled"
v-bind="item.props"
>
<el-radio v-for="opt in options" :key="opt[valueKey]" :value="opt[valueKey]">{{ opt[labelKey] }}</el-radio>
</el-radio-group>
<!-- 复选组 -->
<el-checkbox-group
v-else-if="comp === 'checkbox'"
v-model="model[item.prop]"
:disabled="item.disabled"
v-bind="item.props"
>
<el-checkbox v-for="opt in options" :key="opt[valueKey]" :value="opt[valueKey]">{{ opt[labelKey] }}</el-checkbox>
</el-checkbox-group>
<!-- 开关 -->
<el-switch
v-else-if="comp === 'switch'"
v-model="model[item.prop]"
:disabled="item.disabled"
v-bind="item.props"
/>
<!-- 日期 -->
<el-date-picker
v-else-if="comp === 'date'"
v-model="model[item.prop]"
type="date"
:placeholder="placeholder || '请选择日期'"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD"
v-bind="item.props"
/>
<!-- 日期时间 -->
<el-date-picker
v-else-if="comp === 'datetime'"
v-model="model[item.prop]"
type="datetime"
:placeholder="placeholder || '请选择日期时间'"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD HH:mm:ss"
v-bind="item.props"
/>
<!-- 日期范围 -->
<el-date-picker
v-else-if="comp === 'daterange'"
v-model="model[item.prop]"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD"
v-bind="item.props"
/>
<!-- 日期时间范围 -->
<el-date-picker
v-else-if="comp === 'datetimerange'"
v-model="model[item.prop]"
type="datetimerange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD HH:mm:ss"
v-bind="item.props"
/>
<!-- 时间 -->
<el-time-picker
v-else-if="comp === 'time'"
v-model="model[item.prop]"
:disabled="item.disabled"
:style="controlStyle"
value-format="HH:mm:ss"
v-bind="item.props"
/>
<!-- 级联 -->
<el-cascader
v-else-if="comp === 'cascader'"
v-model="model[item.prop]"
:options="options"
:placeholder="placeholder || '请选择'"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 未知控件回退到 input -->
<el-input
v-else
v-model="model[item.prop]"
:placeholder="placeholder"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
</template>
<script setup>
/**
* 表单控件渲染器(BasicForm 内部使用)
* 根据 item.component 渲染对应的 Element Plus 控件,支持字典自动加载选项。
* 控件直接双向绑定 model[item.prop](引用修改,与 el-form 一致)。
*/
defineOptions({ name: 'FormControl' })
const props = defineProps({
// 表单数据对象(引用,控件原地修改其字段)
model: { type: Object, required: true },
// schema 项配置
item: { type: Object, required: true },
// 字典映射表(来自父级 BasicForm)
dictMap: { type: Object, default: () => ({}) }
})
const comp = computed(() => props.item.component || 'input')
const placeholder = computed(() => props.item.placeholder)
const valueKey = computed(() => props.item.valueKey || 'value')
const labelKey = computed(() => props.item.labelKey || 'label')
// 控件宽度样式
const controlStyle = computed(() => (props.item.width ? { width: props.item.width } : null))
// 选项:静态 options 优先,其次字典
const options = computed(() => {
if (props.item.options) return props.item.options
if (props.item.dict) {
const d = props.dictMap[props.item.dict]
return isRef(d) ? d.value : d || []
}
return []
})
</script>
+234
View File
@@ -0,0 +1,234 @@
<template>
<el-form
ref="formRef"
:model="modelValue"
:rules="mergedRules"
:inline="inline"
:label-width="labelWidth"
:label-position="labelPosition"
:disabled="disabled"
:size="size"
:class="['basic-form', { 'basic-form--grid': !inline }]"
>
<!-- 行内布局直接平铺 -->
<template v-if="inline">
<template v-for="item in visibleSchemas" :key="item.prop">
<el-form-item
:label="item.label"
:prop="item.prop"
:label-width="item.labelWidth"
v-bind="item.formItemProps"
>
<slot :name="`form-${item.prop}`" :model="modelValue" :item="item">
<form-control :model="modelValue" :item="item" :dict-map="dictMap" />
</slot>
</el-form-item>
</template>
<el-form-item v-if="$slots.default">
<slot />
</el-form-item>
</template>
<!-- 栅格布局el-row + el-col -->
<template v-else>
<el-row :gutter="gutter">
<el-col
v-for="item in visibleSchemas"
:key="item.prop"
:span="item.span || 24"
v-bind="item.colProps"
>
<el-form-item
:label="item.label"
:prop="item.prop"
:label-width="item.labelWidth"
v-bind="item.formItemProps"
>
<slot :name="`form-${item.prop}`" :model="modelValue" :item="item">
<form-control :model="modelValue" :item="item" :dict-map="dictMap" />
</slot>
</el-form-item>
</el-col>
<el-col :span="actionSpan" v-if="$slots.default">
<el-form-item :label-width="actionLabelWidth">
<slot />
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
</template>
<script setup>
/**
* 公共表单组件 BasicForm
* 基于 schema 配置驱动,支持常见控件、字典自动加载、校验、插槽扩展。
*
* 数据流:与 Element Plus el-form 一致,传入的对象为引用传递,控件直接修改其字段属性。
* 用法:v-model 或 :model-value 均可(两者等价,组件内部不替换对象,而是原地修改字段)。
*
* 用法示例:
* <basic-form ref="formRef" v-model="form" :schemas="schemas" :rules="rules" label-width="100px" />
*
* schema 项结构:
* {
* label: '岗位名称', // 标签
* prop: 'postName', // 字段名
* component: 'input', // 控件类型:input/textarea/inputNumber/select/radio/checkbox/switch/date/datetime/daterange/datetimerange/time/cascader
* placeholder: '请输入', // 占位文本
* options: [], // 静态选项(select/radio/checkbox
* dict: 'sys_normal_disable', // 字典类型,自动加载选项
* valueKey: 'value', // 选项值字段(默认 value)
* labelKey: 'label', // 选项标签字段(默认 label)
* span: 12, // 栅格占位(grid 布局,默认 24)
* width: '200px', // 控件宽度
* show: true, // 是否显示
* disabled: false,
* rules: [], // 该项校验规则
* defaultValue: undefined, // resetToDefault 时该项的默认值
* props: {}, // 透传给底层控件的属性
* formItemProps: {}, // 透传给 el-form-item 的属性
* colProps: {} // 透传给 el-col 的属性
* }
*/
defineOptions({ name: 'BasicForm' })
const props = defineProps({
// 表单数据对象(引用传递,控件原地修改其字段)
modelValue: {
type: Object,
required: true
},
// 表单项配置数组
schemas: {
type: Array,
default: () => []
},
// 校验规则(可与 schema 内 rules 合并,schema 优先)
rules: {
type: Object,
default: () => ({})
},
// 是否行内布局(搜索场景)
inline: {
type: Boolean,
default: false
},
// 标签宽度
labelWidth: {
type: [String, Number],
default: '80px'
},
// 标签位置
labelPosition: {
type: String,
default: 'right'
},
// 整体禁用
disabled: {
type: Boolean,
default: false
},
// 表单尺寸(large/default/small
size: {
type: String,
default: undefined
},
// 栅格间距(grid 布局)
gutter: {
type: Number,
default: 16
},
// 操作区栅格占位(grid 布局)
actionSpan: {
type: Number,
default: 24
},
// 操作区 label-widthgrid 布局)
actionLabelWidth: {
type: [String, Number],
default: '0'
}
})
const { proxy } = getCurrentInstance()
const formRef = ref()
// 收集所有 schema 中用到的字典类型,统一加载
const dictMap = reactive({})
const dictTypes = computed(() => {
const set = new Set()
props.schemas.forEach((s) => s.dict && set.add(s.dict))
return [...set]
})
watch(
dictTypes,
(types) => {
if (!types.length) return
const dictRefs = proxy.useDict(...types)
types.forEach((t) => {
// useDict 返回的是 toRefs,每项是 ref
const d = dictRefs[t]
dictMap[t] = isRef(d) ? d : ref(d)
})
},
{ immediate: true }
)
// 合并 schema 内 rules 与外部 rulesschema 优先)
const mergedRules = computed(() => {
const result = { ...props.rules }
props.schemas.forEach((s) => {
if (s.rules) result[s.prop] = s.rules
})
return result
})
// 过滤出可见的 schema
const visibleSchemas = computed(() => props.schemas.filter((s) => s.show !== false))
// ====== 暴露 el-form 方法 ======
function validate(callback) {
return formRef.value?.validate(callback)
}
function validateField(p, callback) {
return formRef.value?.validateField(p, callback)
}
function resetFields(p) {
return formRef.value?.resetFields(p)
}
function clearValidate(p) {
return formRef.value?.clearValidate(p)
}
function scrollToField(prop) {
return formRef.value?.scrollToField(prop)
}
function getFormRef() {
return formRef.value
}
// 重置为 schema defaultValue 定义的状态
function resetToDefault() {
props.schemas.forEach((s) => {
props.modelValue[s.prop] = s.defaultValue !== undefined ? s.defaultValue : undefined
})
nextTick(() => clearValidate())
}
defineExpose({
validate,
validateField,
resetFields,
clearValidate,
scrollToField,
getFormRef,
resetToDefault
})
</script>
<style scoped>
.basic-form--grid :deep(.el-form-item) {
margin-bottom: 18px;
}
</style>
+440
View File
@@ -0,0 +1,440 @@
<template>
<div class="basic-table">
<!-- 搜索栏 -->
<basic-form
v-if="searchColumns.length"
ref="searchFormRef"
:model-value="queryParams"
:schemas="searchColumns"
:rules="searchRules"
:label-width="searchLabelWidth"
:size="size"
inline
v-show="showSearch"
>
<template v-for="name in searchSlotNames" :key="name" #[toFormSlot(name)]>
<slot :name="name" />
</template>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<slot name="search-extra" />
</basic-form>
<!-- 工具栏 -->
<el-row v-if="showToolbar" :gutter="10" class="mb8">
<slot name="toolbar" :selection="selectionList" :ids="selectionIds" />
<el-col :span="1.5" v-if="!$slots.toolbar">
<el-button type="primary" plain icon="Plus" @click="$emit('add')" v-if="showAdd">新增</el-button>
</el-col>
<right-toolbar
v-model:showSearch="showSearchInternal"
:columns="toolbarColumns"
:search="searchColumns.length > 0"
@query-table="getList"
/>
</el-row>
<!-- 表格 -->
<el-table
ref="tableRef"
v-loading="loading"
:data="tableData"
:row-key="rowKey"
:border="border"
:stripe="stripe"
:size="size"
:height="height"
:max-height="maxHeight"
:default-sort="defaultSort"
@selection-change="handleSelectionChange"
@row-click="(row, col, e) => $emit('row-click', row, col, e)"
@sort-change="(c) => $emit('sort-change', c)"
>
<!-- 多选列 -->
<el-table-column v-if="selection" type="selection" width="55" align="center" />
<!-- 序号列 -->
<el-table-column v-if="showIndex" type="index" label="序号" width="55" align="center" />
<!-- 动态列 -->
<el-table-column
v-for="col in visibleColumns"
:key="col.key"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
:align="col.align || 'center'"
:fixed="col.fixed"
:sortable="col.sortable"
:show-overflow-tooltip="col.showOverflowTooltip !== false"
>
<template #header="scope">
<slot :name="`header-${col.prop}`" v-bind="scope">{{ col.label }}</slot>
</template>
<template #default="scope">
<slot :name="`col-${col.prop}`" v-bind="scope" :row="scope.row">
<!-- 字典列 -->
<dict-tag
v-if="col.dict"
:options="getDictOptions(col.dict)"
:value="scope.row[col.prop]"
/>
<!-- 时间格式化 -->
<span v-else-if="col.parseTime">{{ parseTime(scope.row[col.prop], col.parseTime === true ? undefined : col.parseTime) }}</span>
<!-- 自定义格式化 -->
<span v-else-if="col.formatter">{{ col.formatter(scope.row, col, scope.row[col.prop], scope.$index) }}</span>
<!-- 默认显示 -->
<span v-else>{{ scope.row[col.prop] }}</span>
</slot>
</template>
</el-table-column>
<!-- 空数据 -->
<template #empty>
<slot name="empty"><el-empty /></slot>
</template>
</el-table>
<!-- 分页 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
:page-sizes="pageSizes"
@pagination="getList"
/>
</div>
</template>
<script setup>
/**
* 公共表格组件 BasicTable
* 集成搜索栏 + 工具栏 + 表格 + 分页,基于 columns/searchColumns 配置驱动,内置复用 BasicForm、RightToolbar、Pagination、DictTag。
*
* 用法示例:
* <basic-table
* ref="tableRef"
* :columns="columns"
* :search-columns="searchColumns"
* :query="listPost"
* @add="handleAdd"
* >
* <template #toolbar="{ selection, ids }">
* <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
* </template>
* <template #col-status="{ row }">
* <dict-tag :options="sys_normal_disable" :value="row.status" />
* </template>
* </basic-table>
*
* column 配置
* {
* label: '岗位名称', // 列标题
* prop: 'postName', // 字段名
* width: 120, // 列宽
* minWidth: 120,
* align: 'center', // 对齐(默认 center
* fixed: 'left'|'right',
* sortable: true,
* showOverflowTooltip: true, // 默认 true
* dict: 'sys_normal_disable', // 用字典标签渲染
* parseTime: true | 'YYYY-MM-DD', // 时间格式化(true 用默认格式)
* formatter: (row,col,val,index)=> ..., // 自定义格式化
* show: true, // 是否显示(参与显隐列)
* showInToolbar: true, // 是否在显隐列工具栏中显示(默认 true)
* visible: true // 初始是否可见(显隐列控制)
* }
*
* searchColumns 配置 BasicForm schemas
*/
defineOptions({ name: 'BasicTable' })
const props = defineProps({
// 列配置数组
columns: {
type: Array,
default: () => []
},
// 搜索表单配置(同 BasicForm schemas
searchColumns: {
type: Array,
default: () => []
},
// 搜索表单校验规则
searchRules: {
type: Object,
default: () => ({})
},
// 搜索表单标签宽度
searchLabelWidth: {
type: [String, Number],
default: 'auto'
},
// 列表加载函数:(params) => Promise<{rows, total}> | {rows, total}
query: {
type: Function,
required: true
},
// 额外固定查询参数(每次请求合并传入,不参与搜索表单重置)
extraParams: {
type: Object,
default: () => ({})
},
// 初始查询参数(搜索字段的默认值)
defaultParams: {
type: Object,
default: () => ({})
},
// 是否显示多选列
selection: {
type: Boolean,
default: true
},
// 是否显示序号列
showIndex: {
type: Boolean,
default: false
},
// 是否显示工具栏
showToolbar: {
type: Boolean,
default: true
},
// 是否显示默认新增按钮(无 toolbar 插槽时生效)
showAdd: {
type: Boolean,
default: false
},
// 是否显示搜索栏(可双向控制)
showSearch: {
type: Boolean,
default: true
},
// 行 key
rowKey: {
type: [String, Function],
default: undefined
},
// 边框
border: {
type: Boolean,
default: false
},
// 斑马纹
stripe: {
type: Boolean,
default: false
},
// 表格/表单尺寸(large/default/small
size: {
type: String,
default: undefined
},
// 表格高度
height: { type: [String, Number], default: undefined },
maxHeight: { type: [String, Number], default: undefined },
// 默认排序(透传 el-table default-sort,如 { prop: 'createTime', order: 'descending' }
defaultSort: {
type: Object,
default: undefined
},
// 每页条数可选项
pageSizes: {
type: Array,
default: () => [10, 20, 30, 50]
},
// 默认每页条数
pageSize: {
type: Number,
default: 10
},
// 是否在挂载后自动加载
autoLoad: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['add', 'update:showSearch', 'row-click', 'sort-change', 'selection-change'])
const { proxy } = getCurrentInstance()
const tableRef = ref()
const searchFormRef = ref()
const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const selectionList = ref([])
const showSearchInternal = ref(props.showSearch)
// 查询参数:搜索字段 + 分页
const queryParams = reactive({
pageNum: 1,
pageSize: props.pageSize,
...props.defaultParams
})
watch(() => props.showSearch, (v) => (showSearchInternal.value = v))
watch(showSearchInternal, (v) => emit('update:showSearch', v))
// ====== 列显隐状态 ======
// 内部维护列状态(带 key/visible),供 RightToolbar 控制显隐
const tableColumns = ref([])
function initColumns() {
tableColumns.value = props.columns.map((col, index) => ({
...col,
key: col.key || col.prop || index,
visible: col.visible !== false && col.show !== false
}))
}
initColumns()
watch(
() => props.columns,
() => initColumns(),
{ deep: false }
)
// 实际渲染的列(visible !== false
const visibleColumns = computed(() => tableColumns.value.filter((c) => c.visible !== false))
// 参与显隐工具栏的列(有 label 且未禁用工具栏显示)
const toolbarColumns = computed(() =>
tableColumns.value.filter((c) => c.label && c.showInToolbar !== false)
)
// ====== 字典加载(用于表格列 dict 渲染) ======
const dictMap = reactive({})
const dictTypes = computed(() => {
const set = new Set()
props.columns.forEach((c) => c.dict && set.add(c.dict))
props.searchColumns.forEach((c) => c.dict && set.add(c.dict))
return [...set]
})
watch(
dictTypes,
(types) => {
if (!types.length) return
const dictRefs = proxy.useDict(...types)
types.forEach((t) => {
const d = dictRefs[t]
dictMap[t] = isRef(d) ? d : ref(d)
})
},
{ immediate: true }
)
function getDictOptions(type) {
const d = dictMap[type]
return isRef(d) ? d.value : d || []
}
// ====== 搜索栏插槽透传:search-xxx -> form-xxx ======
const slots = useSlots()
const searchSlotNames = computed(() =>
Object.keys(slots).filter((n) => n.startsWith('search-') && n !== 'search-extra')
)
function toFormSlot(name) {
return 'form-' + name.slice('search-'.length)
}
// ====== 数据加载 ======
async function getList() {
loading.value = true
try {
const params = { ...queryParams, ...props.extraParams }
const res = await props.query(params)
tableData.value = res?.rows || []
total.value = res?.total || 0
} catch (e) {
console.error('BasicTable 加载失败', e)
} finally {
loading.value = false
}
}
// 搜索
function handleQuery() {
queryParams.pageNum = 1
getList()
}
// 重置搜索
function resetQuery() {
searchFormRef.value?.resetFields()
Object.keys(props.defaultParams || {}).forEach((k) => {
queryParams[k] = props.defaultParams[k]
})
queryParams.pageNum = 1
getList()
}
// 选中变化
function handleSelectionChange(val) {
selectionList.value = val
emit('selection-change', val)
}
const selectionIds = computed(() =>
selectionList.value.map((r) => (props.rowKey ? r[props.rowKey] : r.id)).filter((v) => v !== undefined)
)
// ====== 暴露方法 ======
function refresh() {
getList()
}
function reload() {
queryParams.pageNum = 1
getList()
}
function getSelection() {
return selectionList.value
}
function getSelectionIds() {
return selectionIds.value
}
function clearSelection() {
tableRef.value?.clearSelection()
}
function toggleRowSelection(row, selected) {
tableRef.value?.toggleRowSelection(row, selected)
}
function getTableRef() {
return tableRef.value
}
function getSearchFormRef() {
return searchFormRef.value
}
function getQueryParams() {
return { ...queryParams, ...props.extraParams }
}
function setQueryParams(p) {
Object.assign(queryParams, p)
}
defineExpose({
refresh,
reload,
getList,
handleQuery,
resetQuery,
getSelection,
getSelectionIds,
clearSelection,
toggleRowSelection,
getTableRef,
getSearchFormRef,
getQueryParams,
setQueryParams
})
if (props.autoLoad) {
onMounted(getList)
}
</script>
<style scoped>
.basic-table {
width: 100%;
}
</style>
+6
View File
@@ -43,6 +43,10 @@ import ImageUpload from "@/components/ImageUpload"
import ImagePreview from "@/components/ImagePreview"
// 字典标签组件
import DictTag from '@/components/DictTag'
// 公共表单组件
import BasicForm from '@/components/BasicForm'
// 公共表格组件
import BasicTable from '@/components/BasicTable'
const app = createApp(App)
@@ -65,6 +69,8 @@ app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar)
app.component('Editor', Editor)
app.component('BasicForm', BasicForm)
app.component('BasicTable', BasicTable)
app.use(router)
app.use(store)
+1 -1
View File
@@ -4,7 +4,7 @@
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>若依后台管理框架</h2>
<p>
一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适自己的于是利用空闲休息时间开始自己写一套后台系统如此有了若依管理系统她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA等等当然您也可以对她进行深度定制以做出更强系统所有前端后台代码封装过后十分精简易上手出错概率低同时支持移动客户端访问系统会陆续更新一些实用功能
一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适自己的于是利用空闲休息时间开始自己写一套后台系统如此有了BMS她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA等等当然您也可以对她进行深度定制以做出更强系统所有前端后台代码封装过后十分精简易上手出错概率低同时支持移动客户端访问系统会陆续更新一些实用功能
</p>
<p>
<b>当前版本:</b> <span>v{{ version }}</span>
+97 -171
View File
@@ -1,42 +1,13 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
placeholder="请输入任务名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="任务组名" prop="jobGroup">
<el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable style="width: 200px">
<el-option
v-for="dict in sys_job_group"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="任务状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable style="width: 200px">
<el-option
v-for="dict in sys_job_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="jobId"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -51,8 +22,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['monitor:job:edit']"
>修改</el-button>
</el-col>
@@ -61,8 +32,8 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['monitor:job:remove']"
>删除</el-button>
</el-col>
@@ -80,63 +51,40 @@
type="info"
plain
icon="Operation"
@click="handleJobLog"
@click="handleJobLog()"
v-hasPermi="['monitor:job:query']"
>日志</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="任务编号" width="100" align="center" prop="jobId" />
<el-table-column label="任务名称" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<a class="link-type" style="cursor:pointer" @click="handleView(scope.row)">{{ scope.row.jobName }}</a>
<template #col-jobName="{ row }">
<a class="link-type" style="cursor:pointer" @click="handleView(row)">{{ row.jobName }}</a>
</template>
</el-table-column>
<el-table-column label="任务组名" align="center" prop="jobGroup">
<template #default="scope">
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" />
</template>
</el-table-column>
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
<el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center">
<template #default="scope">
<template #col-status="{ row }">
<el-switch
v-model="scope.row.status"
v-model="row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
@change="handleStatusChange(row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width">
<template #default="scope">
<template #col-action="{ row }">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['monitor:job:edit']"></el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['monitor:job:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['monitor:job:remove']"></el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.jobId)" v-hasPermi="['monitor:job:remove']"></el-button>
</el-tooltip>
<el-tooltip content="执行一次" placement="top">
<el-button link type="primary" icon="CaretRight" @click="handleRun(scope.row)" v-hasPermi="['monitor:job:changeStatus']"></el-button>
<el-button link type="primary" icon="CaretRight" @click="handleRun(row)" v-hasPermi="['monitor:job:changeStatus']"></el-button>
</el-tooltip>
<el-tooltip content="调度日志" placement="top">
<el-button link type="primary" icon="Operation" @click="handleJobLog(scope.row)" v-hasPermi="['monitor:job:query']"></el-button>
<el-button link type="primary" icon="Operation" @click="handleJobLog(row)" v-hasPermi="['monitor:job:query']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</basic-table>
<!-- 添加或修改定时任务对话框 -->
<el-dialog :title="title" v-model="open" width="820px" append-to-body>
@@ -247,28 +195,38 @@ const router = useRouter()
const { proxy } = getCurrentInstance()
const { sys_job_group, sys_job_status } = useDict("sys_job_group", "sys_job_status")
const jobList = ref([])
const tableRef = ref()
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
const openView = ref(false)
const openCron = ref(false)
const expression = ref("")
// 搜索项配置
const searchColumns = [
{ label: "任务名称", prop: "jobName", component: "input", placeholder: "请输入任务名称", width: "200px" },
{ label: "任务组名", prop: "jobGroup", component: "select", dict: "sys_job_group", placeholder: "请选择任务组名", width: "200px" },
{ label: "任务状态", prop: "status", component: "select", dict: "sys_job_status", placeholder: "请选择任务状态", width: "200px" }
]
// 表格列配置
const columns = [
{ label: "任务编号", prop: "jobId", align: "center", width: 100 },
{ label: "任务名称", prop: "jobName", align: "center" },
{ label: "任务组名", prop: "jobGroup", align: "center", dict: "sys_job_group" },
{ label: "调用目标字符串", prop: "invokeTarget", align: "center" },
{ label: "cron执行表达式", prop: "cronExpression", align: "center" },
{ label: "状态", prop: "status", align: "center" },
{ label: "操作", prop: "action", align: "center", width: 200, showInToolbar: false }
]
// 查询函数
function queryList(params) {
return listJob(params)
}
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
jobName: undefined,
jobGroup: undefined,
status: undefined
},
rules: {
jobName: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
invokeTarget: [{ required: true, message: "调用目标字符串不能为空", trigger: "blur" }],
@@ -276,17 +234,7 @@ const data = reactive({
}
})
const { queryParams, form, rules } = toRefs(data)
/** 查询定时任务列表 */
function getList() {
loading.value = true
listJob(queryParams.value).then(response => {
jobList.value = response.rows
total.value = response.total
loading.value = false
})
}
const { form, rules } = toRefs(data)
/** 取消按钮 */
function cancel() {
@@ -309,23 +257,53 @@ function reset() {
proxy.resetForm("jobRef")
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加任务"
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const jobId = row.jobId
getJob(jobId).then(response => {
form.value = response.data
open.value = true
title.value = "修改任务"
})
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.jobId)
single.value = selection.length != 1
multiple.value = !selection.length
/** 提交按钮 */
function submitForm() {
proxy.$refs["jobRef"].validate(valid => {
if (valid) {
if (form.value.jobId != undefined) {
updateJob(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
tableRef.value.refresh()
})
} else {
addJob(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
tableRef.value.refresh()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(jobIds) {
proxy.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function () {
return delJob(jobIds)
}).then(() => {
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
// 任务状态修改
@@ -370,66 +348,14 @@ function crontabFill(value) {
/** 任务日志列表查询 */
function handleJobLog(row) {
const jobId = row.jobId || 0
const jobId = row?.jobId || 0
router.push('/monitor/job-log/index/' + jobId)
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加任务"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const jobId = row.jobId || ids.value
getJob(jobId).then(response => {
form.value = response.data
open.value = true
title.value = "修改任务"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["jobRef"].validate(valid => {
if (valid) {
if (form.value.jobId != undefined) {
updateJob(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addJob(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const jobIds = row.jobId || ids.value
proxy.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function () {
return delJob(jobIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/job/export", {
...queryParams.value,
...tableRef.value.getQueryParams()
}, `job_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+58 -151
View File
@@ -1,69 +1,21 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
placeholder="请输入任务名称"
clearable
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="任务组名" prop="jobGroup">
<el-select
v-model="queryParams.jobGroup"
placeholder="请选择任务组名"
clearable
style="width: 240px"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="jobLogId"
:auto-load="false"
>
<el-option
v-for="dict in sys_job_group"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="执行状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择执行状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_common_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="执行时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['monitor:job:remove']"
>删除</el-button>
</el-col>
@@ -93,44 +45,12 @@
@click="handleClose"
>关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
<el-table-column label="任务组名" align="center" prop="jobGroup" :show-overflow-tooltip="true">
<template #default="scope">
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" />
<template #col-action="{ row }">
<el-button link type="primary" icon="View" @click="handleView(row)" v-hasPermi="['monitor:job:query']">详细</el-button>
</template>
</el-table-column>
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
<el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
<el-table-column label="执行状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="执行时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:job:query']">详细</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</basic-table>
<!-- 调度日志详细 -->
<job-detail v-model:visible="open" :row="form" type="log" />
@@ -145,37 +65,40 @@ import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog"
const { proxy } = getCurrentInstance()
const { sys_common_status, sys_job_group } = useDict("sys_common_status", "sys_job_group")
const jobLogList = ref([])
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const multiple = ref(true)
const total = ref(0)
const dateRange = ref([])
const route = useRoute()
const tableRef = ref()
const open = ref(false)
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
status: undefined
}
form: {}
})
const { form } = toRefs(data)
const { queryParams, form, rules } = toRefs(data)
// 搜索项配置
const searchColumns = [
{ label: "任务名称", prop: "jobName", component: "input", placeholder: "请输入任务名称", width: "240px" },
{ label: "任务组名", prop: "jobGroup", component: "select", dict: "sys_job_group", placeholder: "请选择任务组名", width: "240px" },
{ label: "执行状态", prop: "status", component: "select", dict: "sys_common_status", placeholder: "请选择执行状态", width: "240px" },
{ label: "执行时间", prop: "dateRange", component: "daterange", width: "308px" }
]
/** 查询调度日志列表 */
function getList() {
loading.value = true
listJobLog(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
jobLogList.value = response.rows
total.value = response.total
loading.value = false
})
// 表格列配置
const columns = [
{ label: "日志编号", prop: "jobLogId", align: "center", width: 80 },
{ label: "任务名称", prop: "jobName", align: "center" },
{ label: "任务组名", prop: "jobGroup", align: "center", dict: "sys_job_group" },
{ label: "调用目标字符串", prop: "invokeTarget", align: "center" },
{ label: "日志信息", prop: "jobMessage", align: "center" },
{ label: "执行状态", prop: "status", align: "center", dict: "sys_common_status" },
{ label: "执行时间", prop: "createTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", showInToolbar: false }
]
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listJobLog(p)
}
// 返回按钮
@@ -184,25 +107,6 @@ function handleClose() {
proxy.$tab.closeOpenPage(obj)
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.jobLogId)
multiple.value = !selection.length
}
/** 详细按钮操作 */
function handleView(row) {
open.value = true
@@ -210,11 +114,11 @@ function handleView(row) {
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除调度日志编号为"' + ids.value + '"的数据项?').then(function () {
return delJobLog(ids.value)
function handleDelete(jobIds) {
proxy.$modal.confirm('是否确认删除调度日志编号为"' + jobIds + '"的数据项?').then(function () {
return delJobLog(jobIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -224,7 +128,7 @@ function handleClean() {
proxy.$modal.confirm("是否确认清空所有调度日志数据项?").then(function () {
return cleanJobLog()
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("清空成功")
}).catch(() => {})
}
@@ -232,20 +136,23 @@ function handleClean() {
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/jobLog/export", {
...queryParams.value,
...tableRef.value.getQueryParams()
}, `job_log_${new Date().getTime()}.xlsx`)
}
(() => {
const jobId = route.params && route.params.jobId
// 初始化:从路由参数接收 jobId,异步获取任务名称/组名后加载列表
onMounted(() => {
const jobId = route.params?.jobId || route.query?.jobId
if (jobId !== undefined && jobId != 0) {
getJob(jobId).then(response => {
queryParams.value.jobName = response.data.jobName
queryParams.value.jobGroup = response.data.jobGroup
getList()
tableRef.value.setQueryParams({
jobName: response.data.jobName,
jobGroup: response.data.jobGroup
})
tableRef.value.reload()
})
} else {
getList()
tableRef.value.reload()
}
})()
})
</script>
+55 -144
View File
@@ -1,64 +1,23 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="登录状态"
clearable
style="width: 240px"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="infoId"
:default-sort="defaultSort"
:default-params="defaultParams"
@sort-change="handleSortChange"
>
<el-option
v-for="dict in sys_common_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="登录时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['monitor:logininfor:remove']"
>删除</el-button>
</el-col>
@@ -76,8 +35,8 @@
type="primary"
plain
icon="Unlock"
:disabled="single"
@click="handleUnlock"
:disabled="selection.length !== 1"
@click="handleUnlock(selection)"
v-hasPermi="['monitor:logininfor:unlock']"
>解锁</el-button>
</el-col>
@@ -90,37 +49,8 @@
v-hasPermi="['monitor:logininfor:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table ref="logininforRef" v-loading="loading" :data="logininforList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="访问编号" align="center" prop="infoId" />
<el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="地址" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
<el-table-column label="登录状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
<el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</basic-table>
</div>
</template>
@@ -130,74 +60,57 @@ import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/mo
const { proxy } = getCurrentInstance()
const { sys_common_status } = useDict("sys_common_status")
const logininforList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const selectName = ref("")
const total = ref(0)
const dateRange = ref([])
const defaultSort = ref({ prop: "loginTime", order: "descending" })
const tableRef = ref()
// 查询参数
const queryParams = ref({
pageNum: 1,
pageSize: 10,
ipaddr: undefined,
userName: undefined,
status: undefined,
orderByColumn: undefined,
isAsc: undefined
})
// 默认排序
const defaultSort = { prop: "loginTime", order: "descending" }
/** 查询登录日志列表 */
function getList() {
loading.value = true
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
logininforList.value = response.rows
total.value = response.total
loading.value = false
})
// 默认查询参数(含排序初始值,重置时由 BasicTable 自动恢复)
const defaultParams = {
orderByColumn: "loginTime",
isAsc: "descending"
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
// 搜索项配置
const searchColumns = [
{ label: "登录地址", prop: "ipaddr", component: "input", placeholder: "请输入登录地址", width: "240px" },
{ label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "240px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_common_status", placeholder: "登录状态", width: "240px" },
{ label: "登录时间", prop: "dateRange", component: "daterange", width: "308px" }
]
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.pageNum = 1
proxy.$refs["logininforRef"].sort(defaultSort.value.prop, defaultSort.value.order)
}
// 表格列配置
const columns = [
{ label: "访问编号", prop: "infoId", align: "center" },
{ label: "用户名称", prop: "userName", align: "center", sortable: "custom" },
{ label: "地址", prop: "ipaddr", align: "center" },
{ label: "登录地点", prop: "loginLocation", align: "center" },
{ label: "操作系统", prop: "os", align: "center" },
{ label: "浏览器", prop: "browser", align: "center" },
{ label: "登录状态", prop: "status", align: "center", dict: "sys_common_status" },
{ label: "描述", prop: "msg", align: "center" },
{ label: "访问时间", prop: "loginTime", align: "center", width: 180, sortable: "custom", parseTime: true }
]
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.infoId)
multiple.value = !selection.length
single.value = selection.length != 1
selectName.value = selection.map(item => item.userName)
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return list(p)
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop
queryParams.value.isAsc = column.order
getList()
function handleSortChange(column) {
tableRef.value.setQueryParams({ orderByColumn: column.prop, isAsc: column.order })
tableRef.value.reload()
}
/** 删除按钮操作 */
function handleDelete(row) {
const infoIds = row.infoId || ids.value
function handleDelete(infoIds) {
proxy.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function () {
return delLogininfor(infoIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -207,14 +120,14 @@ function handleClean() {
proxy.$modal.confirm("是否确认清空所有登录日志数据项?").then(function () {
return cleanLogininfor()
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("清空成功")
}).catch(() => {})
}
/** 解锁按钮操作 */
function handleUnlock() {
const username = selectName.value
function handleUnlock(selection) {
const username = selection.map(item => item.userName)
proxy.$modal.confirm('是否确认解锁用户"' + username + '"数据项?').then(function () {
return unlockLogininfor(username)
}).then(() => {
@@ -225,9 +138,7 @@ function handleUnlock() {
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/logininfor/export", {
...queryParams.value,
...tableRef.value.getQueryParams()
}, `logininfor_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+38 -83
View File
@@ -1,59 +1,18 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
:data="onlineList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
style="width: 100%;"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
:selection="false"
:show-toolbar="false"
show-index
>
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
<template #col-action="{ row }">
<el-button link type="primary" icon="Delete" @click="handleForceLogout(row)" v-hasPermi="['monitor:online:forceLogout']">强退</el-button>
</template>
</el-table-column>
<el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
<el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
<el-table-column label="登录时间" align="center" prop="loginTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']">强退</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
</basic-table>
</div>
</template>
@@ -61,38 +20,36 @@
import { forceLogout, list as initData } from "@/api/monitor/online"
const { proxy } = getCurrentInstance()
const tableRef = ref()
const onlineList = ref([])
const loading = ref(true)
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)
// 搜索项配置
const searchColumns = [
{ label: "登录地址", prop: "ipaddr", component: "input", placeholder: "请输入登录地址", width: "200px" },
{ label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "200px" }
]
const queryParams = ref({
ipaddr: undefined,
userName: undefined
})
// 表格列配置
const columns = [
{ label: "会话编号", prop: "tokenId", align: "center" },
{ label: "登录名称", prop: "userName", align: "center" },
{ label: "所属部门", prop: "deptName", align: "center" },
{ label: "主机", prop: "ipaddr", align: "center" },
{ label: "登录地点", prop: "loginLocation", align: "center" },
{ label: "操作系统", prop: "os", align: "center" },
{ label: "浏览器", prop: "browser", align: "center" },
{ label: "登录时间", prop: "loginTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", showInToolbar: false }
]
/** 查询登录日志列表 */
function getList() {
loading.value = true
initData(queryParams.value).then(response => {
onlineList.value = response.rows
total.value = response.total
loading.value = false
})
// 查询函数(在线用户接口返回全量数据,前端分页切片)
function queryList(params) {
return initData({ ipaddr: params.ipaddr, userName: params.userName }).then(res => {
const start = (params.pageNum - 1) * params.pageSize
return {
rows: res.rows.slice(start, start + params.pageSize),
total: res.total
}
/** 搜索按钮操作 */
function handleQuery() {
pageNum.value = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
})
}
/** 强退按钮操作 */
@@ -100,10 +57,8 @@ function handleForceLogout(row) {
proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
return forceLogout(row.tokenId)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
getList()
</script>
+56 -177
View File
@@ -1,88 +1,23 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="操作地址" prop="operIp">
<el-input
v-model="queryParams.operIp"
placeholder="请输入操作地址"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="系统模块" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入系统模块"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="操作人员" prop="operName">
<el-input
v-model="queryParams.operName"
placeholder="请输入操作人员"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="类型" prop="businessType">
<el-select
v-model="queryParams.businessType"
placeholder="操作类型"
clearable
style="width: 240px"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="operId"
:default-sort="defaultSort"
:default-params="defaultParams"
@sort-change="handleSortChange"
>
<el-option
v-for="dict in sys_oper_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="操作状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_common_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="操作时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['monitor:operlog:remove']"
>删除</el-button>
</el-col>
@@ -104,49 +39,12 @@
v-hasPermi="['monitor:operlog:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table ref="operlogRef" v-loading="loading" :data="operlogList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="日志编号" align="center" prop="operId" />
<el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" />
<el-table-column label="操作类型" align="center" prop="businessType">
<template #default="scope">
<dict-tag :options="sys_oper_type" :value="scope.row.businessType" />
<template #col-action="{ row }">
<el-button link type="primary" icon="View" @click="handleDetail(row)" v-hasPermi="['monitor:operlog:query']">详细</el-button>
</template>
</el-table-column>
<el-table-column label="操作人员" align="center" width="110" prop="operName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
<template #default="scope">
<span>{{ parseTime(scope.row.operTime) }}</span>
</template>
</el-table-column>
<el-table-column label="消耗时间" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']">
<template #default="scope">
<span>{{ scope.row.costTime }}毫秒</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleDetail(scope.row, scope.index)" v-hasPermi="['monitor:operlog:query']">详细</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</basic-table>
<operlog-detail v-model:visible="detailVisible" :row="detailRow" />
</div>
@@ -159,69 +57,53 @@ import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog"
const { proxy } = getCurrentInstance()
const { sys_oper_type, sys_common_status } = useDict("sys_oper_type", "sys_common_status")
const operlogList = ref([])
const tableRef = ref()
const detailVisible = ref(false)
const loading = ref(true)
const detailRow = ref({})
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
const dateRange = ref([])
const defaultSort = ref({ prop: "operTime", order: "descending" })
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
operIp: undefined,
title: undefined,
operName: undefined,
businessType: undefined,
status: undefined
}
})
// 默认排序
const defaultSort = { prop: "operTime", order: "descending" }
const { queryParams, form } = toRefs(data)
/** 查询登录日志 */
function getList() {
loading.value = true
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
operlogList.value = response.rows
total.value = response.total
loading.value = false
})
// 默认查询参数(含排序初始值,重置时由 BasicTable 自动恢复)
const defaultParams = {
orderByColumn: "operTime",
isAsc: "descending"
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
// 搜索项配置
const searchColumns = [
{ label: "操作地址", prop: "operIp", component: "input", placeholder: "请输入操作地址", width: "240px" },
{ label: "系统模块", prop: "title", component: "input", placeholder: "请输入系统模块", width: "240px" },
{ label: "操作人员", prop: "operName", component: "input", placeholder: "请输入操作人员", width: "240px" },
{ label: "类型", prop: "businessType", component: "select", dict: "sys_oper_type", placeholder: "操作类型", width: "240px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_common_status", placeholder: "操作状态", width: "240px" },
{ label: "操作时间", prop: "dateRange", component: "daterange", width: "308px" }
]
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.pageNum = 1
proxy.$refs["operlogRef"].sort(defaultSort.value.prop, defaultSort.value.order)
}
// 表格列配置
const columns = [
{ label: "日志编号", prop: "operId", align: "center" },
{ label: "系统模块", prop: "title", align: "center" },
{ label: "操作类型", prop: "businessType", align: "center", dict: "sys_oper_type" },
{ label: "操作人员", prop: "operName", align: "center", width: 110, sortable: "custom" },
{ label: "操作地址", prop: "operIp", align: "center", width: 130 },
{ label: "操作状态", prop: "status", align: "center", dict: "sys_common_status" },
{ label: "操作日期", prop: "operTime", align: "center", width: 180, sortable: "custom", parseTime: true },
{ label: "消耗时间", prop: "costTime", align: "center", width: 110, sortable: "custom", formatter: (row, col, val) => val + '毫秒' },
{ label: "操作", prop: "action", align: "center", showInToolbar: false }
]
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.operId)
multiple.value = !selection.length
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return list(p)
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop
queryParams.value.isAsc = column.order
getList()
function handleSortChange(column) {
tableRef.value.setQueryParams({ orderByColumn: column.prop, isAsc: column.order })
tableRef.value.reload()
}
/** 详细按钮操作 */
@@ -231,12 +113,11 @@ function handleDetail(row) {
}
/** 删除按钮操作 */
function handleDelete(row) {
const operIds = row.operId || ids.value
function handleDelete(operIds) {
proxy.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function () {
return delOperlog(operIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -246,7 +127,7 @@ function handleClean() {
proxy.$modal.confirm("是否确认清空所有操作日志数据项?").then(function () {
return cleanOperlog()
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("清空成功")
}).catch(() => {})
}
@@ -254,9 +135,7 @@ function handleClean() {
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/operlog/export", {
...queryParams.value,
...tableRef.value.getQueryParams()
}, `config_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+54 -140
View File
@@ -1,51 +1,13 @@
<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">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="configId"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -60,8 +22,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:config:edit']"
>修改</el-button>
</el-col>
@@ -70,8 +32,8 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:config:remove']"
>删除</el-button>
</el-col>
@@ -93,41 +55,13 @@
v-hasPermi="['system:config:remove']"
>刷新缓存</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="参数主键" align="center" prop="configId" />
<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 #col-action="{ row }">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:config:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.configId)" v-hasPermi="['system:config:remove']">删除</el-button>
</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"
/>
</basic-table>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
@@ -170,26 +104,39 @@ import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache
const { proxy } = getCurrentInstance()
const { sys_yes_no } = useDict("sys_yes_no")
const configList = ref([])
const tableRef = 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 searchColumns = [
{ label: "参数名称", prop: "configName", component: "input", placeholder: "请输入参数名称", width: "240px" },
{ label: "参数键名", prop: "configKey", component: "input", placeholder: "请输入参数键名", width: "240px" },
{ label: "系统内置", prop: "configType", component: "select", dict: "sys_yes_no", placeholder: "系统内置", width: "240px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "320px" }
]
// 表格列配置
const columns = [
{ label: "参数主键", prop: "configId", align: "center" },
{ label: "参数名称", prop: "configName", align: "center" },
{ label: "参数键名", prop: "configKey", align: "center" },
{ label: "参数键值", prop: "configValue", align: "center" },
{ label: "系统内置", prop: "configType", align: "center", dict: "sys_yes_no" },
{ label: "备注", prop: "remark", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", width: 150, showInToolbar: false }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listConfig(p)
}
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" }],
@@ -197,17 +144,7 @@ const data = reactive({
}
})
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
})
}
const { form, rules } = toRefs(data)
/** 取消按钮 */
function cancel() {
@@ -228,26 +165,6 @@ function reset() {
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()
@@ -258,7 +175,7 @@ function handleAdd() {
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const configId = row.configId || ids.value
const configId = row.configId
getConfig(configId).then(response => {
form.value = response.data
open.value = true
@@ -271,16 +188,16 @@ function submitForm() {
proxy.$refs["configRef"].validate(valid => {
if (valid) {
if (form.value.configId != undefined) {
updateConfig(form.value).then(response => {
updateConfig(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
addConfig(form.value).then(response => {
addConfig(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -288,12 +205,11 @@ function submitForm() {
}
/** 删除按钮操作 */
function handleDelete(row) {
const configIds = row.configId || ids.value
function handleDelete(configIds) {
proxy.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function () {
return delConfig(configIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -301,7 +217,7 @@ function handleDelete(row) {
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/config/export", {
...queryParams.value
...tableRef.value.getQueryParams()
}, `config_${new Date().getTime()}.xlsx`)
}
@@ -311,6 +227,4 @@ function handleRefreshCache() {
proxy.$modal.msgSuccess("刷新缓存成功")
})
}
getList()
</script>
+68 -154
View File
@@ -1,42 +1,15 @@
<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">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
:extra-params="extraParams"
:auto-load="false"
row-key="dictCode"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -51,8 +24,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
</el-col>
@@ -61,8 +34,8 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:dict:remove']"
>删除</el-button>
</el-col>
@@ -83,46 +56,18 @@
@click="handleClose"
>关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编码" align="center" prop="dictCode" />
<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 #col-dictLabel="{ row }">
<span v-if="(row.listClass == '' || row.listClass == 'default') && (row.cssClass == '' || row.cssClass == null)">{{ row.dictLabel }}</span>
<el-tag v-else :type="row.listClass == 'primary' ? '' : row.listClass" :class="row.cssClass">{{ 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"
/>
<template #col-action="{ row }">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:dict:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.dictCode)" v-hasPermi="['system:dict:remove']">删除</el-button>
</template>
</basic-table>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
@@ -177,24 +122,18 @@
<script setup name="Data">
import useDictStore from '@/store/modules/dict'
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type"
import { getType } from "@/api/system/dict/type"
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data"
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const dataList = ref([])
const tableRef = 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 extraParams = reactive({ dictType: "" })
// 数据标签回显样式
const listClassOptions = ref([
{ value: "default", label: "默认" },
@@ -205,15 +144,31 @@ const listClassOptions = ref([
{ value: "danger", label: "危险" }
])
// 搜索项配置
const searchColumns = [
{ label: "字典标签", prop: "dictLabel", component: "input", placeholder: "请输入字典标签", width: "200px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "数据状态", width: "200px" }
]
// 表格列配置
const columns = [
{ label: "字典编码", prop: "dictCode", align: "center" },
{ label: "字典标签", prop: "dictLabel", align: "center" },
{ label: "字典键值", prop: "dictValue", align: "center" },
{ label: "字典排序", prop: "dictSort", align: "center" },
{ label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
{ label: "备注", prop: "remark", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", width: 160, showInToolbar: false }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
return listData(params)
}
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" }],
@@ -221,33 +176,16 @@ const data = reactive({
}
})
const { queryParams, form, rules } = toRefs(data)
const { form, rules } = toRefs(data)
/** 查询字典类型详细 */
function getTypes(dictId) {
/** 查询字典类型详细(从路由参数获取上级 dictType) */
onMounted(() => {
const dictId = route.params && route.params.dictId
getType(dictId).then(response => {
queryParams.value.dictType = response.data.dictType
defaultDictType.value = response.data.dictType
getList()
extraParams.dictType = response.data.dictType
tableRef.value.reload()
})
}
/** 查询字典类型列表 */
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() {
@@ -270,44 +208,24 @@ function reset() {
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
form.value.dictType = extraParams.dictType
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const dictCode = row.dictCode || ids.value
const dictCode = row.dictCode
getData(dictCode).then(response => {
form.value = response.data
open.value = true
@@ -320,18 +238,18 @@ function submitForm() {
proxy.$refs["dataRef"].validate(valid => {
if (valid) {
if (form.value.dictCode != undefined) {
updateData(form.value).then(response => {
useDictStore().removeDict(queryParams.value.dictType)
updateData(form.value).then(() => {
useDictStore().removeDict(extraParams.dictType)
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
addData(form.value).then(response => {
useDictStore().removeDict(queryParams.value.dictType)
addData(form.value).then(() => {
useDictStore().removeDict(extraParams.dictType)
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -339,24 +257,20 @@ function submitForm() {
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictCodes = row.dictCode || ids.value
function handleDelete(dictCodes) {
proxy.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
return delData(dictCodes)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
useDictStore().removeDict(queryParams.value.dictType)
useDictStore().removeDict(extraParams.dictType)
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/data/export", {
...queryParams.value
...tableRef.value.getQueryParams()
}, `dict_data_${new Date().getTime()}.xlsx`)
}
getTypes(route.params && route.params.dictId)
getTypeList()
</script>
+58 -149
View File
@@ -1,56 +1,13 @@
<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"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="dictId"
>
<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">
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -65,8 +22,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
</el-col>
@@ -75,8 +32,8 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:dict:remove']"
>删除</el-button>
</el-col>
@@ -98,45 +55,18 @@
v-hasPermi="['system:dict:remove']"
>刷新缓存</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编号" align="center" prop="dictId" />
<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">
<a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.dictType }}</a>
<template #col-dictType="{ row }">
<a class="link-type" style="cursor:pointer" @click="handleViewData(row)">{{ row.dictType }}</a>
</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="280" 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="Operation" @click="handleDataList(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"
/>
<template #col-action="{ row }">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:dict:edit']">修改</el-button>
<el-button link type="primary" icon="Operation" @click="handleDataList(row)" v-hasPermi="['system:dict:edit']">列表</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.dictId)" v-hasPermi="['system:dict:remove']">删除</el-button>
</template>
</basic-table>
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
@@ -188,45 +118,47 @@ import { listType, getType, delType, addType, updateType, refreshCache } from "@
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const typeList = ref([])
const tableRef = 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 drawerVisible = ref(false)
const drawerRow = ref({})
// 搜索项配置
const searchColumns = [
{ label: "字典名称", prop: "dictName", component: "input", placeholder: "请输入字典名称", width: "240px" },
{ label: "字典类型", prop: "dictType", component: "input", placeholder: "请输入字典类型", width: "240px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "字典状态", width: "240px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "320px" }
]
// 表格列配置
const columns = [
{ label: "字典编号", prop: "dictId", align: "center" },
{ label: "字典名称", prop: "dictName", align: "center" },
{ label: "字典类型", prop: "dictType", align: "center" },
{ label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
{ label: "备注", prop: "remark", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", width: 280, showInToolbar: false }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listType(p)
}
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
})
}
})
const { form, rules } = toRefs(data)
/** 取消按钮 */
function cancel() {
@@ -246,19 +178,6 @@ function reset() {
proxy.resetForm("dictRef")
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
}
/** 新增按钮操作 */
function handleAdd() {
reset()
@@ -266,13 +185,6 @@ function handleAdd() {
title.value = "添加字典类型"
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.dictId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 字典数据抽屉 */
function handleViewData(row) {
drawerRow.value = row
@@ -287,7 +199,7 @@ function handleDataList(row) {
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const dictId = row.dictId || ids.value
const dictId = row.dictId
getType(dictId).then(response => {
form.value = response.data
open.value = true
@@ -300,16 +212,16 @@ function submitForm() {
proxy.$refs["dictRef"].validate(valid => {
if (valid) {
if (form.value.dictId != undefined) {
updateType(form.value).then(response => {
updateType(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
addType(form.value).then(response => {
addType(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -317,12 +229,11 @@ function submitForm() {
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.dictId || ids.value
function handleDelete(dictIds) {
proxy.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
return delType(dictIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -330,7 +241,7 @@ function handleDelete(row) {
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/type/export", {
...queryParams.value
...tableRef.value.getQueryParams()
}, `dict_${new Date().getTime()}.xlsx`)
}
@@ -341,6 +252,4 @@ function handleRefreshCache() {
useDictStore().cleanDict()
})
}
getList()
</script>
+68 -75
View File
@@ -1,47 +1,24 @@
<template>
<el-dialog v-model="visible" :title="`「${noticeTitle}」已读用户`" width="760px" top="6vh" append-to-body @close="handleClose">
<el-form ref="queryRef" :model="queryParams" size="small" :inline="true" style="margin-bottom: 4px;">
<el-form-item prop="searchValue">
<el-input
v-model="queryParams.searchValue"
placeholder="登录名称 / 用户名称"
clearable
:prefix-icon="Search"
style="width: 220px;"
@keyup.enter="handleQuery"
@clear="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" size="small" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="small" @click="resetQuery">重置</el-button>
</el-form-item>
<el-form-item style="float: right; margin-right: 0;">
<span class="read-stat">
<strong>{{ total }}</strong> 人已读
</span>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="userList" size="small" stripe height="340px">
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="登录名称" prop="userName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="用户名称" prop="nickName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="所属部门" prop="deptName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" prop="phonenumber" align="center" width="120" />
<el-table-column label="阅读时间" prop="readTime" align="center" width="160">
<template #default="scope">
<span>{{ parseTime(scope.row.readTime) }}</span>
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
:extra-params="extraParams"
row-key="userId"
size="small"
height="340px"
stripe
:show-toolbar="false"
:selection="false"
:show-index="true"
:auto-load="false"
>
<template #search-extra>
<span class="read-stat"> <strong>{{ readTotal }}</strong> 人已读</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"
style="padding: 6px 0px;"
/>
</basic-table>
</el-dialog>
</template>
@@ -51,52 +28,64 @@ import { listNoticeReadUsers } from "@/api/system/notice"
const { proxy } = getCurrentInstance()
const tableRef = ref()
const visible = ref(false)
const loading = ref(false)
const noticeTitle = ref("")
const total = ref(0)
const userList = ref([])
const readTotal = ref(0)
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
noticeId: undefined,
searchValue: undefined
// 固定参数:公告 ID(每次请求合并,不参与搜索重置)
const extraParams = reactive({ noticeId: undefined })
// 搜索项配置
const searchColumns = [
{
label: "",
prop: "searchValue",
component: "input",
placeholder: "登录名称 / 用户名称",
width: "220px",
formItemProps: { labelWidth: "0px" },
props: {
prefixIcon: Search,
clearable: true,
onKeyup: (e) => { if (e.key === "Enter") tableRef.value?.handleQuery() },
onClear: () => tableRef.value?.handleQuery()
}
}
]
// 表格列配置
const columns = [
{ label: "登录名称", prop: "userName", align: "center" },
{ label: "用户名称", prop: "nickName", align: "center" },
{ label: "所属部门", prop: "deptName", align: "center" },
{ label: "手机号码", prop: "phonenumber", align: "center", width: 120 },
{ label: "阅读时间", prop: "readTime", align: "center", width: 160, parseTime: true }
]
// 查询函数(BasicTable 调用,返回 { rows, total });同时记录已读总数用于统计
function queryList(params) {
return listNoticeReadUsers(params).then(res => {
readTotal.value = res.total
return res
})
}
/** 打开弹框 */
function open(row) {
queryParams.noticeId = row.noticeId
extraParams.noticeId = row.noticeId
noticeTitle.value = row.noticeTitle
queryParams.searchValue = undefined
queryParams.pageNum = 1
visible.value = true
getList()
}
function getList() {
loading.value = true
listNoticeReadUsers(queryParams).then(res => {
userList.value = res.rows
total.value = res.total
}).finally(() => {
loading.value = false
nextTick(() => {
tableRef.value?.setQueryParams({ searchValue: undefined })
tableRef.value?.reload()
})
}
function handleQuery() {
queryParams.pageNum = 1
getList()
}
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 关闭弹框 */
function handleClose() {
userList.value = []
total.value = 0
queryParams.searchValue = undefined
tableRef.value?.clearSelection()
tableRef.value?.setQueryParams({ searchValue: undefined })
}
defineExpose({
@@ -115,4 +104,8 @@ defineExpose({
font-size: 15px;
margin: 0 2px;
}
/* 将搜索栏操作区(搜索/重置 + 已读统计)浮动到右侧 */
:deep(.basic-form > .el-form-item:last-of-type) {
float: right;
}
</style>
+55 -136
View File
@@ -1,41 +1,13 @@
<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">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="noticeId"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -50,8 +22,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:notice:edit']"
>修改</el-button>
</el-col>
@@ -60,54 +32,23 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:notice:remove']"
>删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="noticeId" width="100" />
<el-table-column label="公告标题" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.noticeTitle }}</a>
<template #col-noticeTitle="{ row }">
<a class="link-type" style="cursor:pointer" @click="handleViewData(row)">{{ row.noticeTitle }}</a>
</template>
</el-table-column>
<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="User" @click="handleReadUsers(scope.row)" v-hasPermi="['system:notice:list']">阅读用户</el-button>
<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"
/>
<template #col-action="{ row }">
<el-button link type="primary" icon="User" @click="handleReadUsers(row)" v-hasPermi="['system:notice:list']">阅读用户</el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:notice:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.noticeId)" v-hasPermi="['system:notice:remove']">删除</el-button>
</template>
</basic-table>
<!-- 添加或修改公告对话框 -->
<el-dialog :title="title" v-model="open" width="780px" append-to-body>
@@ -168,42 +109,42 @@ import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api
const { proxy } = getCurrentInstance()
const { sys_notice_status, sys_notice_type } = useDict("sys_notice_status", "sys_notice_type")
const noticeList = ref([])
const tableRef = 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 searchColumns = [
{ label: "公告标题", prop: "noticeTitle", component: "input", placeholder: "请输入公告标题", width: "200px" },
{ label: "操作人员", prop: "createBy", component: "input", placeholder: "请输入操作人员", width: "200px" },
{ label: "类型", prop: "noticeType", component: "select", dict: "sys_notice_type", placeholder: "公告类型", width: "200px" }
]
// 表格列配置
const columns = [
{ label: "序号", prop: "noticeId", align: "center", width: 100 },
{ label: "公告标题", prop: "noticeTitle", align: "center" },
{ label: "公告类型", prop: "noticeType", align: "center", width: 100, dict: "sys_notice_type" },
{ label: "状态", prop: "status", align: "center", width: 100, dict: "sys_notice_status" },
{ label: "创建者", prop: "createBy", align: "center", width: 100 },
{ label: "创建时间", prop: "createTime", align: "center", width: 100, parseTime: "{y}-{m}-{d}" },
{ label: "操作", prop: "action", align: "center", width: 220, showInToolbar: false }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
return listNotice(params)
}
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
})
}
})
const { form, rules } = toRefs(data)
/** 取消按钮 */
function cancel() {
@@ -223,25 +164,6 @@ function reset() {
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()
@@ -252,7 +174,7 @@ function handleAdd() {
/**修改按钮操作 */
function handleUpdate(row) {
reset()
const noticeId = row.noticeId || ids.value
const noticeId = row.noticeId
getNotice(noticeId).then(response => {
form.value = response.data
open.value = true
@@ -265,16 +187,16 @@ function submitForm() {
proxy.$refs["noticeRef"].validate(valid => {
if (valid) {
if (form.value.noticeId != undefined) {
updateNotice(form.value).then(response => {
updateNotice(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
addNotice(form.value).then(response => {
addNotice(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -292,15 +214,12 @@ function handleReadUsers(row) {
}
/** 删除按钮操作 */
function handleDelete(row) {
const noticeIds = row.noticeId || ids.value
function handleDelete(noticeIds) {
proxy.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
return delNotice(noticeIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
getList()
</script>
+48 -125
View File
@@ -1,41 +1,13 @@
<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">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="postId"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -50,8 +22,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:post:edit']"
>修改</el-button>
</el-col>
@@ -60,8 +32,8 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:post:remove']"
>删除</el-button>
</el-col>
@@ -74,40 +46,13 @@
v-hasPermi="['system:post:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="岗位编号" align="center" prop="postId" />
<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 #col-action="{ row }">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:post:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.postId)" v-hasPermi="['system:post:remove']">删除</el-button>
</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"
/>
</basic-table>
<!-- 添加或修改岗位对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
@@ -150,25 +95,35 @@ import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/po
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const postList = ref([])
const tableRef = 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 searchColumns = [
{ label: "岗位编码", prop: "postCode", component: "input", placeholder: "请输入岗位编码", width: "200px" },
{ label: "岗位名称", prop: "postName", component: "input", placeholder: "请输入岗位名称", width: "200px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "岗位状态", width: "200px" }
]
// 表格列配置
const columns = [
{ label: "岗位编号", prop: "postId", align: "center" },
{ label: "岗位编码", prop: "postCode", align: "center" },
{ label: "岗位名称", prop: "postName", align: "center" },
{ label: "岗位排序", prop: "postSort", align: "center" },
{ label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", width: 180, showInToolbar: false }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
return listPost(params)
}
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" }],
@@ -176,17 +131,7 @@ const data = reactive({
}
})
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
})
}
const { form, rules } = toRefs(data)
/** 取消按钮 */
function cancel() {
@@ -207,25 +152,6 @@ function reset() {
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()
@@ -236,7 +162,7 @@ function handleAdd() {
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const postId = row.postId || ids.value
const postId = row.postId
getPost(postId).then(response => {
form.value = response.data
open.value = true
@@ -252,13 +178,13 @@ function submitForm() {
updatePost(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
addPost(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -266,12 +192,11 @@ function submitForm() {
}
/** 删除按钮操作 */
function handleDelete(row) {
const postIds = row.postId || ids.value
function handleDelete(postIds) {
proxy.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
return delPost(postIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -279,9 +204,7 @@ function handleDelete(row) {
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/post/export", {
...queryParams.value
...tableRef.value.getQueryParams()
}, `post_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+49 -103
View File
@@ -1,32 +1,15 @@
<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">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
:extra-params="{ roleId: route.params.roleId }"
row-key="userId"
@selection-change="handleSelectionChange"
>
<template #toolbar="{ selection }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -41,7 +24,7 @@
type="danger"
plain
icon="CircleClose"
:disabled="multiple"
:disabled="!selection.length"
@click="cancelAuthUserAll"
v-hasPermi="['system:role:remove']"
>批量取消授权</el-button>
@@ -54,40 +37,14 @@
@click="handleClose"
>关闭</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="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 #col-action="{ row }">
<el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(row)" v-hasPermi="['system:role:remove']">取消授权</el-button>
</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>
</basic-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" />
<select-user ref="selectRef" :role-id="route.params.roleId" @ok="handleSelectOk" />
</div>
</template>
@@ -97,55 +54,35 @@ import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/syst
const route = useRoute()
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const userList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const multiple = ref(true)
const total = ref(0)
const tableRef = ref()
const userIds = ref([])
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
roleId: route.params.roleId,
userName: undefined,
phonenumber: undefined,
})
// 搜索项配置
const searchColumns = [
{ label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "200px" },
{ label: "手机号码", prop: "phonenumber", component: "input", placeholder: "请输入手机号码", width: "200px" }
]
/** 查询授权用户列表 */
function getList() {
loading.value = true
allocatedUserList(queryParams).then(response => {
userList.value = response.rows
total.value = response.total
loading.value = false
})
}
// 表格列配置
const columns = [
{ label: "用户名称", prop: "userName", align: "center" },
{ label: "用户昵称", prop: "nickName", align: "center" },
{ label: "邮箱", prop: "email", align: "center" },
{ label: "手机", prop: "phonenumber", align: "center" },
{ label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
{ label: "操作", prop: "action", align: "center", width: 120, showInToolbar: false }
]
/** 返回按钮 */
function handleClose() {
const obj = { path: "/system/role" }
proxy.$tab.closeOpenPage(obj)
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
return allocatedUserList(params)
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
userIds.value = selection.map(item => item.userId)
multiple.value = !selection.length
}
/** 打开授权用户表弹窗 */
@@ -153,27 +90,36 @@ function openSelectUser() {
proxy.$refs["selectRef"].show()
}
/** 选择用户回调:刷新列表(回到第一页) */
function handleSelectOk() {
tableRef.value?.reload()
}
/** 取消授权按钮操作 */
function cancelAuthUser(row) {
proxy.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function () {
return authUserCancel({ userId: row.userId, roleId: queryParams.roleId })
return authUserCancel({ userId: row.userId, roleId: route.params.roleId })
}).then(() => {
getList()
tableRef.value?.refresh()
proxy.$modal.msgSuccess("取消授权成功")
}).catch(() => {})
}
/** 批量取消授权按钮操作 */
function cancelAuthUserAll() {
const roleId = queryParams.roleId
const roleId = route.params.roleId
const uIds = userIds.value.join(",")
proxy.$modal.confirm("是否取消选中用户授权数据项?").then(function () {
return authUserCancelAll({ roleId: roleId, userIds: uIds })
}).then(() => {
getList()
tableRef.value?.refresh()
proxy.$modal.msgSuccess("取消授权成功")
}).catch(() => {})
}
getList()
/** 关闭按钮 */
function handleClose() {
const obj = { path: "/system/role" }
proxy.$tab.closeOpenPage(obj)
}
</script>
+68 -167
View File
@@ -1,55 +1,14 @@
<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"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="roleId"
:search-label-width="'68px'"
>
<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">
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
@@ -64,8 +23,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
:disabled="selection.length !== 1"
@click="handleUpdate(selection[0])"
v-hasPermi="['system:role:edit']"
>修改</el-button>
</el-col>
@@ -74,8 +33,8 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['system:role:remove']"
>删除</el-button>
</el-col>
@@ -88,56 +47,32 @@
v-hasPermi="['system:role:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<!-- 表格数据 -->
<el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="角色编号" prop="roleId" width="120" />
<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">
<template #col-status="{ row }">
<el-switch
v-model="scope.row.status"
v-model="row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
@change="handleStatusChange(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"
/>
<template #col-action="{ row }">
<el-tooltip content="修改" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="Delete" @click="handleDelete(row.roleId)" v-hasPermi="['system:role:remove']"></el-button>
</el-tooltip>
<el-tooltip content="数据权限" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="CircleCheck" @click="handleDataScope(row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
<el-tooltip content="分配用户" placement="top" v-if="row.roleId !== 1">
<el-button link type="primary" icon="User" @click="handleAuthUser(row)" v-hasPermi="['system:role:edit']"></el-button>
</el-tooltip>
</template>
</basic-table>
<!-- 添加或修改角色配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
@@ -249,14 +184,8 @@ const router = useRouter()
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const roleList = ref([])
const tableRef = 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([])
@@ -269,6 +198,32 @@ const openDataScope = ref(false)
const menuRef = ref(null)
const deptRef = ref(null)
// 搜索项配置
const searchColumns = [
{ label: "角色名称", prop: "roleName", component: "input", placeholder: "请输入角色名称", width: "240px" },
{ label: "权限字符", prop: "roleKey", component: "input", placeholder: "请输入权限字符", width: "240px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "角色状态", width: "240px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "308px" }
]
// 表格列配置
const columns = [
{ label: "角色编号", prop: "roleId", width: 120 },
{ label: "角色名称", prop: "roleName", width: 150, showOverflowTooltip: true },
{ label: "权限字符", prop: "roleKey", width: 150, showOverflowTooltip: true },
{ label: "显示顺序", prop: "roleSort", width: 100 },
{ label: "状态", prop: "status" },
{ label: "创建时间", prop: "createTime", parseTime: true },
{ label: "操作", prop: "action", showInToolbar: false }
]
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listRole(p)
}
/** 数据范围选项*/
const dataScopeOptions = ref([
{ value: "1", label: "全部数据权限" },
@@ -280,13 +235,6 @@ const dataScopeOptions = ref([
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" }],
@@ -294,38 +242,14 @@ const data = reactive({
},
})
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()
}
const { form, rules } = toRefs(data)
/** 删除按钮操作 */
function handleDelete(row) {
const roleIds = row.roleId || ids.value
function handleDelete(roleIds) {
proxy.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function () {
return delRole(roleIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -333,17 +257,10 @@ function handleDelete(row) {
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/role/export", {
...queryParams.value,
...tableRef.value.getQueryParams()
}, `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" ? "启用" : "停用"
@@ -356,20 +273,6 @@ function handleStatusChange(row) {
})
}
/** 更多操作 */
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)
@@ -427,12 +330,13 @@ function handleAdd() {
/** 修改角色 */
function handleUpdate(row) {
reset()
const roleId = row.roleId || ids.value
const roleId = row.roleId
const roleMenu = getRoleMenuTreeselect(roleId)
getRole(roleId).then(response => {
form.value = response.data
form.value.roleSort = Number(form.value.roleSort)
open.value = true
title.value = "修改角色"
nextTick(() => {
roleMenu.then((res) => {
let checkedKeys = res.checkedKeys
@@ -444,7 +348,6 @@ function handleUpdate(row) {
})
})
})
title.value = "修改角色"
}
/** 根据角色ID查询菜单树结构 */
@@ -515,14 +418,14 @@ function submitForm() {
updateRole(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
form.value.menuIds = getMenuAllCheckedKeys()
addRole(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -549,6 +452,7 @@ function handleDataScope(row) {
getRole(row.roleId).then(response => {
form.value = response.data
openDataScope.value = true
title.value = "分配数据权限"
nextTick(() => {
deptTreeSelect.then(res => {
nextTick(() => {
@@ -559,7 +463,6 @@ function handleDataScope(row) {
})
})
})
title.value = "分配数据权限"
}
/** 提交按钮(数据权限) */
@@ -569,7 +472,7 @@ function submitDataScope() {
dataScope(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
openDataScope.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -579,6 +482,4 @@ function cancelDataScope() {
openDataScope.value = false
reset()
}
getList()
</script>
+42 -87
View File
@@ -1,56 +1,20 @@
<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"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
:extra-params="{ roleId: props.roleId }"
row-key="userId"
size="small"
height="260px"
:show-toolbar="false"
:auto-load="false"
@row-click="clickRow"
@selection-change="handleSelectionChange"
/>
</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>
@@ -70,68 +34,59 @@ const props = defineProps({
})
const { proxy } = getCurrentInstance()
const { sys_normal_disable } = useDict("sys_normal_disable")
const userList = ref([])
const tableRef = 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
})
// 搜索项配置
const searchColumns = [
{ label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "200px" },
{ label: "手机号码", prop: "phonenumber", component: "input", placeholder: "请输入手机号码", width: "200px" }
]
// 表格列配置
const columns = [
{ label: "用户名称", prop: "userName", align: "center" },
{ label: "用户昵称", prop: "nickName", align: "center" },
{ label: "邮箱", prop: "email", align: "center" },
{ label: "手机", prop: "phonenumber", align: "center" },
{ label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
return unallocatedUserList(params)
}
// 显示弹框
function show() {
queryParams.roleId = props.roleId
getList()
visible.value = true
nextTick(() => {
tableRef.value?.reload()
})
}
/** 选择行 */
function clickRow(row) {
proxy.$refs["refTable"].toggleRowSelection(row)
tableRef.value?.getTableRef()?.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 == "") {
const uIds = tableRef.value?.getSelection().map(u => u.userId).join(",") || ""
if (uIds === "") {
proxy.$modal.msgError("请选择要分配的用户")
return
}
authUserSelectAll({ roleId: roleId, userIds: uIds }).then(res => {
authUserSelectAll({ roleId: props.roleId, userIds: uIds }).then(res => {
proxy.$modal.msgSuccess(res.msg)
visible.value = false
emit("ok")
+85 -57
View File
@@ -17,24 +17,17 @@
</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" />
<basic-table
ref="tableRef"
:columns="columns"
:query="queryList"
:extra-params="extraParams"
row-key="roleId"
:show-index="true"
:show-toolbar="false"
@row-click="clickRow"
@selection-change="handleSelectionChange"
/>
<el-form label-width="100px">
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
@@ -51,38 +44,93 @@ 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 tableRef = ref()
const form = ref({
nickName: undefined,
userName: undefined,
userId: undefined
})
const allRoles = ref([])
const currentPageRows = ref([])
const selectedRoleIds = ref(new Set())
// 固定参数:用户 ID(每次请求合并传入)
const extraParams = reactive({ userId: route.params.userId })
// 表格列配置
const columns = [
{ label: "角色编号", prop: "roleId", align: "center" },
{ label: "角色名称", prop: "roleName", align: "center" },
{ label: "权限字符", prop: "roleKey", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
]
/**
* 查询函数:本页数据由 getAuthRole 一次性返回(user + roles),
* BasicTable 走服务端分页机制,这里改为缓存全部角色后按页切片(客户端分页)。
* 跨页选择通过 selectedRoleIds 集合维护(BasicTable 内置 selection 列不支持 reserve-selection)。
*/
function queryList(params) {
const pageNum = params.pageNum || 1
const pageSize = params.pageSize || 10
if (!params.userId) {
return Promise.resolve({ rows: [], total: 0 })
}
if (!allRoles.value.length) {
return getAuthRole(params.userId).then(res => {
form.value = res.user
allRoles.value = res.roles || []
// 初始化已选中集合:原 flag 为 true 的角色
selectedRoleIds.value = new Set(
allRoles.value.filter(r => r.flag).map(r => r.roleId)
)
const total = allRoles.value.length
const rows = allRoles.value.slice((pageNum - 1) * pageSize, pageNum * pageSize)
currentPageRows.value = rows
nextTick(() => applySelection())
return { rows, total }
})
} else {
const total = allRoles.value.length
const rows = allRoles.value.slice((pageNum - 1) * pageSize, pageNum * pageSize)
currentPageRows.value = rows
nextTick(() => applySelection())
return Promise.resolve({ rows, total })
}
}
/** 按当前页回显选中状态(仅当前页可见行可被 toggleRowSelection */
function applySelection() {
const tableEl = tableRef.value?.getTableRef()
currentPageRows.value.forEach(row => {
if (selectedRoleIds.value.has(row.roleId)) {
tableEl?.toggleRowSelection(row, true)
}
})
}
/** 角色状态可选:仅正常(status==="0")角色可勾选 */
function checkSelectable(row) {
return row.status === "0"
}
/** 单击选中行数据 */
function clickRow(row) {
if (checkSelectable(row)) {
proxy.$refs["roleRef"].toggleRowSelection(row)
tableRef.value?.getTableRef()?.toggleRowSelection(row)
}
}
/** 多选框选中数据 */
/** 多选框选中数据:按当前页回填/移除,维护跨页选中集合 */
function handleSelectionChange(selection) {
roleIds.value = selection.map(item => item.roleId)
const pageSelected = new Set(selection.map(r => r.roleId))
currentPageRows.value.forEach(row => {
if (pageSelected.has(row.roleId)) {
selectedRoleIds.value.add(row.roleId)
} else {
selectedRoleIds.value.delete(row.roleId)
}
/** 保存选中的数据编号 */
function getRowKey(row) {
return row.roleId
}
// 检查角色状态
function checkSelectable(row) {
return row.status === "0" ? true : false
})
}
/** 关闭按钮 */
@@ -94,30 +142,10 @@ function close() {
/** 提交按钮 */
function submitForm() {
const userId = form.value.userId
const rIds = roleIds.value.join(",")
const rIds = [...selectedRoleIds.value].join(",")
updateAuthRole({ userId: userId, roleIds: rIds }).then(() => {
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>
+73 -144
View File
@@ -3,36 +3,24 @@
<tree-panel title="组织机构" :tree-data="deptOptions" search-placeholder="请输入部门名称" storage-key="dept-sidebar-width" :defaultExpandAll="true" @node-click="handleNodeClick" @refresh="getDeptTree" ref="deptTreeRef" />
<div class="tree-sidebar-content">
<div class="content-inner">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" 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">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
:extra-params="extraParams"
row-key="userId"
:search-label-width="'68px'"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
<el-button type="success" plain icon="Edit" :disabled="selection.length !== 1" @click="handleUpdate(selection[0])" v-hasPermi="['system:user:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
<el-button type="danger" plain icon="Delete" :disabled="!selection.length" @click="handleDelete(ids)" v-hasPermi="['system:user:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
@@ -40,53 +28,36 @@
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" storageKey="xxxxxxxx"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" />
<el-table-column label="用户名称" align="center" key="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true">
<template #default="scope">
<a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.userName }}</a>
</template>
</el-table-column>
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" />
<el-table-column label="状态" align="center" key="status" v-if="columns.status.visible">
<template #default="scope">
<template #col-userName="{ row }">
<a class="link-type" style="cursor:pointer" @click="handleViewData(row)">{{ row.userName }}</a>
</template>
<template #col-status="{ row }">
<el-switch
v-model="scope.row.status"
v-model="row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
@change="handleStatusChange(row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns.createTime.visible" width="160">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
<template #col-action="{ row }">
<el-tooltip content="修改" placement="top" v-if="row.userId !== 1">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:user:edit']"></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)" v-hasPermi="['system:user:remove']"></el-button>
<el-tooltip content="删除" placement="top" v-if="row.userId !== 1">
<el-button link type="primary" icon="Delete" @click="handleDelete(row.userId)" v-hasPermi="['system:user:remove']"></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)" v-hasPermi="['system:user:resetPwd']"></el-button>
<el-tooltip content="重置密码" placement="top" v-if="row.userId !== 1">
<el-button link type="primary" icon="Key" @click="handleResetPwd(row)" v-hasPermi="['system:user:resetPwd']"></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)" v-hasPermi="['system:user:edit']"></el-button>
<el-tooltip content="分配角色" placement="top" v-if="row.userId !== 1">
<el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(row)" v-hasPermi="['system:user:edit']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</basic-table>
</div>
</div>
@@ -180,7 +151,7 @@
<!-- 用户详情抽屉 -->
<user-view-drawer ref="userViewRef" />
<!-- 用户导入对话框 -->
<excel-import-dialog ref="importUserRef" title="用户导入" action="/system/user/importData" template-action="/system/user/importTemplate" template-file-name="user_template" update-support-label="是否更新已经存在的用户数据" @success="getList" />
<excel-import-dialog ref="importUserRef" title="用户导入" action="/system/user/importData" template-action="/system/user/importTemplate" template-file-name="user_template" update-support-label="是否更新已经存在的用户数据" @success="() => tableRef.refresh()" />
</div>
</template>
@@ -196,42 +167,48 @@ const { proxy } = getCurrentInstance()
const { pwdValidator, pwdPromptValidator } = usePasswordRule()
const { sys_normal_disable, sys_user_sex } = useDict("sys_normal_disable", "sys_user_sex")
const userList = ref([])
const tableRef = 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 deptId = ref(undefined)
const deptOptions = ref(undefined)
const enabledDeptOptions = ref(undefined)
const initPassword = ref(undefined)
const postOptions = ref([])
const roleOptions = ref([])
// 列显隐信息
const columns = ref({
userId: { label: '用户编号', visible: true },
userName: { label: '用户名称', visible: true },
nickName: { label: '用户昵称', visible: true },
deptName: { label: '部门', visible: true },
phonenumber: { label: '手机号码', visible: true },
status: { label: '状态', visible: true },
createTime: { label: '创建时间', visible: true }
})
// 部门联动参数(不参与搜索重置,由树点击控制)
const extraParams = computed(() => ({ deptId: deptId.value }))
// 搜索项配置
const searchColumns = [
{ label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "240px" },
{ label: "手机号码", prop: "phonenumber", component: "input", placeholder: "请输入手机号码", width: "240px" },
{ label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "用户状态", width: "240px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "308px" }
]
// 表格列配置
const columns = [
{ label: "用户编号", prop: "userId" },
{ label: "用户名称", prop: "userName", showOverflowTooltip: true },
{ label: "用户昵称", prop: "nickName", showOverflowTooltip: true },
{ label: "部门", prop: "deptName", showOverflowTooltip: true, formatter: (row) => row.dept ? row.dept.deptName : "" },
{ label: "手机号码", prop: "phonenumber", width: 120 },
{ label: "状态", prop: "status" },
{ label: "创建时间", prop: "createTime", width: 160, parseTime: true },
{ label: "操作", prop: "action", width: 150, showInToolbar: false }
]
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listUser(p)
}
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" }],
@@ -240,17 +217,7 @@ const data = reactive({
}
})
const { queryParams, form, rules } = toRefs(data)
/** 查询用户列表 */
function getList() {
loading.value = true
listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(res => {
loading.value = false
userList.value = res.rows
total.value = res.total
})
}
const { form, rules } = toRefs(data)
/** 查询部门下拉树结构 */
function getDeptTree() {
@@ -275,32 +242,16 @@ function filterDisabledDept(deptList) {
/** 节点单击事件 */
function handleNodeClick(data) {
queryParams.value.deptId = data.id
handleQuery()
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.deptId = undefined
proxy.$refs.deptTreeRef.setCurrentKey(null)
handleQuery()
deptId.value = data.id
tableRef.value.reload()
}
/** 删除按钮操作 */
function handleDelete(row) {
const userIds = row.userId || ids.value
function handleDelete(userIds) {
proxy.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
return delUser(userIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@@ -308,7 +259,7 @@ function handleDelete(row) {
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/user/export", {
...queryParams.value,
...tableRef.value.getQueryParams()
}, `user_${new Date().getTime()}.xlsx`)
}
@@ -324,20 +275,6 @@ function handleStatusChange(row) {
})
}
/** 更多操作 */
function handleCommand(command, row) {
switch (command) {
case "handleResetPwd":
handleResetPwd(row)
break
case "handleAuthRole":
handleAuthRole(row)
break
default:
break
}
}
/** 跳转角色分配 */
function handleAuthRole(row) {
const userId = row.userId
@@ -358,13 +295,6 @@ function handleResetPwd(row) {
}).catch(() => {})
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.userId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 详情按钮操作 */
function handleViewData(row) {
proxy.$refs["userViewRef"].open(row.userId)
@@ -415,7 +345,7 @@ function handleAdd() {
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const userId = row.userId || ids.value
const userId = row.userId
getUser(userId).then(response => {
form.value = response.data
postOptions.value = response.posts
@@ -436,13 +366,13 @@ function submitForm() {
updateUser(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
tableRef.value.refresh()
})
} else {
addUser(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
tableRef.value.refresh()
})
}
}
@@ -451,7 +381,6 @@ function submitForm() {
onMounted(() => {
getDeptTree()
getList()
proxy.getConfigKey("sys.user.initPassword").then(response => {
initPassword.value = response.msg
})
+38 -72
View File
@@ -1,46 +1,19 @@
<template>
<!-- 导入表 -->
<el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
style="width: 180px"
@keyup.enter="handleQuery"
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="tableName"
size="small"
height="260px"
:show-toolbar="false"
:auto-load="false"
@row-click="clickRow"
@selection-change="handleSelectionChange"
/>
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input
v-model="queryParams.tableComment"
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="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleImportTable"> </el-button>
@@ -53,30 +26,43 @@
<script setup>
import { listDbTable, importTable } from "@/api/tool/gen"
const total = ref(0)
const tableRef = ref()
const visible = ref(false)
const tables = ref([])
const dbTableList = ref([])
const { proxy } = getCurrentInstance()
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
})
// 搜索项配置
const searchColumns = [
{ label: "表名称", prop: "tableName", component: "input", placeholder: "请输入表名称", width: "200px" },
{ label: "表描述", prop: "tableComment", component: "input", placeholder: "请输入表描述", width: "200px" }
]
// 表格列配置
const columns = [
{ label: "表名称", prop: "tableName", align: "center" },
{ label: "表描述", prop: "tableComment", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center" },
{ label: "更新时间", prop: "updateTime", align: "center" }
]
// 查询函数(BasicTable 调用,返回 { rows, total }
function queryList(params) {
return listDbTable(params)
}
const emit = defineEmits(["ok"])
/** 查询参数列表 */
/** 显示弹框 */
function show() {
getList()
visible.value = true
nextTick(() => {
tableRef.value?.reload()
})
}
/** 单击选择行 */
function clickRow(row) {
proxy.$refs.table.toggleRowSelection(row)
tableRef.value?.getTableRef()?.toggleRowSelection(row)
}
/** 多选框选中数据 */
@@ -84,30 +70,10 @@ function handleSelectionChange(selection) {
tables.value = selection.map(item => item.tableName)
}
/** 查询表数据 */
function getList() {
listDbTable(queryParams).then(res => {
dbTableList.value = res.rows
total.value = res.total
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 导入按钮操作 */
function handleImportTable() {
const tableNames = tables.value.join(",")
if (tableNames == "") {
const tableNames = tableRef.value?.getSelection().map(t => t.tableName).join(",") || ""
if (tableNames === "") {
proxy.$modal.msgError("请选择要导入的表")
return
}
+95 -155
View File
@@ -1,48 +1,25 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input
v-model="queryParams.tableComment"
placeholder="请输入表描述"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<basic-table
ref="tableRef"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="tableId"
show-index
:default-sort="defaultSort"
:default-params="defaultParams"
@sort-change="handleSortChange"
@selection-change="handleSelectionChange"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Download"
:disabled="multiple"
@click="handleGenTable"
:disabled="!selection.length"
@click="handleGenTable()"
v-hasPermi="['tool:gen:code']"
>生成</el-button>
</el-col>
@@ -69,8 +46,8 @@
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleEditTable"
:disabled="selection.length !== 1"
@click="handleEditTable(selection[0])"
v-hasPermi="['tool:gen:edit']"
>修改</el-button>
</el-col>
@@ -79,53 +56,32 @@
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
:disabled="!selection.length"
@click="handleDelete(ids)"
v-hasPermi="['tool:gen:remove']"
>删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table ref="genRef" v-loading="loading" :data="tableList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
<el-table-column type="selection" align="center" width="55"></el-table-column>
<el-table-column label="序号" type="index" width="50" align="center">
<template #default="scope">
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
<el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" />
<el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" />
<el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="160" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
<template #default="scope">
<template #col-action="{ row }">
<el-tooltip content="预览" placement="top">
<el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
<el-button link type="primary" icon="View" @click="handlePreview(row)" v-hasPermi="['tool:gen:preview']"></el-button>
</el-tooltip>
<el-tooltip content="编辑" placement="top">
<el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
<el-button link type="primary" icon="Edit" @click="handleEditTable(row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row.tableId)" v-hasPermi="['tool:gen:remove']"></el-button>
</el-tooltip>
<el-tooltip content="同步" placement="top">
<el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
<el-button link type="primary" icon="Refresh" @click="handleSynchDb(row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip>
<el-tooltip content="生成代码" placement="top">
<el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
<el-button link type="primary" icon="Download" @click="handleGenTable(row)" v-hasPermi="['tool:gen:code']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</basic-table>
<!-- 预览界面 -->
<el-dialog :title="preview.title" v-model="preview.open" width="80%" top="5vh" append-to-body class="scrollbar">
<el-tabs v-model="preview.activeName">
@@ -147,79 +103,91 @@
<script setup name="Gen">
import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen"
import router from "@/router"
import importTable from "./importTable"
import createTable from "./createTable"
const route = useRoute()
const { proxy } = getCurrentInstance()
const tableList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const tableNames = ref([])
const dateRange = ref([])
const tableRef = ref()
const importRef = ref()
const createRef = ref()
const uniqueId = ref("")
const defaultSort = ref({ prop: "createTime", order: "descending" })
const selectedTableNames = ref([])
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined,
orderByColumn: defaultSort.value.prop,
isAsc: defaultSort.value.order
},
preview: {
// 默认排序
const defaultSort = { prop: "createTime", order: "descending" }
const defaultParams = {
orderByColumn: "createTime",
isAsc: "descending"
}
const preview = reactive({
open: false,
title: "代码预览",
data: {},
activeName: "domain.java"
}
})
const { queryParams, preview } = toRefs(data)
// 搜索项配置
const searchColumns = [
{ label: "表名称", prop: "tableName", component: "input", placeholder: "请输入表名称", width: "200px" },
{ label: "表描述", prop: "tableComment", component: "input", placeholder: "请输入表描述", width: "200px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "308px" }
]
// 表格列配置
const columns = [
{ label: "表名称", prop: "tableName", align: "center" },
{ label: "表描述", prop: "tableComment", align: "center" },
{ label: "实体", prop: "className", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 160, sortable: "custom" },
{ label: "更新时间", prop: "updateTime", align: "center", width: 160, sortable: "custom" },
{ label: "操作", prop: "action", align: "center", width: 330, showInToolbar: false }
]
// 查询函数
function queryList(params) {
const p = proxy.addDateRange({ ...params }, params.dateRange)
delete p.dateRange
return listTable(p)
}
/** 搜索按钮操作(供子组件 @ok 回调) */
function handleQuery() {
tableRef.value.reload()
}
/** 排序触发事件 */
function handleSortChange(column) {
tableRef.value.setQueryParams({ orderByColumn: column.prop, isAsc: column.order })
tableRef.value.reload()
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
selectedTableNames.value = selection.map(item => item.tableName)
}
// keep-alive 页面重新激活时,从路由参数恢复分页并重置搜索
onActivated(() => {
const time = route.query.t
if (time != null && time != uniqueId.value) {
uniqueId.value = time
queryParams.value.pageNum = Number(route.query.pageNum)
dateRange.value = []
proxy.resetForm("queryForm")
getList()
tableRef.value.getSearchFormRef()?.resetFields()
tableRef.value.setQueryParams({ pageNum: Number(route.query.pageNum) || 1 })
tableRef.value.refresh()
}
})
/** 查询表集合 */
function getList() {
loading.value = true
listTable(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
tableList.value = response.rows
total.value = response.total
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 生成代码操作 */
function handleGenTable(row) {
const tbNames = row.tableName || tableNames.value
if (tbNames == "") {
const tbNames = row?.tableName || selectedTableNames.value
if (!tbNames || (Array.isArray(tbNames) && tbNames.length === 0)) {
proxy.$modal.msgError("请选择要生成的数据")
return
}
if (row.genType === "1") {
if (row?.genType === "1") {
genCode(row.tableName).then(response => {
proxy.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath)
})
@@ -241,28 +209,20 @@ function handleSynchDb(row) {
/** 打开导入表弹窗 */
function openImportTable() {
proxy.$refs["importRef"].show()
importRef.value.show()
}
/** 打开创建表弹窗 */
function openCreateTable() {
proxy.$refs["createRef"].show()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.pageNum = 1
proxy.$refs["genRef"].sort(defaultSort.value.prop, defaultSort.value.order)
createRef.value.show()
}
/** 预览按钮 */
function handlePreview(row) {
previewTable(row.tableId).then(response => {
preview.value.data = response.data
preview.value.open = true
preview.value.activeName = "domain.java"
preview.data = response.data
preview.open = true
preview.activeName = "domain.java"
})
}
@@ -271,39 +231,19 @@ function copyTextSuccess() {
proxy.$modal.msgSuccess("复制成功")
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.tableId)
tableNames.value = selection.map(item => item.tableName)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop
queryParams.value.isAsc = column.order
getList()
}
/** 修改按钮操作 */
function handleEditTable(row) {
const tableId = row.tableId || ids.value[0]
const tableName = row.tableName || tableNames.value[0]
const params = { pageNum: queryParams.value.pageNum }
proxy.$tab.openPage("修改[" + tableName + "]生成配置", '/tool/gen-edit/index/' + tableId, params)
const params = { pageNum: tableRef.value.getQueryParams().pageNum }
proxy.$tab.openPage("修改[" + row.tableName + "]生成配置", '/tool/gen-edit/index/' + row.tableId, params)
}
/** 删除按钮操作 */
function handleDelete(row) {
const tableIds = row.tableId || ids.value
function handleDelete(tableIds) {
proxy.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?').then(function () {
return delTable(tableIds)
}).then(() => {
getList()
tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
getList()
</script>