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' VITE_APP_ENV = 'development'
# 若依管理系统/开发环境 # BMS/开发环境
VITE_APP_BASE_API = '/dev-api' 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' VITE_APP_ENV = 'production'
# 若依管理系统/生产环境 # BMS/生产环境
VITE_APP_BASE_API = '/prod-api' VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
+2 -2
View File
@@ -1,10 +1,10 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = 若依管理系统 VITE_APP_TITLE = BMS
# 生产环境配置 # 生产环境配置
VITE_APP_ENV = 'staging' VITE_APP_ENV = 'staging'
# 若依管理系统/生产环境 # BMS/生产环境
VITE_APP_BASE_API = '/stage-api' VITE_APP_BASE_API = '/stage-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.9.2", "version": "3.9.2",
"description": "若依管理系统", "description": "BMS",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
"type": "module", "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 ImagePreview from "@/components/ImagePreview"
// 字典标签组件 // 字典标签组件
import DictTag from '@/components/DictTag' import DictTag from '@/components/DictTag'
// 公共表单组件
import BasicForm from '@/components/BasicForm'
// 公共表格组件
import BasicTable from '@/components/BasicTable'
const app = createApp(App) const app = createApp(App)
@@ -65,6 +69,8 @@ app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview) app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar) app.component('RightToolbar', RightToolbar)
app.component('Editor', Editor) app.component('Editor', Editor)
app.component('BasicForm', BasicForm)
app.component('BasicTable', BasicTable)
app.use(router) app.use(router)
app.use(store) app.use(store)
+1 -1
View File
@@ -4,7 +4,7 @@
<el-col :sm="24" :lg="12" style="padding-left: 20px"> <el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>若依后台管理框架</h2> <h2>若依后台管理框架</h2>
<p> <p>
一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适自己的于是利用空闲休息时间开始自己写一套后台系统如此有了若依管理系统她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA等等当然您也可以对她进行深度定制以做出更强系统所有前端后台代码封装过后十分精简易上手出错概率低同时支持移动客户端访问系统会陆续更新一些实用功能 一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适自己的于是利用空闲休息时间开始自己写一套后台系统如此有了BMS她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA等等当然您也可以对她进行深度定制以做出更强系统所有前端后台代码封装过后十分精简易上手出错概率低同时支持移动客户端访问系统会陆续更新一些实用功能
</p> </p>
<p> <p>
<b>当前版本:</b> <span>v{{ version }}</span> <b>当前版本:</b> <span>v{{ version }}</span>
+361 -435
View File
@@ -1,435 +1,361 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> <basic-table
<el-form-item label="任务名称" prop="jobName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.jobName" :search-columns="searchColumns"
placeholder="请输入任务名称" :query="queryList"
clearable row-key="jobId"
style="width: 200px" >
@keyup.enter="handleQuery" <template #toolbar="{ selection, ids }">
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="任务组名" prop="jobGroup"> type="primary"
<el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable style="width: 200px"> plain
<el-option icon="Plus"
v-for="dict in sys_job_group" @click="handleAdd"
:key="dict.value" v-hasPermi="['monitor:job:add']"
:label="dict.label" >新增</el-button>
:value="dict.value" </el-col>
/> <el-col :span="1.5">
</el-select> <el-button
</el-form-item> type="success"
<el-form-item label="任务状态" prop="status"> plain
<el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable style="width: 200px"> icon="Edit"
<el-option :disabled="selection.length !== 1"
v-for="dict in sys_job_status" @click="handleUpdate(selection[0])"
:key="dict.value" v-hasPermi="['monitor:job:edit']"
:label="dict.label" >修改</el-button>
:value="dict.value" </el-col>
/> <el-col :span="1.5">
</el-select> <el-button
</el-form-item> type="danger"
<el-form-item> plain
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> icon="Delete"
<el-button icon="Refresh" @click="resetQuery">重置</el-button> :disabled="!selection.length"
</el-form-item> @click="handleDelete(ids)"
</el-form> v-hasPermi="['monitor:job:remove']"
>删除</el-button>
<el-row :gutter="10" class="mb8"> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="primary" type="warning"
plain plain
icon="Plus" icon="Download"
@click="handleAdd" @click="handleExport"
v-hasPermi="['monitor:job:add']" v-hasPermi="['monitor:job:export']"
>新增</el-button> >导出</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="success" type="info"
plain plain
icon="Edit" icon="Operation"
:disabled="single" @click="handleJobLog()"
@click="handleUpdate" v-hasPermi="['monitor:job:query']"
v-hasPermi="['monitor:job:edit']" >日志</el-button>
>修改</el-button> </el-col>
</el-col> </template>
<el-col :span="1.5">
<el-button <template #col-jobName="{ row }">
type="danger" <a class="link-type" style="cursor:pointer" @click="handleView(row)">{{ row.jobName }}</a>
plain </template>
icon="Delete"
:disabled="multiple" <template #col-status="{ row }">
@click="handleDelete" <el-switch
v-hasPermi="['monitor:job:remove']" v-model="row.status"
>删除</el-button> active-value="0"
</el-col> inactive-value="1"
<el-col :span="1.5"> @change="handleStatusChange(row)"
<el-button ></el-switch>
type="warning" </template>
plain
icon="Download" <template #col-action="{ row }">
@click="handleExport" <el-tooltip content="修改" placement="top">
v-hasPermi="['monitor:job:export']" <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['monitor:job:edit']"></el-button>
>导出</el-button> </el-tooltip>
</el-col> <el-tooltip content="删除" placement="top">
<el-col :span="1.5"> <el-button link type="primary" icon="Delete" @click="handleDelete(row.jobId)" v-hasPermi="['monitor:job:remove']"></el-button>
<el-button </el-tooltip>
type="info" <el-tooltip content="执行一次" placement="top">
plain <el-button link type="primary" icon="CaretRight" @click="handleRun(row)" v-hasPermi="['monitor:job:changeStatus']"></el-button>
icon="Operation" </el-tooltip>
@click="handleJobLog" <el-tooltip content="调度日志" placement="top">
v-hasPermi="['monitor:job:query']" <el-button link type="primary" icon="Operation" @click="handleJobLog(row)" v-hasPermi="['monitor:job:query']"></el-button>
>日志</el-button> </el-tooltip>
</el-col> </template>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> </basic-table>
</el-row>
<!-- 添加或修改定时任务对话框 -->
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange"> <el-dialog :title="title" v-model="open" width="820px" append-to-body>
<el-table-column type="selection" width="55" align="center" /> <el-form ref="jobRef" :model="form" :rules="rules" label-width="120px">
<el-table-column label="任务编号" width="100" align="center" prop="jobId" /> <el-row>
<el-table-column label="任务名称" align="center" :show-overflow-tooltip="true"> <el-col :span="12">
<template #default="scope"> <el-form-item label="任务名称" prop="jobName">
<a class="link-type" style="cursor:pointer" @click="handleView(scope.row)">{{ scope.row.jobName }}</a> <el-input v-model="form.jobName" placeholder="请输入任务名称" />
</template> </el-form-item>
</el-table-column> </el-col>
<el-table-column label="任务组名" align="center" prop="jobGroup"> <el-col :span="12">
<template #default="scope"> <el-form-item label="任务分组" prop="jobGroup">
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" /> <el-select v-model="form.jobGroup" placeholder="请选择">
</template> <el-option
</el-table-column> v-for="dict in sys_job_group"
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" /> :key="dict.value"
<el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" /> :label="dict.label"
<el-table-column label="状态" align="center"> :value="dict.value"
<template #default="scope"> ></el-option>
<el-switch </el-select>
v-model="scope.row.status" </el-form-item>
active-value="0" </el-col>
inactive-value="1" <el-col :span="24">
@change="handleStatusChange(scope.row)" <el-form-item prop="invokeTarget">
></el-switch> <template #label>
</template> <span>
</el-table-column> 调用方法
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width"> <el-tooltip placement="top">
<template #default="scope"> <template #content>
<el-tooltip content="修改" placement="top"> <div>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['monitor:job:edit']"></el-button> Bean调用示例ryTask.ryParams('ry')
</el-tooltip> <br />Class类调用示例com.ruoyi.quartz.task.RyTask.ryParams('ry')
<el-tooltip content="删除" placement="top"> <br />参数说明支持字符串布尔类型长整型浮点型整型
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['monitor:job:remove']"></el-button> </div>
</el-tooltip> </template>
<el-tooltip content="执行一次" placement="top"> <el-icon><question-filled /></el-icon>
<el-button link type="primary" icon="CaretRight" @click="handleRun(scope.row)" v-hasPermi="['monitor:job:changeStatus']"></el-button> </el-tooltip>
</el-tooltip> </span>
<el-tooltip content="调度日志" placement="top"> </template>
<el-button link type="primary" icon="Operation" @click="handleJobLog(scope.row)" v-hasPermi="['monitor:job:query']"></el-button> <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
</el-tooltip> </el-form-item>
</template> </el-col>
</el-table-column> <el-col :span="24">
</el-table> <el-form-item label="cron表达式" prop="cronExpression">
<el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式">
<pagination <template #append>
v-show="total > 0" <el-button type="primary" @click="handleShowCron">
:total="total" 生成表达式
v-model:page="queryParams.pageNum" <i class="el-icon-time el-icon--right"></i>
v-model:limit="queryParams.pageSize" </el-button>
@pagination="getList" </template>
/> </el-input>
</el-form-item>
<!-- 添加或修改定时任务对话框 --> </el-col>
<el-dialog :title="title" v-model="open" width="820px" append-to-body> <el-col :span="24" v-if="form.jobId !== undefined">
<el-form ref="jobRef" :model="form" :rules="rules" label-width="120px"> <el-form-item label="状态">
<el-row> <el-radio-group v-model="form.status">
<el-col :span="12"> <el-radio
<el-form-item label="任务名称" prop="jobName"> v-for="dict in sys_job_status"
<el-input v-model="form.jobName" placeholder="请输入任务名称" /> :key="dict.value"
</el-form-item> :value="dict.value"
</el-col> >{{ dict.label }}</el-radio>
<el-col :span="12"> </el-radio-group>
<el-form-item label="任务分组" prop="jobGroup"> </el-form-item>
<el-select v-model="form.jobGroup" placeholder="请选择"> </el-col>
<el-option <el-col :span="12">
v-for="dict in sys_job_group" <el-form-item label="执行策略" prop="misfirePolicy">
:key="dict.value" <el-radio-group v-model="form.misfirePolicy">
:label="dict.label" <el-radio-button value="1">立即执行</el-radio-button>
:value="dict.value" <el-radio-button value="2">执行一次</el-radio-button>
></el-option> <el-radio-button value="3">放弃执行</el-radio-button>
</el-select> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="12">
<el-form-item prop="invokeTarget"> <el-form-item label="是否并发" prop="concurrent">
<template #label> <el-radio-group v-model="form.concurrent">
<span> <el-radio-button value="0">允许</el-radio-button>
调用方法 <el-radio-button value="1">禁止</el-radio-button>
<el-tooltip placement="top"> </el-radio-group>
<template #content> </el-form-item>
<div> </el-col>
Bean调用示例ryTask.ryParams('ry') </el-row>
<br />Class类调用示例com.ruoyi.quartz.task.RyTask.ryParams('ry') </el-form>
<br />参数说明支持字符串布尔类型长整型浮点型整型 <template #footer>
</div> <div class="dialog-footer">
</template> <el-button type="primary" @click="submitForm"> </el-button>
<el-icon><question-filled /></el-icon> <el-button @click="cancel"> </el-button>
</el-tooltip> </div>
</span> </template>
</template> </el-dialog>
<el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
</el-form-item> <el-dialog title="Cron表达式生成器" v-model="openCron" append-to-body destroy-on-close>
</el-col> <crontab ref="crontabRef" @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
<el-col :span="24"> </el-dialog>
<el-form-item label="cron表达式" prop="cronExpression">
<el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式"> <!-- 任务详细 -->
<template #append> <job-detail v-model:visible="openView" :row="form" type="job" />
<el-button type="primary" @click="handleShowCron"> </div>
生成表达式 </template>
<i class="el-icon-time el-icon--right"></i>
</el-button> <script setup name="Job">
</template> import Crontab from '@/components/Crontab'
</el-input> import JobDetail from './detail'
</el-form-item> import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job"
</el-col>
<el-col :span="24" v-if="form.jobId !== undefined"> const router = useRouter()
<el-form-item label="状态"> const { proxy } = getCurrentInstance()
<el-radio-group v-model="form.status"> const { sys_job_group, sys_job_status } = useDict("sys_job_group", "sys_job_status")
<el-radio
v-for="dict in sys_job_status" const tableRef = ref()
:key="dict.value" const open = ref(false)
:value="dict.value" const title = ref("")
>{{ dict.label }}</el-radio> const openView = ref(false)
</el-radio-group> const openCron = ref(false)
</el-form-item> const expression = ref("")
</el-col>
<el-col :span="12"> // 搜索项配置
<el-form-item label="执行策略" prop="misfirePolicy"> const searchColumns = [
<el-radio-group v-model="form.misfirePolicy"> { label: "任务名称", prop: "jobName", component: "input", placeholder: "请输入任务名称", width: "200px" },
<el-radio-button value="1">立即执行</el-radio-button> { label: "任务组名", prop: "jobGroup", component: "select", dict: "sys_job_group", placeholder: "请选择任务组名", width: "200px" },
<el-radio-button value="2">执行一次</el-radio-button> { label: "任务状态", prop: "status", component: "select", dict: "sys_job_status", placeholder: "请选择任务状态", width: "200px" }
<el-radio-button value="3">放弃执行</el-radio-button> ]
</el-radio-group>
</el-form-item> // 表格列配置
</el-col> const columns = [
<el-col :span="12"> { label: "任务编号", prop: "jobId", align: "center", width: 100 },
<el-form-item label="是否并发" prop="concurrent"> { label: "任务名称", prop: "jobName", align: "center" },
<el-radio-group v-model="form.concurrent"> { label: "任务组名", prop: "jobGroup", align: "center", dict: "sys_job_group" },
<el-radio-button value="0">允许</el-radio-button> { label: "调用目标字符串", prop: "invokeTarget", align: "center" },
<el-radio-button value="1">禁止</el-radio-button> { label: "cron执行表达式", prop: "cronExpression", align: "center" },
</el-radio-group> { label: "状态", prop: "status", align: "center" },
</el-form-item> { label: "操作", prop: "action", align: "center", width: 200, showInToolbar: false }
</el-col> ]
</el-row>
</el-form> // 查询函数
<template #footer> function queryList(params) {
<div class="dialog-footer"> return listJob(params)
<el-button type="primary" @click="submitForm"> </el-button> }
<el-button @click="cancel"> </el-button>
</div> const data = reactive({
</template> form: {},
</el-dialog> rules: {
jobName: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
<el-dialog title="Cron表达式生成器" v-model="openCron" append-to-body destroy-on-close> invokeTarget: [{ required: true, message: "调用目标字符串不能为空", trigger: "blur" }],
<crontab ref="crontabRef" @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab> cronExpression: [{ required: true, message: "cron执行表达式不能为空", trigger: "change" }]
</el-dialog> }
})
<!-- 任务详细 -->
<job-detail v-model:visible="openView" :row="form" type="job" /> const { form, rules } = toRefs(data)
</div>
</template> /** 取消按钮 */
function cancel() {
<script setup name="Job"> open.value = false
import Crontab from '@/components/Crontab' reset()
import JobDetail from './detail' }
import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job"
/** 表单重置 */
const router = useRouter() function reset() {
const { proxy } = getCurrentInstance() form.value = {
const { sys_job_group, sys_job_status } = useDict("sys_job_group", "sys_job_status") jobId: undefined,
jobName: undefined,
const jobList = ref([]) jobGroup: undefined,
const open = ref(false) invokeTarget: undefined,
const loading = ref(true) cronExpression: undefined,
const showSearch = ref(true) misfirePolicy: '1',
const ids = ref([]) concurrent: '1',
const single = ref(true) status: "0"
const multiple = ref(true) }
const total = ref(0) proxy.resetForm("jobRef")
const title = ref("") }
const openView = ref(false)
const openCron = ref(false) /** 新增按钮操作 */
const expression = ref("") function handleAdd() {
reset()
const data = reactive({ open.value = true
form: {}, title.value = "添加任务"
queryParams: { }
pageNum: 1,
pageSize: 10, /** 修改按钮操作 */
jobName: undefined, function handleUpdate(row) {
jobGroup: undefined, reset()
status: undefined const jobId = row.jobId
}, getJob(jobId).then(response => {
rules: { form.value = response.data
jobName: [{ required: true, message: "任务名称不能为空", trigger: "blur" }], open.value = true
invokeTarget: [{ required: true, message: "调用目标字符串不能为空", trigger: "blur" }], title.value = "修改任务"
cronExpression: [{ required: true, message: "cron执行表达式不能为空", trigger: "change" }] })
} }
})
/** 提交按钮 */
const { queryParams, form, rules } = toRefs(data) function submitForm() {
proxy.$refs["jobRef"].validate(valid => {
/** 查询定时任务列表 */ if (valid) {
function getList() { if (form.value.jobId != undefined) {
loading.value = true updateJob(form.value).then(response => {
listJob(queryParams.value).then(response => { proxy.$modal.msgSuccess("修改成功")
jobList.value = response.rows open.value = false
total.value = response.total tableRef.value.refresh()
loading.value = false })
}) } else {
} addJob(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
/** 取消按钮 */ open.value = false
function cancel() { tableRef.value.refresh()
open.value = false })
reset() }
} }
})
/** 表单重置 */ }
function reset() {
form.value = { /** 删除按钮操作 */
jobId: undefined, function handleDelete(jobIds) {
jobName: undefined, proxy.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function () {
jobGroup: undefined, return delJob(jobIds)
invokeTarget: undefined, }).then(() => {
cronExpression: undefined, tableRef.value.refresh()
misfirePolicy: '1', proxy.$modal.msgSuccess("删除成功")
concurrent: '1', }).catch(() => {})
status: "0" }
}
proxy.resetForm("jobRef") // 任务状态修改
} function handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
/** 搜索按钮操作 */ proxy.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function () {
function handleQuery() { return changeJobStatus(row.jobId, row.status)
queryParams.value.pageNum = 1 }).then(() => {
getList() proxy.$modal.msgSuccess(text + "成功")
} }).catch(function () {
row.status = row.status === "0" ? "1" : "0"
/** 重置按钮操作 */ })
function resetQuery() { }
proxy.resetForm("queryRef")
handleQuery() /* 立即执行一次 */
} function handleRun(row) {
proxy.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function () {
// 多选框选中数据 return runJob(row.jobId, row.jobGroup)
function handleSelectionChange(selection) { }).then(() => {
ids.value = selection.map(item => item.jobId) proxy.$modal.msgSuccess("执行成功")
single.value = selection.length != 1 }).catch(() => {})
multiple.value = !selection.length }
}
/** 任务详细信息 */
// 任务状态修改 function handleView(row) {
function handleStatusChange(row) { getJob(row.jobId).then(response => {
let text = row.status === "0" ? "启用" : "停用" form.value = response.data
proxy.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function () { openView.value = true
return changeJobStatus(row.jobId, row.status) })
}).then(() => { }
proxy.$modal.msgSuccess(text + "成功")
}).catch(function () { /** cron表达式按钮操作 */
row.status = row.status === "0" ? "1" : "0" function handleShowCron() {
}) expression.value = form.value.cronExpression
} openCron.value = true
}
/* 立即执行一次 */
function handleRun(row) { /** 确定后回传值 */
proxy.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function () { function crontabFill(value) {
return runJob(row.jobId, row.jobGroup) form.value.cronExpression = value
}).then(() => { }
proxy.$modal.msgSuccess("执行成功")
}).catch(() => {}) /** 任务日志列表查询 */
} function handleJobLog(row) {
const jobId = row?.jobId || 0
/** 任务详细信息 */ router.push('/monitor/job-log/index/' + jobId)
function handleView(row) { }
getJob(row.jobId).then(response => {
form.value = response.data /** 导出按钮操作 */
openView.value = true function handleExport() {
}) proxy.download("monitor/job/export", {
} ...tableRef.value.getQueryParams()
}, `job_${new Date().getTime()}.xlsx`)
/** cron表达式按钮操作 */ }
function handleShowCron() { </script>
expression.value = form.value.cronExpression
openCron.value = true
}
/** 确定后回传值 */
function crontabFill(value) {
form.value.cronExpression = value
}
/** 任务日志列表查询 */
function handleJobLog(row) {
const jobId = row.jobId || 0
router.push('/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,
}, `job_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+158 -251
View File
@@ -1,251 +1,158 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <basic-table
<el-form-item label="任务名称" prop="jobName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.jobName" :search-columns="searchColumns"
placeholder="请输入任务名称" :query="queryList"
clearable row-key="jobLogId"
style="width: 240px" :auto-load="false"
@keyup.enter="handleQuery" >
/> <template #toolbar="{ selection, ids }">
</el-form-item> <el-col :span="1.5">
<el-form-item label="任务组名" prop="jobGroup"> <el-button
<el-select type="danger"
v-model="queryParams.jobGroup" plain
placeholder="请选择任务组名" icon="Delete"
clearable :disabled="!selection.length"
style="width: 240px" @click="handleDelete(ids)"
> v-hasPermi="['monitor:job:remove']"
<el-option >删除</el-button>
v-for="dict in sys_job_group" </el-col>
:key="dict.value" <el-col :span="1.5">
:label="dict.label" <el-button
:value="dict.value" type="danger"
/> plain
</el-select> icon="Delete"
</el-form-item> @click="handleClean"
<el-form-item label="执行状态" prop="status"> v-hasPermi="['monitor:job:remove']"
<el-select >清空</el-button>
v-model="queryParams.status" </el-col>
placeholder="请选择执行状态" <el-col :span="1.5">
clearable <el-button
style="width: 240px" type="warning"
> plain
<el-option icon="Download"
v-for="dict in sys_common_status" @click="handleExport"
:key="dict.value" v-hasPermi="['monitor:job:export']"
:label="dict.label" >导出</el-button>
:value="dict.value" </el-col>
/> <el-col :span="1.5">
</el-select> <el-button
</el-form-item> type="warning"
<el-form-item label="执行时间" style="width: 308px"> plain
<el-date-picker icon="Close"
v-model="dateRange" @click="handleClose"
value-format="YYYY-MM-DD" >关闭</el-button>
type="daterange" </el-col>
range-separator="-" </template>
start-placeholder="开始日期"
end-placeholder="结束日期" <template #col-action="{ row }">
></el-date-picker> <el-button link type="primary" icon="View" @click="handleView(row)" v-hasPermi="['monitor:job:query']">详细</el-button>
</el-form-item> </template>
<el-form-item> </basic-table>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <!-- 调度日志详细 -->
</el-form-item> <job-detail v-model:visible="open" :row="form" type="log" />
</el-form> </div>
</template>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <script setup name="JobLog">
<el-button import JobDetail from './detail'
type="danger" import { getJob } from "@/api/monitor/job"
plain import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog"
icon="Delete"
:disabled="multiple" const { proxy } = getCurrentInstance()
@click="handleDelete" const { sys_common_status, sys_job_group } = useDict("sys_common_status", "sys_job_group")
v-hasPermi="['monitor:job:remove']"
>删除</el-button> const route = useRoute()
</el-col> const tableRef = ref()
<el-col :span="1.5"> const open = ref(false)
<el-button
type="danger" const data = reactive({
plain form: {}
icon="Delete" })
@click="handleClean" const { form } = toRefs(data)
v-hasPermi="['monitor:job:remove']"
>清空</el-button> // 搜索项配置
</el-col> const searchColumns = [
<el-col :span="1.5"> { label: "任务名称", prop: "jobName", component: "input", placeholder: "请输入任务名称", width: "240px" },
<el-button { label: "任务组名", prop: "jobGroup", component: "select", dict: "sys_job_group", placeholder: "请选择任务组名", width: "240px" },
type="warning" { label: "执行状态", prop: "status", component: "select", dict: "sys_common_status", placeholder: "请选择执行状态", width: "240px" },
plain { label: "执行时间", prop: "dateRange", component: "daterange", width: "308px" }
icon="Download" ]
@click="handleExport"
v-hasPermi="['monitor:job:export']" // 表格列配置
>导出</el-button> const columns = [
</el-col> { label: "日志编号", prop: "jobLogId", align: "center", width: 80 },
<el-col :span="1.5"> { label: "任务名称", prop: "jobName", align: "center" },
<el-button { label: "任务组名", prop: "jobGroup", align: "center", dict: "sys_job_group" },
type="warning" { label: "调用目标字符串", prop: "invokeTarget", align: "center" },
plain { label: "日志信息", prop: "jobMessage", align: "center" },
icon="Close" { label: "执行状态", prop: "status", align: "center", dict: "sys_common_status" },
@click="handleClose" { label: "执行时间", prop: "createTime", align: "center", width: 180, parseTime: true },
>关闭</el-button> { label: "操作", prop: "action", align: "center", showInToolbar: false }
</el-col> ]
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> // 查询函数
function queryList(params) {
<el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange"> const p = proxy.addDateRange({ ...params }, params.dateRange)
<el-table-column type="selection" width="55" align="center" /> delete p.dateRange
<el-table-column label="日志编号" width="80" align="center" prop="jobLogId" /> return listJobLog(p)
<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" /> function handleClose() {
</template> const obj = { path: "/monitor/job" }
</el-table-column> proxy.$tab.closeOpenPage(obj)
<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"> function handleView(row) {
<dict-tag :options="sys_common_status" :value="scope.row.status" /> open.value = true
</template> form.value = row
</el-table-column> }
<el-table-column label="执行时间" align="center" prop="createTime" width="180">
<template #default="scope"> /** 删除按钮操作 */
<span>{{ parseTime(scope.row.createTime) }}</span> function handleDelete(jobIds) {
</template> proxy.$modal.confirm('是否确认删除调度日志编号为"' + jobIds + '"的数据项?').then(function () {
</el-table-column> return delJobLog(jobIds)
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> }).then(() => {
<template #default="scope"> tableRef.value.refresh()
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:job:query']">详细</el-button> proxy.$modal.msgSuccess("删除成功")
</template> }).catch(() => {})
</el-table-column> }
</el-table>
/** 清空按钮操作 */
<pagination function handleClean() {
v-show="total > 0" proxy.$modal.confirm("是否确认清空所有调度日志数据项?").then(function () {
:total="total" return cleanJobLog()
v-model:page="queryParams.pageNum" }).then(() => {
v-model:limit="queryParams.pageSize" tableRef.value.refresh()
@pagination="getList" proxy.$modal.msgSuccess("清空成功")
/> }).catch(() => {})
}
<!-- 调度日志详细 -->
<job-detail v-model:visible="open" :row="form" type="log" /> /** 导出按钮操作 */
</div> function handleExport() {
</template> proxy.download("monitor/jobLog/export", {
...tableRef.value.getQueryParams()
<script setup name="JobLog"> }, `job_log_${new Date().getTime()}.xlsx`)
import JobDetail from './detail' }
import { getJob } from "@/api/monitor/job"
import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog" // 初始化:从路由参数接收 jobId,异步获取任务名称/组名后加载列表
onMounted(() => {
const { proxy } = getCurrentInstance() const jobId = route.params?.jobId || route.query?.jobId
const { sys_common_status, sys_job_group } = useDict("sys_common_status", "sys_job_group") if (jobId !== undefined && jobId != 0) {
getJob(jobId).then(response => {
const jobLogList = ref([]) tableRef.value.setQueryParams({
const open = ref(false) jobName: response.data.jobName,
const loading = ref(true) jobGroup: response.data.jobGroup
const showSearch = ref(true) })
const ids = ref([]) tableRef.value.reload()
const multiple = ref(true) })
const total = ref(0) } else {
const dateRange = ref([]) tableRef.value.reload()
const route = useRoute() }
})
const data = reactive({ </script>
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
status: undefined
}
})
const { queryParams, form, rules } = toRefs(data)
/** 查询调度日志列表 */
function getList() {
loading.value = true
listJobLog(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
jobLogList.value = response.rows
total.value = response.total
loading.value = false
})
}
// 返回按钮
function handleClose() {
const obj = { path: "/monitor/job" }
proxy.$tab.closeOpenPage(obj)
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.jobLogId)
multiple.value = !selection.length
}
/** 详细按钮操作 */
function handleView(row) {
open.value = true
form.value = row
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除调度日志编号为"' + ids.value + '"的数据项?').then(function () {
return delJobLog(ids.value)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有调度日志数据项?").then(function () {
return cleanJobLog()
}).then(() => {
getList()
proxy.$modal.msgSuccess("清空成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/jobLog/export", {
...queryParams.value,
}, `job_log_${new Date().getTime()}.xlsx`)
}
(() => {
const jobId = route.params && route.params.jobId
if (jobId !== undefined && jobId != 0) {
getJob(jobId).then(response => {
queryParams.value.jobName = response.data.jobName
queryParams.value.jobGroup = response.data.jobGroup
getList()
})
} else {
getList()
}
})()
</script>
+144 -233
View File
@@ -1,233 +1,144 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <basic-table
<el-form-item label="登录地址" prop="ipaddr"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.ipaddr" :search-columns="searchColumns"
placeholder="请输入登录地址" :query="queryList"
clearable row-key="infoId"
style="width: 240px;" :default-sort="defaultSort"
@keyup.enter="handleQuery" :default-params="defaultParams"
/> @sort-change="handleSortChange"
</el-form-item> >
<el-form-item label="用户名称" prop="userName"> <template #toolbar="{ selection, ids }">
<el-input <el-col :span="1.5">
v-model="queryParams.userName" <el-button
placeholder="请输入用户名称" type="danger"
clearable plain
style="width: 240px;" icon="Delete"
@keyup.enter="handleQuery" :disabled="!selection.length"
/> @click="handleDelete(ids)"
</el-form-item> v-hasPermi="['monitor:logininfor:remove']"
<el-form-item label="状态" prop="status"> >删除</el-button>
<el-select </el-col>
v-model="queryParams.status" <el-col :span="1.5">
placeholder="登录状态" <el-button
clearable type="danger"
style="width: 240px" plain
> icon="Delete"
<el-option @click="handleClean"
v-for="dict in sys_common_status" v-hasPermi="['monitor:logininfor:remove']"
:key="dict.value" >清空</el-button>
:label="dict.label" </el-col>
:value="dict.value" <el-col :span="1.5">
/> <el-button
</el-select> type="primary"
</el-form-item> plain
<el-form-item label="登录时间" style="width: 308px"> icon="Unlock"
<el-date-picker :disabled="selection.length !== 1"
v-model="dateRange" @click="handleUnlock(selection)"
value-format="YYYY-MM-DD HH:mm:ss" v-hasPermi="['monitor:logininfor:unlock']"
type="daterange" >解锁</el-button>
range-separator="-" </el-col>
start-placeholder="开始日期" <el-col :span="1.5">
end-placeholder="结束日期" <el-button
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" type="warning"
></el-date-picker> plain
</el-form-item> icon="Download"
<el-form-item> @click="handleExport"
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> v-hasPermi="['monitor:logininfor:export']"
<el-button icon="Refresh" @click="resetQuery">重置</el-button> >导出</el-button>
</el-form-item> </el-col>
</el-form> </template>
</basic-table>
<el-row :gutter="10" class="mb8"> </div>
<el-col :span="1.5"> </template>
<el-button
type="danger" <script setup name="Logininfor">
plain import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/monitor/logininfor"
icon="Delete"
:disabled="multiple" const { proxy } = getCurrentInstance()
@click="handleDelete" const { sys_common_status } = useDict("sys_common_status")
v-hasPermi="['monitor:logininfor:remove']"
>删除</el-button> const tableRef = ref()
</el-col>
<el-col :span="1.5"> // 默认排序
<el-button const defaultSort = { prop: "loginTime", order: "descending" }
type="danger"
plain // 默认查询参数(含排序初始值,重置时由 BasicTable 自动恢复)
icon="Delete" const defaultParams = {
@click="handleClean" orderByColumn: "loginTime",
v-hasPermi="['monitor:logininfor:remove']" isAsc: "descending"
>清空</el-button> }
</el-col>
<el-col :span="1.5"> // 搜索项配置
<el-button const searchColumns = [
type="primary" { label: "登录地址", prop: "ipaddr", component: "input", placeholder: "请输入登录地址", width: "240px" },
plain { label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "240px" },
icon="Unlock" { label: "状态", prop: "status", component: "select", dict: "sys_common_status", placeholder: "登录状态", width: "240px" },
:disabled="single" { label: "登录时间", prop: "dateRange", component: "daterange", width: "308px" }
@click="handleUnlock" ]
v-hasPermi="['monitor:logininfor:unlock']"
>解锁</el-button> // 表格列配置
</el-col> const columns = [
<el-col :span="1.5"> { label: "访问编号", prop: "infoId", align: "center" },
<el-button { label: "用户名称", prop: "userName", align: "center", sortable: "custom" },
type="warning" { label: "地址", prop: "ipaddr", align: "center" },
plain { label: "登录地点", prop: "loginLocation", align: "center" },
icon="Download" { label: "操作系统", prop: "os", align: "center" },
@click="handleExport" { label: "浏览器", prop: "browser", align: "center" },
v-hasPermi="['monitor:logininfor:export']" { label: "登录状态", prop: "status", align: "center", dict: "sys_common_status" },
>导出</el-button> { label: "描述", prop: "msg", align: "center" },
</el-col> { label: "访问时间", prop: "loginTime", align: "center", width: 180, sortable: "custom", parseTime: true }
<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"> function queryList(params) {
<el-table-column type="selection" width="55" align="center" /> const p = proxy.addDateRange({ ...params }, params.dateRange)
<el-table-column label="访问编号" align="center" prop="infoId" /> delete p.dateRange
<el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" /> return list(p)
<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" /> function handleSortChange(column) {
<el-table-column label="登录状态" align="center" prop="status"> tableRef.value.setQueryParams({ orderByColumn: column.prop, isAsc: column.order })
<template #default="scope"> tableRef.value.reload()
<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" /> function handleDelete(infoIds) {
<el-table-column label="访问时间" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180"> proxy.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function () {
<template #default="scope"> return delLogininfor(infoIds)
<span>{{ parseTime(scope.row.loginTime) }}</span> }).then(() => {
</template> tableRef.value.refresh()
</el-table-column> proxy.$modal.msgSuccess("删除成功")
</el-table> }).catch(() => {})
}
<pagination
v-show="total > 0" /** 清空按钮操作 */
:total="total" function handleClean() {
v-model:page="queryParams.pageNum" proxy.$modal.confirm("是否确认清空所有登录日志数据项?").then(function () {
v-model:limit="queryParams.pageSize" return cleanLogininfor()
@pagination="getList" }).then(() => {
/> tableRef.value.refresh()
</div> proxy.$modal.msgSuccess("清空成功")
</template> }).catch(() => {})
}
<script setup name="Logininfor">
import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/monitor/logininfor" /** 解锁按钮操作 */
function handleUnlock(selection) {
const { proxy } = getCurrentInstance() const username = selection.map(item => item.userName)
const { sys_common_status } = useDict("sys_common_status") proxy.$modal.confirm('是否确认解锁用户"' + username + '"数据项?').then(function () {
return unlockLogininfor(username)
const logininforList = ref([]) }).then(() => {
const loading = ref(true) proxy.$modal.msgSuccess("用户" + username + "解锁成功")
const showSearch = ref(true) }).catch(() => {})
const ids = ref([]) }
const single = ref(true)
const multiple = ref(true) /** 导出按钮操作 */
const selectName = ref("") function handleExport() {
const total = ref(0) proxy.download("monitor/logininfor/export", {
const dateRange = ref([]) ...tableRef.value.getQueryParams()
const defaultSort = ref({ prop: "loginTime", order: "descending" }) }, `logininfor_${new Date().getTime()}.xlsx`)
}
// 查询参数 </script>
const queryParams = ref({
pageNum: 1,
pageSize: 10,
ipaddr: undefined,
userName: undefined,
status: undefined,
orderByColumn: undefined,
isAsc: undefined
})
/** 查询登录日志列表 */
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
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.pageNum = 1
proxy.$refs["logininforRef"].sort(defaultSort.value.prop, defaultSort.value.order)
}
/** 多选框选中数据 */
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 handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop
queryParams.value.isAsc = column.order
getList()
}
/** 删除按钮操作 */
function handleDelete(row) {
const infoIds = row.infoId || ids.value
proxy.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function () {
return delLogininfor(infoIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有登录日志数据项?").then(function () {
return cleanLogininfor()
}).then(() => {
getList()
proxy.$modal.msgSuccess("清空成功")
}).catch(() => {})
}
/** 解锁按钮操作 */
function handleUnlock() {
const username = selectName.value
proxy.$modal.confirm('是否确认解锁用户"' + username + '"数据项?').then(function () {
return unlockLogininfor(username)
}).then(() => {
proxy.$modal.msgSuccess("用户" + username + "解锁成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/logininfor/export", {
...queryParams.value,
}, `logininfor_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+64 -109
View File
@@ -1,109 +1,64 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true"> <basic-table
<el-form-item label="登录地址" prop="ipaddr"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.ipaddr" :search-columns="searchColumns"
placeholder="请输入登录地址" :query="queryList"
clearable :selection="false"
style="width: 200px" :show-toolbar="false"
@keyup.enter="handleQuery" show-index
/> >
</el-form-item> <template #col-action="{ row }">
<el-form-item label="用户名称" prop="userName"> <el-button link type="primary" icon="Delete" @click="handleForceLogout(row)" v-hasPermi="['monitor:online:forceLogout']">强退</el-button>
<el-input </template>
v-model="queryParams.userName" </basic-table>
placeholder="请输入用户名称" </div>
clearable </template>
style="width: 200px"
@keyup.enter="handleQuery" <script setup name="Online">
/> import { forceLogout, list as initData } from "@/api/monitor/online"
</el-form-item>
<el-form-item> const { proxy } = getCurrentInstance()
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> const tableRef = ref()
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> // 搜索项配置
</el-form> const searchColumns = [
<el-table { label: "登录地址", prop: "ipaddr", component: "input", placeholder: "请输入登录地址", width: "200px" },
v-loading="loading" { label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "200px" }
:data="onlineList.slice((pageNum - 1) * pageSize, pageNum * pageSize)" ]
style="width: 100%;"
> // 表格列配置
<el-table-column label="序号" width="50" type="index" align="center"> const columns = [
<template #default="scope"> { label: "会话编号", prop: "tokenId", align: "center" },
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span> { label: "登录名称", prop: "userName", align: "center" },
</template> { label: "所属部门", prop: "deptName", align: "center" },
</el-table-column> { label: "主机", prop: "ipaddr", align: "center" },
<el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" /> { label: "登录地点", prop: "loginLocation", align: "center" },
<el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" /> { label: "操作系统", prop: "os", align: "center" },
<el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true" /> { label: "浏览器", prop: "browser", align: "center" },
<el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" /> { label: "登录时间", prop: "loginTime", align: "center", width: 180, parseTime: true },
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" /> { label: "操作", prop: "action", align: "center", showInToolbar: false }
<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"> function queryList(params) {
<span>{{ parseTime(scope.row.loginTime) }}</span> return initData({ ipaddr: params.ipaddr, userName: params.userName }).then(res => {
</template> const start = (params.pageNum - 1) * params.pageSize
</el-table-column> return {
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> rows: res.rows.slice(start, start + params.pageSize),
<template #default="scope"> total: res.total
<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" /> function handleForceLogout(row) {
</div> proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
</template> return forceLogout(row.tokenId)
}).then(() => {
<script setup name="Online"> tableRef.value.refresh()
import { forceLogout, list as initData } from "@/api/monitor/online" proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
const { proxy } = getCurrentInstance() }
</script>
const onlineList = ref([])
const loading = ref(true)
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)
const queryParams = ref({
ipaddr: undefined,
userName: undefined
})
/** 查询登录日志列表 */
function getList() {
loading.value = true
initData(queryParams.value).then(response => {
onlineList.value = response.rows
total.value = response.total
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
pageNum.value = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 强退按钮操作 */
function handleForceLogout(row) {
proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
return forceLogout(row.tokenId)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
getList()
</script>
+141 -262
View File
@@ -1,262 +1,141 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <basic-table
<el-form-item label="操作地址" prop="operIp"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.operIp" :search-columns="searchColumns"
placeholder="请输入操作地址" :query="queryList"
clearable row-key="operId"
style="width: 240px;" :default-sort="defaultSort"
@keyup.enter="handleQuery" :default-params="defaultParams"
/> @sort-change="handleSortChange"
</el-form-item> >
<el-form-item label="系统模块" prop="title"> <template #toolbar="{ selection, ids }">
<el-input <el-col :span="1.5">
v-model="queryParams.title" <el-button
placeholder="请输入系统模块" type="danger"
clearable plain
style="width: 240px;" icon="Delete"
@keyup.enter="handleQuery" :disabled="!selection.length"
/> @click="handleDelete(ids)"
</el-form-item> v-hasPermi="['monitor:operlog:remove']"
<el-form-item label="操作人员" prop="operName"> >删除</el-button>
<el-input </el-col>
v-model="queryParams.operName" <el-col :span="1.5">
placeholder="请输入操作人员" <el-button
clearable type="danger"
style="width: 240px;" plain
@keyup.enter="handleQuery" icon="Delete"
/> @click="handleClean"
</el-form-item> v-hasPermi="['monitor:operlog:remove']"
<el-form-item label="类型" prop="businessType"> >清空</el-button>
<el-select </el-col>
v-model="queryParams.businessType" <el-col :span="1.5">
placeholder="操作类型" <el-button
clearable type="warning"
style="width: 240px" plain
> icon="Download"
<el-option @click="handleExport"
v-for="dict in sys_oper_type" v-hasPermi="['monitor:operlog:export']"
:key="dict.value" >导出</el-button>
:label="dict.label" </el-col>
:value="dict.value" </template>
/>
</el-select> <template #col-action="{ row }">
</el-form-item> <el-button link type="primary" icon="View" @click="handleDetail(row)" v-hasPermi="['monitor:operlog:query']">详细</el-button>
<el-form-item label="状态" prop="status"> </template>
<el-select </basic-table>
v-model="queryParams.status"
placeholder="操作状态" <operlog-detail v-model:visible="detailVisible" :row="detailRow" />
clearable </div>
style="width: 240px" </template>
>
<el-option <script setup name="Operlog">
v-for="dict in sys_common_status" import OperlogDetail from './detail'
:key="dict.value" import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog"
:label="dict.label"
:value="dict.value" const { proxy } = getCurrentInstance()
/> const { sys_oper_type, sys_common_status } = useDict("sys_oper_type", "sys_common_status")
</el-select>
</el-form-item> const tableRef = ref()
<el-form-item label="操作时间" style="width: 308px"> const detailVisible = ref(false)
<el-date-picker const detailRow = ref({})
v-model="dateRange"
value-format="YYYY-MM-DD HH:mm:ss" // 默认排序
type="daterange" const defaultSort = { prop: "operTime", order: "descending" }
range-separator="-"
start-placeholder="开始日期" // 默认查询参数(含排序初始值,重置时由 BasicTable 自动恢复)
end-placeholder="结束日期" const defaultParams = {
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" orderByColumn: "operTime",
></el-date-picker> isAsc: "descending"
</el-form-item> }
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> // 搜索项配置
<el-button icon="Refresh" @click="resetQuery">重置</el-button> const searchColumns = [
</el-form-item> { label: "操作地址", prop: "operIp", component: "input", placeholder: "请输入操作地址", width: "240px" },
</el-form> { label: "系统模块", prop: "title", component: "input", placeholder: "请输入系统模块", width: "240px" },
{ label: "操作人员", prop: "operName", component: "input", placeholder: "请输入操作人员", width: "240px" },
<el-row :gutter="10" class="mb8"> { label: "类型", prop: "businessType", component: "select", dict: "sys_oper_type", placeholder: "操作类型", width: "240px" },
<el-col :span="1.5"> { label: "状态", prop: "status", component: "select", dict: "sys_common_status", placeholder: "操作状态", width: "240px" },
<el-button { label: "操作时间", prop: "dateRange", component: "daterange", width: "308px" }
type="danger" ]
plain
icon="Delete" // 表格列配置
:disabled="multiple" const columns = [
@click="handleDelete" { label: "日志编号", prop: "operId", align: "center" },
v-hasPermi="['monitor:operlog:remove']" { label: "系统模块", prop: "title", align: "center" },
>删除</el-button> { label: "操作类型", prop: "businessType", align: "center", dict: "sys_oper_type" },
</el-col> { label: "操作人员", prop: "operName", align: "center", width: 110, sortable: "custom" },
<el-col :span="1.5"> { label: "操作地址", prop: "operIp", align: "center", width: 130 },
<el-button { label: "操作状态", prop: "status", align: "center", dict: "sys_common_status" },
type="danger" { label: "操作日期", prop: "operTime", align: "center", width: 180, sortable: "custom", parseTime: true },
plain { label: "消耗时间", prop: "costTime", align: "center", width: 110, sortable: "custom", formatter: (row, col, val) => val + '毫秒' },
icon="Delete" { label: "操作", prop: "action", align: "center", showInToolbar: false }
@click="handleClean" ]
v-hasPermi="['monitor:operlog:remove']"
>清空</el-button> // 查询函数
</el-col> function queryList(params) {
<el-col :span="1.5"> const p = proxy.addDateRange({ ...params }, params.dateRange)
<el-button delete p.dateRange
type="warning" return list(p)
plain }
icon="Download"
@click="handleExport" /** 排序触发事件 */
v-hasPermi="['monitor:operlog:export']" function handleSortChange(column) {
>导出</el-button> tableRef.value.setQueryParams({ orderByColumn: column.prop, isAsc: column.order })
</el-col> tableRef.value.reload()
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> }
</el-row>
/** 详细按钮操作 */
<el-table ref="operlogRef" v-loading="loading" :data="operlogList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange"> function handleDetail(row) {
<el-table-column type="selection" width="50" align="center" /> detailRow.value = row
<el-table-column label="日志编号" align="center" prop="operId" /> detailVisible.value = true
<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" /> function handleDelete(operIds) {
</template> proxy.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function () {
</el-table-column> return delOperlog(operIds)
<el-table-column label="操作人员" align="center" width="110" prop="operName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" /> }).then(() => {
<el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" /> tableRef.value.refresh()
<el-table-column label="操作状态" align="center" prop="status"> proxy.$modal.msgSuccess("删除成功")
<template #default="scope"> }).catch(() => {})
<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']"> function handleClean() {
<template #default="scope"> proxy.$modal.confirm("是否确认清空所有操作日志数据项?").then(function () {
<span>{{ parseTime(scope.row.operTime) }}</span> return cleanOperlog()
</template> }).then(() => {
</el-table-column> tableRef.value.refresh()
<el-table-column label="消耗时间" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']"> proxy.$modal.msgSuccess("清空成功")
<template #default="scope"> }).catch(() => {})
<span>{{ scope.row.costTime }}毫秒</span> }
</template>
</el-table-column> /** 导出按钮操作 */
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> function handleExport() {
<template #default="scope"> proxy.download("monitor/operlog/export", {
<el-button link type="primary" icon="View" @click="handleDetail(scope.row, scope.index)" v-hasPermi="['monitor:operlog:query']">详细</el-button> ...tableRef.value.getQueryParams()
</template> }, `config_${new Date().getTime()}.xlsx`)
</el-table-column> }
</el-table> </script>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<operlog-detail v-model:visible="detailVisible" :row="detailRow" />
</div>
</template>
<script setup name="Operlog">
import OperlogDetail from './detail'
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 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 { 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
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.pageNum = 1
proxy.$refs["operlogRef"].sort(defaultSort.value.prop, defaultSort.value.order)
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.operId)
multiple.value = !selection.length
}
/** 排序触发事件 */
function handleSortChange(column, prop, order) {
queryParams.value.orderByColumn = column.prop
queryParams.value.isAsc = column.order
getList()
}
/** 详细按钮操作 */
function handleDetail(row) {
detailRow.value = row
detailVisible.value = true
}
/** 删除按钮操作 */
function handleDelete(row) {
const operIds = row.operId || ids.value
proxy.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function () {
return delOperlog(operIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 清空按钮操作 */
function handleClean() {
proxy.$modal.confirm("是否确认清空所有操作日志数据项?").then(function () {
return cleanOperlog()
}).then(() => {
getList()
proxy.$modal.msgSuccess("清空成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("monitor/operlog/export",{
...queryParams.value,
}, `config_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+230 -316
View File
@@ -1,316 +1,230 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <basic-table
<el-form-item label="参数名称" prop="configName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.configName" :search-columns="searchColumns"
placeholder="请输入参数名称" :query="queryList"
clearable row-key="configId"
style="width: 240px" >
@keyup.enter="handleQuery" <template #toolbar="{ selection, ids }">
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="参数键名" prop="configKey"> type="primary"
<el-input plain
v-model="queryParams.configKey" icon="Plus"
placeholder="请输入参数键名" @click="handleAdd"
clearable v-hasPermi="['system:config:add']"
style="width: 240px" >新增</el-button>
@keyup.enter="handleQuery" </el-col>
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="系统内置" prop="configType"> type="success"
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable style="width: 240px"> plain
<el-option icon="Edit"
v-for="dict in sys_yes_no" :disabled="selection.length !== 1"
:key="dict.value" @click="handleUpdate(selection[0])"
:label="dict.label" v-hasPermi="['system:config:edit']"
:value="dict.value" >修改</el-button>
/> </el-col>
</el-select> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="创建时间" style="width: 308px;"> type="danger"
<el-date-picker plain
v-model="dateRange" icon="Delete"
value-format="YYYY-MM-DD" :disabled="!selection.length"
type="daterange" @click="handleDelete(ids)"
range-separator="-" v-hasPermi="['system:config:remove']"
start-placeholder="开始日期" >删除</el-button>
end-placeholder="结束日期" </el-col>
></el-date-picker> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item> type="warning"
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> plain
<el-button icon="Refresh" @click="resetQuery">重置</el-button> icon="Download"
</el-form-item> @click="handleExport"
</el-form> v-hasPermi="['system:config:export']"
>导出</el-button>
<el-row :gutter="10" class="mb8"> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="primary" type="danger"
plain plain
icon="Plus" icon="Refresh"
@click="handleAdd" @click="handleRefreshCache"
v-hasPermi="['system:config:add']" v-hasPermi="['system:config:remove']"
>新增</el-button> >刷新缓存</el-button>
</el-col> </el-col>
<el-col :span="1.5"> </template>
<el-button
type="success" <template #col-action="{ row }">
plain <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:config:edit']">修改</el-button>
icon="Edit" <el-button link type="primary" icon="Delete" @click="handleDelete(row.configId)" v-hasPermi="['system:config:remove']">删除</el-button>
:disabled="single" </template>
@click="handleUpdate" </basic-table>
v-hasPermi="['system:config:edit']"
>修改</el-button> <!-- 添加或修改参数配置对话框 -->
</el-col> <el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-col :span="1.5"> <el-form ref="configRef" :model="form" :rules="rules" label-width="80px">
<el-button <el-form-item label="参数名称" prop="configName">
type="danger" <el-input v-model="form.configName" placeholder="请输入参数名称" />
plain </el-form-item>
icon="Delete" <el-form-item label="参数键名" prop="configKey">
:disabled="multiple" <el-input v-model="form.configKey" placeholder="请输入参数键名" />
@click="handleDelete" </el-form-item>
v-hasPermi="['system:config:remove']" <el-form-item label="参数键值" prop="configValue">
>删除</el-button> <el-input v-model="form.configValue" type="textarea" placeholder="请输入参数键值" />
</el-col> </el-form-item>
<el-col :span="1.5"> <el-form-item label="系统内置" prop="configType">
<el-button <el-radio-group v-model="form.configType">
type="warning" <el-radio
plain v-for="dict in sys_yes_no"
icon="Download" :key="dict.value"
@click="handleExport" :value="dict.value"
v-hasPermi="['system:config:export']" >{{ dict.label }}</el-radio>
>导出</el-button> </el-radio-group>
</el-col> </el-form-item>
<el-col :span="1.5"> <el-form-item label="备注" prop="remark">
<el-button <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
type="danger" </el-form-item>
plain </el-form>
icon="Refresh" <template #footer>
@click="handleRefreshCache" <div class="dialog-footer">
v-hasPermi="['system:config:remove']" <el-button type="primary" @click="submitForm"> </el-button>
>刷新缓存</el-button> <el-button @click="cancel"> </el-button>
</el-col> </div>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> </template>
</el-row> </el-dialog>
</div>
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange"> </template>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="参数主键" align="center" prop="configId" /> <script setup name="Config">
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" /> import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config"
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
<el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" /> const { proxy } = getCurrentInstance()
<el-table-column label="系统内置" align="center" prop="configType"> const { sys_yes_no } = useDict("sys_yes_no")
<template #default="scope">
<dict-tag :options="sys_yes_no" :value="scope.row.configType" /> const tableRef = ref()
</template> const open = ref(false)
</el-table-column> const title = ref("")
<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"> const searchColumns = [
<span>{{ parseTime(scope.row.createTime) }}</span> { label: "参数名称", prop: "configName", component: "input", placeholder: "请输入参数名称", width: "240px" },
</template> { label: "参数键名", prop: "configKey", component: "input", placeholder: "请输入参数键名", width: "240px" },
</el-table-column> { label: "系统内置", prop: "configType", component: "select", dict: "sys_yes_no", placeholder: "系统内置", width: "240px" },
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width"> { label: "创建时间", prop: "dateRange", component: "daterange", width: "320px" }
<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> const columns = [
</el-table-column> { label: "参数主键", prop: "configId", align: "center" },
</el-table> { label: "参数名称", prop: "configName", align: "center" },
{ label: "参数键名", prop: "configKey", align: "center" },
<pagination { label: "参数键值", prop: "configValue", align: "center" },
v-show="total > 0" { label: "系统内置", prop: "configType", align: "center", dict: "sys_yes_no" },
:total="total" { label: "备注", prop: "remark", align: "center" },
v-model:page="queryParams.pageNum" { label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
v-model:limit="queryParams.pageSize" { label: "操作", prop: "action", align: "center", width: 150, showInToolbar: false }
@pagination="getList" ]
/>
// 查询函数(BasicTable 调用,返回 { rows, total }
<!-- 添加或修改参数配置对话框 --> function queryList(params) {
<el-dialog :title="title" v-model="open" width="500px" append-to-body> const p = proxy.addDateRange({ ...params }, params.dateRange)
<el-form ref="configRef" :model="form" :rules="rules" label-width="80px"> delete p.dateRange
<el-form-item label="参数名称" prop="configName"> return listConfig(p)
<el-input v-model="form.configName" placeholder="请输入参数名称" /> }
</el-form-item>
<el-form-item label="参数键名" prop="configKey"> const data = reactive({
<el-input v-model="form.configKey" placeholder="请输入参数键名" /> form: {},
</el-form-item> rules: {
<el-form-item label="参数键值" prop="configValue"> configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
<el-input v-model="form.configValue" type="textarea" placeholder="请输入参数键值" /> configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
</el-form-item> configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
<el-form-item label="系统内置" prop="configType"> }
<el-radio-group v-model="form.configType"> })
<el-radio
v-for="dict in sys_yes_no" const { form, rules } = toRefs(data)
:key="dict.value"
:value="dict.value" /** 取消按钮 */
>{{ dict.label }}</el-radio> function cancel() {
</el-radio-group> open.value = false
</el-form-item> reset()
<el-form-item label="备注" prop="remark"> }
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item> /** 表单重置 */
</el-form> function reset() {
<template #footer> form.value = {
<div class="dialog-footer"> configId: undefined,
<el-button type="primary" @click="submitForm"> </el-button> configName: undefined,
<el-button @click="cancel"> </el-button> configKey: undefined,
</div> configValue: undefined,
</template> configType: "Y",
</el-dialog> remark: undefined
</div> }
</template> proxy.resetForm("configRef")
}
<script setup name="Config">
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config" /** 新增按钮操作 */
function handleAdd() {
const { proxy } = getCurrentInstance() reset()
const { sys_yes_no } = useDict("sys_yes_no") open.value = true
title.value = "添加参数"
const configList = ref([]) }
const open = ref(false)
const loading = ref(true) /** 修改按钮操作 */
const showSearch = ref(true) function handleUpdate(row) {
const ids = ref([]) reset()
const single = ref(true) const configId = row.configId
const multiple = ref(true) getConfig(configId).then(response => {
const total = ref(0) form.value = response.data
const title = ref("") open.value = true
const dateRange = ref([]) title.value = "修改参数"
})
const data = reactive({ }
form: {},
queryParams: { /** 提交按钮 */
pageNum: 1, function submitForm() {
pageSize: 10, proxy.$refs["configRef"].validate(valid => {
configName: undefined, if (valid) {
configKey: undefined, if (form.value.configId != undefined) {
configType: undefined updateConfig(form.value).then(() => {
}, proxy.$modal.msgSuccess("修改成功")
rules: { open.value = false
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }], tableRef.value.refresh()
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }], })
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }] } else {
} addConfig(form.value).then(() => {
}) proxy.$modal.msgSuccess("新增成功")
open.value = false
const { queryParams, form, rules } = toRefs(data) tableRef.value.refresh()
})
/** 查询参数列表 */ }
function getList() { }
loading.value = true })
listConfig(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { }
configList.value = response.rows
total.value = response.total /** 删除按钮操作 */
loading.value = false function handleDelete(configIds) {
}) proxy.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function () {
} return delConfig(configIds)
}).then(() => {
/** 取消按钮 */ tableRef.value.refresh()
function cancel() { proxy.$modal.msgSuccess("删除成功")
open.value = false }).catch(() => {})
reset() }
}
/** 导出按钮操作 */
/** 表单重置 */ function handleExport() {
function reset() { proxy.download("system/config/export", {
form.value = { ...tableRef.value.getQueryParams()
configId: undefined, }, `config_${new Date().getTime()}.xlsx`)
configName: undefined, }
configKey: undefined,
configValue: undefined, /** 刷新缓存按钮操作 */
configType: "Y", function handleRefreshCache() {
remark: undefined refreshCache().then(() => {
} proxy.$modal.msgSuccess("刷新缓存成功")
proxy.resetForm("configRef") })
} }
</script>
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.configId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加参数"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const configId = row.configId || ids.value
getConfig(configId).then(response => {
form.value = response.data
open.value = true
title.value = "修改参数"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["configRef"].validate(valid => {
if (valid) {
if (form.value.configId != undefined) {
updateConfig(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addConfig(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const configIds = row.configId || ids.value
proxy.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function () {
return delConfig(configIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/config/export", {
...queryParams.value
}, `config_${new Date().getTime()}.xlsx`)
}
/** 刷新缓存按钮操作 */
function handleRefreshCache() {
refreshCache().then(() => {
proxy.$modal.msgSuccess("刷新缓存成功")
})
}
getList()
</script>
+276 -362
View File
@@ -1,362 +1,276 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> <basic-table
<el-form-item label="字典名称" prop="dictType"> ref="tableRef"
<el-select v-model="queryParams.dictType" style="width: 200px"> :columns="columns"
<el-option :search-columns="searchColumns"
v-for="item in typeOptions" :query="queryList"
:key="item.dictId" :extra-params="extraParams"
:label="item.dictName" :auto-load="false"
:value="item.dictType" row-key="dictCode"
/> >
</el-select> <template #toolbar="{ selection, ids }">
</el-form-item> <el-col :span="1.5">
<el-form-item label="字典标签" prop="dictLabel"> <el-button
<el-input type="primary"
v-model="queryParams.dictLabel" plain
placeholder="请输入字典标签" icon="Plus"
clearable @click="handleAdd"
style="width: 200px" v-hasPermi="['system:dict:add']"
@keyup.enter="handleQuery" >新增</el-button>
/> </el-col>
</el-form-item> <el-col :span="1.5">
<el-form-item label="状态" prop="status"> <el-button
<el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px"> type="success"
<el-option plain
v-for="dict in sys_normal_disable" icon="Edit"
:key="dict.value" :disabled="selection.length !== 1"
:label="dict.label" @click="handleUpdate(selection[0])"
:value="dict.value" v-hasPermi="['system:dict:edit']"
/> >修改</el-button>
</el-select> </el-col>
</el-form-item> <el-col :span="1.5">
<el-form-item> <el-button
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> type="danger"
<el-button icon="Refresh" @click="resetQuery">重置</el-button> plain
</el-form-item> icon="Delete"
</el-form> :disabled="!selection.length"
@click="handleDelete(ids)"
<el-row :gutter="10" class="mb8"> v-hasPermi="['system:dict:remove']"
<el-col :span="1.5"> >删除</el-button>
<el-button </el-col>
type="primary" <el-col :span="1.5">
plain <el-button
icon="Plus" type="warning"
@click="handleAdd" plain
v-hasPermi="['system:dict:add']" icon="Download"
>新增</el-button> @click="handleExport"
</el-col> v-hasPermi="['system:dict:export']"
<el-col :span="1.5"> >导出</el-button>
<el-button </el-col>
type="success" <el-col :span="1.5">
plain <el-button
icon="Edit" type="warning"
:disabled="single" plain
@click="handleUpdate" icon="Close"
v-hasPermi="['system:dict:edit']" @click="handleClose"
>修改</el-button> >关闭</el-button>
</el-col> </el-col>
<el-col :span="1.5"> </template>
<el-button
type="danger" <template #col-dictLabel="{ row }">
plain <span v-if="(row.listClass == '' || row.listClass == 'default') && (row.cssClass == '' || row.cssClass == null)">{{ row.dictLabel }}</span>
icon="Delete" <el-tag v-else :type="row.listClass == 'primary' ? '' : row.listClass" :class="row.cssClass">{{ row.dictLabel }}</el-tag>
:disabled="multiple" </template>
@click="handleDelete"
v-hasPermi="['system:dict:remove']" <template #col-action="{ row }">
>删除</el-button> <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:dict:edit']">修改</el-button>
</el-col> <el-button link type="primary" icon="Delete" @click="handleDelete(row.dictCode)" v-hasPermi="['system:dict:remove']">删除</el-button>
<el-col :span="1.5"> </template>
<el-button </basic-table>
type="warning"
plain <!-- 添加或修改参数配置对话框 -->
icon="Download" <el-dialog :title="title" v-model="open" width="500px" append-to-body>
@click="handleExport" <el-form ref="dataRef" :model="form" :rules="rules" label-width="80px">
v-hasPermi="['system:dict:export']" <el-form-item label="字典类型">
>导出</el-button> <el-input v-model="form.dictType" :disabled="true" />
</el-col> </el-form-item>
<el-col :span="1.5"> <el-form-item label="数据标签" prop="dictLabel">
<el-button <el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
type="warning" </el-form-item>
plain <el-form-item label="数据键值" prop="dictValue">
icon="Close" <el-input v-model="form.dictValue" placeholder="请输入数据键值" />
@click="handleClose" </el-form-item>
>关闭</el-button> <el-form-item label="样式属性" prop="cssClass">
</el-col> <el-input v-model="form.cssClass" placeholder="请输入样式属性" />
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> </el-form-item>
</el-row> <el-form-item label="显示排序" prop="dictSort">
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange"> </el-form-item>
<el-table-column type="selection" width="55" align="center" /> <el-form-item label="回显样式" prop="listClass">
<el-table-column label="字典编码" align="center" prop="dictCode" /> <el-select v-model="form.listClass">
<el-table-column label="字典标签" align="center" prop="dictLabel"> <el-option
<template #default="scope"> v-for="item in listClassOptions"
<span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span> :key="item.value"
<el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag> :label="item.label + '(' + item.value + ')'"
</template> :value="item.value"
</el-table-column> ></el-option>
<el-table-column label="字典键值" align="center" prop="dictValue" /> </el-select>
<el-table-column label="字典排序" align="center" prop="dictSort" /> </el-form-item>
<el-table-column label="状态" align="center" prop="status"> <el-form-item label="状态" prop="status">
<template #default="scope"> <el-radio-group v-model="form.status">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" /> <el-radio
</template> v-for="dict in sys_normal_disable"
</el-table-column> :key="dict.value"
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" /> :value="dict.value"
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> >{{ dict.label }}</el-radio>
<template #default="scope"> </el-radio-group>
<span>{{ parseTime(scope.row.createTime) }}</span> </el-form-item>
</template> <el-form-item label="备注" prop="remark">
</el-table-column> <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> </el-form-item>
<template #default="scope"> </el-form>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']">修改</el-button> <template #footer>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']">删除</el-button> <div class="dialog-footer">
</template> <el-button type="primary" @click="submitForm"> </el-button>
</el-table-column> <el-button @click="cancel"> </el-button>
</el-table> </div>
</template>
<pagination </el-dialog>
v-show="total > 0" </div>
:total="total" </template>
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" <script setup name="Data">
@pagination="getList" import useDictStore from '@/store/modules/dict'
/> import { getType } from "@/api/system/dict/type"
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data"
<!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body> const { proxy } = getCurrentInstance()
<el-form ref="dataRef" :model="form" :rules="rules" label-width="80px"> const { sys_normal_disable } = useDict("sys_normal_disable")
<el-form-item label="字典类型">
<el-input v-model="form.dictType" :disabled="true" /> const tableRef = ref()
</el-form-item> const open = ref(false)
<el-form-item label="数据标签" prop="dictLabel"> const title = ref("")
<el-input v-model="form.dictLabel" placeholder="请输入数据标签" /> const route = useRoute()
</el-form-item> // 上级字典类型(来自路由,固定参数,不随搜索重置)
<el-form-item label="数据键值" prop="dictValue"> const extraParams = reactive({ dictType: "" })
<el-input v-model="form.dictValue" placeholder="请输入数据键值" /> // 数据标签回显样式
</el-form-item> const listClassOptions = ref([
<el-form-item label="样式属性" prop="cssClass"> { value: "default", label: "默认" },
<el-input v-model="form.cssClass" placeholder="请输入样式属性" /> { value: "primary", label: "主要" },
</el-form-item> { value: "success", label: "成功" },
<el-form-item label="显示排序" prop="dictSort"> { value: "info", label: "信息" },
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" /> { value: "warning", label: "警告" },
</el-form-item> { value: "danger", label: "危险" }
<el-form-item label="回显样式" prop="listClass"> ])
<el-select v-model="form.listClass">
<el-option // 搜索项配置
v-for="item in listClassOptions" const searchColumns = [
:key="item.value" { label: "字典标签", prop: "dictLabel", component: "input", placeholder: "请输入字典标签", width: "200px" },
:label="item.label + '(' + item.value + ')'" { label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "数据状态", width: "200px" }
:value="item.value" ]
></el-option>
</el-select> // 表格列配置
</el-form-item> const columns = [
<el-form-item label="状态" prop="status"> { label: "字典编码", prop: "dictCode", align: "center" },
<el-radio-group v-model="form.status"> { label: "字典标签", prop: "dictLabel", align: "center" },
<el-radio { label: "字典键值", prop: "dictValue", align: "center" },
v-for="dict in sys_normal_disable" { label: "字典排序", prop: "dictSort", align: "center" },
:key="dict.value" { label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
:value="dict.value" { label: "备注", prop: "remark", align: "center" },
>{{ dict.label }}</el-radio> { label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
</el-radio-group> { label: "操作", prop: "action", align: "center", width: 160, showInToolbar: false }
</el-form-item> ]
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> // 查询函数(BasicTable 调用,返回 { rows, total }
</el-form-item> function queryList(params) {
</el-form> return listData(params)
<template #footer> }
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> const data = reactive({
<el-button @click="cancel"> </el-button> form: {},
</div> rules: {
</template> dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
</el-dialog> dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
</div> dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
</template> }
})
<script setup name="Data">
import useDictStore from '@/store/modules/dict' const { form, rules } = toRefs(data)
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type"
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data" /** 查询字典类型详细(从路由参数获取上级 dictType) */
onMounted(() => {
const { proxy } = getCurrentInstance() const dictId = route.params && route.params.dictId
const { sys_normal_disable } = useDict("sys_normal_disable") getType(dictId).then(response => {
extraParams.dictType = response.data.dictType
const dataList = ref([]) tableRef.value.reload()
const open = ref(false) })
const loading = ref(true) })
const showSearch = ref(true)
const ids = ref([]) /** 取消按钮 */
const single = ref(true) function cancel() {
const multiple = ref(true) open.value = false
const total = ref(0) reset()
const title = ref("") }
const defaultDictType = ref("")
const typeOptions = ref([]) /** 表单重置 */
const route = useRoute() function reset() {
// 数据标签回显样式 form.value = {
const listClassOptions = ref([ dictCode: undefined,
{ value: "default", label: "默认" }, dictLabel: undefined,
{ value: "primary", label: "主要" }, dictValue: undefined,
{ value: "success", label: "成功" }, cssClass: undefined,
{ value: "info", label: "信息" }, listClass: "default",
{ value: "warning", label: "警告" }, dictSort: 0,
{ value: "danger", label: "危险" } status: "0",
]) remark: undefined
}
const data = reactive({ proxy.resetForm("dataRef")
form: {}, }
queryParams: {
pageNum: 1, /** 返回按钮操作 */
pageSize: 10, function handleClose() {
dictType: undefined, const obj = { path: "/system/dict" }
dictLabel: undefined, proxy.$tab.closeOpenPage(obj)
status: undefined }
},
rules: { /** 新增按钮操作 */
dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }], function handleAdd() {
dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }], reset()
dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }] open.value = true
} title.value = "添加字典数据"
}) form.value.dictType = extraParams.dictType
}
const { queryParams, form, rules } = toRefs(data)
/** 修改按钮操作 */
/** 查询字典类型详细 */ function handleUpdate(row) {
function getTypes(dictId) { reset()
getType(dictId).then(response => { const dictCode = row.dictCode
queryParams.value.dictType = response.data.dictType getData(dictCode).then(response => {
defaultDictType.value = response.data.dictType form.value = response.data
getList() open.value = true
}) title.value = "修改字典数据"
} })
}
/** 查询字典类型列表 */
function getTypeList() { /** 提交按钮 */
getDictOptionselect().then(response => { function submitForm() {
typeOptions.value = response.data proxy.$refs["dataRef"].validate(valid => {
}) if (valid) {
} if (form.value.dictCode != undefined) {
updateData(form.value).then(() => {
/** 查询字典数据列表 */ useDictStore().removeDict(extraParams.dictType)
function getList() { proxy.$modal.msgSuccess("修改成功")
loading.value = true open.value = false
listData(queryParams.value).then(response => { tableRef.value.refresh()
dataList.value = response.rows })
total.value = response.total } else {
loading.value = false addData(form.value).then(() => {
}) useDictStore().removeDict(extraParams.dictType)
} proxy.$modal.msgSuccess("新增成功")
open.value = false
/** 取消按钮 */ tableRef.value.refresh()
function cancel() { })
open.value = false }
reset() }
} })
}
/** 表单重置 */
function reset() { /** 删除按钮操作 */
form.value = { function handleDelete(dictCodes) {
dictCode: undefined, proxy.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
dictLabel: undefined, return delData(dictCodes)
dictValue: undefined, }).then(() => {
cssClass: undefined, tableRef.value.refresh()
listClass: "default", proxy.$modal.msgSuccess("删除成功")
dictSort: 0, useDictStore().removeDict(extraParams.dictType)
status: "0", }).catch(() => {})
remark: undefined }
}
proxy.resetForm("dataRef") /** 导出按钮操作 */
} function handleExport() {
proxy.download("system/dict/data/export", {
/** 搜索按钮操作 */ ...tableRef.value.getQueryParams()
function handleQuery() { }, `dict_data_${new Date().getTime()}.xlsx`)
queryParams.value.pageNum = 1 }
getList() </script>
}
/** 返回按钮操作 */
function handleClose() {
const obj = { path: "/system/dict" }
proxy.$tab.closeOpenPage(obj)
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
queryParams.value.dictType = defaultDictType.value
handleQuery()
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加字典数据"
form.value.dictType = queryParams.value.dictType
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.dictCode)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const dictCode = row.dictCode || ids.value
getData(dictCode).then(response => {
form.value = response.data
open.value = true
title.value = "修改字典数据"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dataRef"].validate(valid => {
if (valid) {
if (form.value.dictCode != undefined) {
updateData(form.value).then(response => {
useDictStore().removeDict(queryParams.value.dictType)
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addData(form.value).then(response => {
useDictStore().removeDict(queryParams.value.dictType)
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictCodes = row.dictCode || ids.value
proxy.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
return delData(dictCodes)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
useDictStore().removeDict(queryParams.value.dictType)
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/data/export", {
...queryParams.value
}, `dict_data_${new Date().getTime()}.xlsx`)
}
getTypes(route.params && route.params.dictId)
getTypeList()
</script>
+255 -346
View File
@@ -1,346 +1,255 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <basic-table
<el-form-item label="字典名称" prop="dictName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.dictName" :search-columns="searchColumns"
placeholder="请输入字典名称" :query="queryList"
clearable row-key="dictId"
style="width: 240px" >
@keyup.enter="handleQuery" <template #toolbar="{ selection, ids }">
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="字典类型" prop="dictType"> type="primary"
<el-input plain
v-model="queryParams.dictType" icon="Plus"
placeholder="请输入字典类型" @click="handleAdd"
clearable v-hasPermi="['system:dict:add']"
style="width: 240px" >新增</el-button>
@keyup.enter="handleQuery" </el-col>
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="状态" prop="status"> type="success"
<el-select plain
v-model="queryParams.status" icon="Edit"
placeholder="字典状态" :disabled="selection.length !== 1"
clearable @click="handleUpdate(selection[0])"
style="width: 240px" v-hasPermi="['system:dict:edit']"
> >修改</el-button>
<el-option </el-col>
v-for="dict in sys_normal_disable" <el-col :span="1.5">
:key="dict.value" <el-button
:label="dict.label" type="danger"
:value="dict.value" plain
/> icon="Delete"
</el-select> :disabled="!selection.length"
</el-form-item> @click="handleDelete(ids)"
<el-form-item label="创建时间" style="width: 308px"> v-hasPermi="['system:dict:remove']"
<el-date-picker >删除</el-button>
v-model="dateRange" </el-col>
value-format="YYYY-MM-DD" <el-col :span="1.5">
type="daterange" <el-button
range-separator="-" type="warning"
start-placeholder="开始日期" plain
end-placeholder="结束日期" icon="Download"
></el-date-picker> @click="handleExport"
</el-form-item> v-hasPermi="['system:dict:export']"
<el-form-item> >导出</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> </el-col>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-col :span="1.5">
</el-form-item> <el-button
</el-form> type="danger"
plain
<el-row :gutter="10" class="mb8"> icon="Refresh"
<el-col :span="1.5"> @click="handleRefreshCache"
<el-button v-hasPermi="['system:dict:remove']"
type="primary" >刷新缓存</el-button>
plain </el-col>
icon="Plus" </template>
@click="handleAdd"
v-hasPermi="['system:dict:add']" <template #col-dictType="{ row }">
>新增</el-button> <a class="link-type" style="cursor:pointer" @click="handleViewData(row)">{{ row.dictType }}</a>
</el-col> </template>
<el-col :span="1.5">
<el-button <template #col-action="{ row }">
type="success" <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:dict:edit']">修改</el-button>
plain <el-button link type="primary" icon="Operation" @click="handleDataList(row)" v-hasPermi="['system:dict:edit']">列表</el-button>
icon="Edit" <el-button link type="primary" icon="Delete" @click="handleDelete(row.dictId)" v-hasPermi="['system:dict:remove']">删除</el-button>
:disabled="single" </template>
@click="handleUpdate" </basic-table>
v-hasPermi="['system:dict:edit']"
>修改</el-button> <!-- 添加或修改参数配置对话框 -->
</el-col> <el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-col :span="1.5"> <el-form ref="dictRef" :model="form" :rules="rules" label-width="100px">
<el-button <el-form-item label="字典名称" prop="dictName">
type="danger" <el-input v-model="form.dictName" placeholder="请输入字典名称" />
plain </el-form-item>
icon="Delete" <el-form-item prop="dictType">
:disabled="multiple" <el-input v-model="form.dictType" placeholder="请输入字典类型" />
@click="handleDelete" <template #label>
v-hasPermi="['system:dict:remove']" <span>
>删除</el-button> <el-tooltip content='数据存储中的Key值,如:sys_user_sex' placement="top">
</el-col> <el-icon><question-filled /></el-icon>
<el-col :span="1.5"> </el-tooltip>
<el-button 字典类型
type="warning" </span>
plain </template>
icon="Download" </el-form-item>
@click="handleExport" <el-form-item label="状态" prop="status">
v-hasPermi="['system:dict:export']" <el-radio-group v-model="form.status">
>导出</el-button> <el-radio
</el-col> v-for="dict in sys_normal_disable"
<el-col :span="1.5"> :key="dict.value"
<el-button :value="dict.value"
type="danger" >{{ dict.label }}</el-radio>
plain </el-radio-group>
icon="Refresh" </el-form-item>
@click="handleRefreshCache" <el-form-item label="备注" prop="remark">
v-hasPermi="['system:dict:remove']" <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
>刷新缓存</el-button> </el-form-item>
</el-col> </el-form>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <template #footer>
</el-row> <div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange"> <el-button @click="cancel"> </el-button>
<el-table-column type="selection" width="55" align="center" /> </div>
<el-table-column label="字典编号" align="center" prop="dictId" /> </template>
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true"/> </el-dialog>
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template #default="scope"> <dict-data-drawer v-model:visible="drawerVisible" :row="drawerRow" />
<a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.dictType }}</a> </div>
</template> </template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status"> <script setup name="Dict">
<template #default="scope"> import DictDataDrawer from './detail'
<dict-tag :options="sys_normal_disable" :value="scope.row.status" /> import useDictStore from '@/store/modules/dict'
</template> import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type"
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" /> const { proxy } = getCurrentInstance()
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> const { sys_normal_disable } = useDict("sys_normal_disable")
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> const tableRef = ref()
</template> const open = ref(false)
</el-table-column> const title = ref("")
<el-table-column label="操作" align="center" width="280" class-name="small-padding fixed-width"> const drawerVisible = ref(false)
<template #default="scope"> const drawerRow = ref({})
<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> const searchColumns = [
</template> { label: "字典名称", prop: "dictName", component: "input", placeholder: "请输入字典名称", width: "240px" },
</el-table-column> { label: "字典类型", prop: "dictType", component: "input", placeholder: "请输入字典类型", width: "240px" },
</el-table> { label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "字典状态", width: "240px" },
{ label: "创建时间", prop: "dateRange", component: "daterange", width: "320px" }
<pagination ]
v-show="total > 0"
:total="total" // 表格列配置
v-model:page="queryParams.pageNum" const columns = [
v-model:limit="queryParams.pageSize" { label: "字典编号", prop: "dictId", align: "center" },
@pagination="getList" { label: "字典名称", prop: "dictName", align: "center" },
/> { label: "字典类型", prop: "dictType", align: "center" },
{ label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
<!-- 添加或修改参数配置对话框 --> { label: "备注", prop: "remark", align: "center" },
<el-dialog :title="title" v-model="open" width="500px" append-to-body> { label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
<el-form ref="dictRef" :model="form" :rules="rules" label-width="100px"> { label: "操作", prop: "action", align: "center", width: 280, showInToolbar: false }
<el-form-item label="字典名称" prop="dictName"> ]
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
</el-form-item> // 查询函数(BasicTable 调用,返回 { rows, total }
<el-form-item prop="dictType"> function queryList(params) {
<el-input v-model="form.dictType" placeholder="请输入字典类型" /> const p = proxy.addDateRange({ ...params }, params.dateRange)
<template #label> delete p.dateRange
<span> return listType(p)
<el-tooltip content='数据存储中的Key值,如:sys_user_sex' placement="top"> }
<el-icon><question-filled /></el-icon>
</el-tooltip> const data = reactive({
字典类型 form: {},
</span> rules: {
</template> dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
</el-form-item> dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
<el-form-item label="状态" prop="status"> }
<el-radio-group v-model="form.status"> })
<el-radio
v-for="dict in sys_normal_disable" const { form, rules } = toRefs(data)
:key="dict.value"
:value="dict.value" /** 取消按钮 */
>{{ dict.label }}</el-radio> function cancel() {
</el-radio-group> open.value = false
</el-form-item> reset()
<el-form-item label="备注" prop="remark"> }
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item> /** 表单重置 */
</el-form> function reset() {
<template #footer> form.value = {
<div class="dialog-footer"> dictId: undefined,
<el-button type="primary" @click="submitForm"> </el-button> dictName: undefined,
<el-button @click="cancel"> </el-button> dictType: undefined,
</div> status: "0",
</template> remark: undefined
</el-dialog> }
proxy.resetForm("dictRef")
<dict-data-drawer v-model:visible="drawerVisible" :row="drawerRow" /> }
</div>
</template> /** 新增按钮操作 */
function handleAdd() {
<script setup name="Dict"> reset()
import DictDataDrawer from './detail' open.value = true
import useDictStore from '@/store/modules/dict' title.value = "添加字典类型"
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type" }
const { proxy } = getCurrentInstance() /** 字典数据抽屉 */
const { sys_normal_disable } = useDict("sys_normal_disable") function handleViewData(row) {
drawerRow.value = row
const typeList = ref([]) drawerVisible.value = true
const open = ref(false) }
const loading = ref(true)
const showSearch = ref(true) /** 字典数据列表页面 */
const ids = ref([]) function handleDataList(row) {
const single = ref(true) proxy.$tab.openPage("字典数据", '/system/dict-data/index/' + row.dictId)
const multiple = ref(true) }
const total = ref(0)
const title = ref("") /** 修改按钮操作 */
const dateRange = ref([]) function handleUpdate(row) {
const drawerVisible = ref(false) reset()
const drawerRow = ref({}) const dictId = row.dictId
getType(dictId).then(response => {
const data = reactive({ form.value = response.data
form: {}, open.value = true
queryParams: { title.value = "修改字典类型"
pageNum: 1, })
pageSize: 10, }
dictName: undefined,
dictType: undefined, /** 提交按钮 */
status: undefined function submitForm() {
}, proxy.$refs["dictRef"].validate(valid => {
rules: { if (valid) {
dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }], if (form.value.dictId != undefined) {
dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }] updateType(form.value).then(() => {
}, proxy.$modal.msgSuccess("修改成功")
}) open.value = false
tableRef.value.refresh()
const { queryParams, form, rules } = toRefs(data) })
} else {
/** 查询字典类型列表 */ addType(form.value).then(() => {
function getList() { proxy.$modal.msgSuccess("新增成功")
loading.value = true open.value = false
listType(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { tableRef.value.refresh()
typeList.value = response.rows })
total.value = response.total }
loading.value = false }
}) })
} }
/** 取消按钮 */ /** 删除按钮操作 */
function cancel() { function handleDelete(dictIds) {
open.value = false proxy.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
reset() return delType(dictIds)
} }).then(() => {
tableRef.value.refresh()
/** 表单重置 */ proxy.$modal.msgSuccess("删除成功")
function reset() { }).catch(() => {})
form.value = { }
dictId: undefined,
dictName: undefined, /** 导出按钮操作 */
dictType: undefined, function handleExport() {
status: "0", proxy.download("system/dict/type/export", {
remark: undefined ...tableRef.value.getQueryParams()
} }, `dict_${new Date().getTime()}.xlsx`)
proxy.resetForm("dictRef") }
}
/** 刷新缓存按钮操作 */
/** 搜索按钮操作 */ function handleRefreshCache() {
function handleQuery() { refreshCache().then(() => {
queryParams.value.pageNum = 1 proxy.$modal.msgSuccess("刷新成功")
getList() useDictStore().cleanDict()
} })
}
/** 重置按钮操作 */ </script>
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
handleQuery()
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加字典类型"
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.dictId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 字典数据抽屉 */
function handleViewData(row) {
drawerRow.value = row
drawerVisible.value = true
}
/** 字典数据列表页面 */
function handleDataList(row) {
proxy.$tab.openPage("字典数据", '/system/dict-data/index/' + row.dictId)
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const dictId = row.dictId || ids.value
getType(dictId).then(response => {
form.value = response.data
open.value = true
title.value = "修改字典类型"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["dictRef"].validate(valid => {
if (valid) {
if (form.value.dictId != undefined) {
updateType(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addType(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.dictId || ids.value
proxy.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
return delType(dictIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/dict/type/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`)
}
/** 刷新缓存按钮操作 */
function handleRefreshCache() {
refreshCache().then(() => {
proxy.$modal.msgSuccess("刷新成功")
useDictStore().cleanDict()
})
}
getList()
</script>
+70 -77
View File
@@ -1,47 +1,24 @@
<template> <template>
<el-dialog v-model="visible" :title="`「${noticeTitle}」已读用户`" width="760px" top="6vh" append-to-body @close="handleClose"> <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;"> <basic-table
<el-form-item prop="searchValue"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.searchValue" :search-columns="searchColumns"
placeholder="登录名称 / 用户名称" :query="queryList"
clearable :extra-params="extraParams"
:prefix-icon="Search" row-key="userId"
style="width: 220px;" size="small"
@keyup.enter="handleQuery" height="340px"
@clear="handleQuery" stripe
/> :show-toolbar="false"
</el-form-item> :selection="false"
<el-form-item> :show-index="true"
<el-button type="primary" icon="Search" size="small" @click="handleQuery">搜索</el-button> :auto-load="false"
<el-button icon="Refresh" size="small" @click="resetQuery">重置</el-button> >
</el-form-item> <template #search-extra>
<el-form-item style="float: right; margin-right: 0;"> <span class="read-stat"> <strong>{{ readTotal }}</strong> 人已读</span>
<span class="read-stat"> </template>
<strong>{{ total }}</strong> 人已读 </basic-table>
</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>
</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;"
/>
</el-dialog> </el-dialog>
</template> </template>
@@ -51,52 +28,64 @@ import { listNoticeReadUsers } from "@/api/system/notice"
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const tableRef = ref()
const visible = ref(false) const visible = ref(false)
const loading = ref(false)
const noticeTitle = ref("") const noticeTitle = ref("")
const total = ref(0) const readTotal = ref(0)
const userList = ref([])
const queryParams = reactive({ // 固定参数:公告 ID(每次请求合并,不参与搜索重置)
pageNum: 1, const extraParams = reactive({ noticeId: undefined })
pageSize: 10,
noticeId: undefined,
searchValue: undefined
})
function open(row) { // 搜索项配置
queryParams.noticeId = row.noticeId const searchColumns = [
noticeTitle.value = row.noticeTitle {
queryParams.searchValue = undefined label: "",
queryParams.pageNum = 1 prop: "searchValue",
visible.value = true component: "input",
getList() placeholder: "登录名称 / 用户名称",
} width: "220px",
formItemProps: { labelWidth: "0px" },
props: {
prefixIcon: Search,
clearable: true,
onKeyup: (e) => { if (e.key === "Enter") tableRef.value?.handleQuery() },
onClear: () => tableRef.value?.handleQuery()
}
}
]
function getList() { // 表格列配置
loading.value = true const columns = [
listNoticeReadUsers(queryParams).then(res => { { label: "登录名称", prop: "userName", align: "center" },
userList.value = res.rows { label: "用户名称", prop: "nickName", align: "center" },
total.value = res.total { label: "所属部门", prop: "deptName", align: "center" },
}).finally(() => { { label: "手机号码", prop: "phonenumber", align: "center", width: 120 },
loading.value = false { 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 handleQuery() { /** 打开弹框 */
queryParams.pageNum = 1 function open(row) {
getList() extraParams.noticeId = row.noticeId
} noticeTitle.value = row.noticeTitle
visible.value = true
function resetQuery() { nextTick(() => {
proxy.resetForm("queryRef") tableRef.value?.setQueryParams({ searchValue: undefined })
handleQuery() tableRef.value?.reload()
})
} }
/** 关闭弹框 */
function handleClose() { function handleClose() {
userList.value = [] tableRef.value?.clearSelection()
total.value = 0 tableRef.value?.setQueryParams({ searchValue: undefined })
queryParams.searchValue = undefined
} }
defineExpose({ defineExpose({
@@ -115,4 +104,8 @@ defineExpose({
font-size: 15px; font-size: 15px;
margin: 0 2px; margin: 0 2px;
} }
/* 将搜索栏操作区(搜索/重置 + 已读统计)浮动到右侧 */
:deep(.basic-form > .el-form-item:last-of-type) {
float: right;
}
</style> </style>
+225 -306
View File
@@ -1,306 +1,225 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> <basic-table
<el-form-item label="公告标题" prop="noticeTitle"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.noticeTitle" :search-columns="searchColumns"
placeholder="请输入公告标题" :query="queryList"
clearable row-key="noticeId"
style="width: 200px" >
@keyup.enter="handleQuery" <template #toolbar="{ selection, ids }">
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="操作人员" prop="createBy"> type="primary"
<el-input plain
v-model="queryParams.createBy" icon="Plus"
placeholder="请输入操作人员" @click="handleAdd"
clearable v-hasPermi="['system:notice:add']"
style="width: 200px" >新增</el-button>
@keyup.enter="handleQuery" </el-col>
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="类型" prop="noticeType"> type="success"
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px"> plain
<el-option icon="Edit"
v-for="dict in sys_notice_type" :disabled="selection.length !== 1"
:key="dict.value" @click="handleUpdate(selection[0])"
:label="dict.label" v-hasPermi="['system:notice:edit']"
:value="dict.value" >修改</el-button>
/> </el-col>
</el-select> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item> type="danger"
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> plain
<el-button icon="Refresh" @click="resetQuery">重置</el-button> icon="Delete"
</el-form-item> :disabled="!selection.length"
</el-form> @click="handleDelete(ids)"
v-hasPermi="['system:notice:remove']"
<el-row :gutter="10" class="mb8"> >删除</el-button>
<el-col :span="1.5"> </el-col>
<el-button </template>
type="primary"
plain <template #col-noticeTitle="{ row }">
icon="Plus" <a class="link-type" style="cursor:pointer" @click="handleViewData(row)">{{ row.noticeTitle }}</a>
@click="handleAdd" </template>
v-hasPermi="['system:notice:add']"
>新增</el-button> <template #col-action="{ row }">
</el-col> <el-button link type="primary" icon="User" @click="handleReadUsers(row)" v-hasPermi="['system:notice:list']">阅读用户</el-button>
<el-col :span="1.5"> <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:notice:edit']">修改</el-button>
<el-button <el-button link type="primary" icon="Delete" @click="handleDelete(row.noticeId)" v-hasPermi="['system:notice:remove']">删除</el-button>
type="success" </template>
plain </basic-table>
icon="Edit"
:disabled="single" <!-- 添加或修改公告对话框 -->
@click="handleUpdate" <el-dialog :title="title" v-model="open" width="780px" append-to-body>
v-hasPermi="['system:notice:edit']" <el-form ref="noticeRef" :model="form" :rules="rules" label-width="80px">
>修改</el-button> <el-row>
</el-col> <el-col :span="12">
<el-col :span="1.5"> <el-form-item label="公告标题" prop="noticeTitle">
<el-button <el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
type="danger" </el-form-item>
plain </el-col>
icon="Delete" <el-col :span="12">
:disabled="multiple" <el-form-item label="公告类型" prop="noticeType">
@click="handleDelete" <el-select v-model="form.noticeType" placeholder="请选择">
v-hasPermi="['system:notice:remove']" <el-option
>删除</el-button> v-for="dict in sys_notice_type"
</el-col> :key="dict.value"
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> :label="dict.label"
</el-row> :value="dict.value"
></el-option>
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange"> </el-select>
<el-table-column type="selection" width="55" align="center" /> </el-form-item>
<el-table-column label="序号" align="center" prop="noticeId" width="100" /> </el-col>
<el-table-column label="公告标题" align="center" :show-overflow-tooltip="true"> <el-col :span="24">
<template #default="scope"> <el-form-item label="状态">
<a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.noticeTitle }}</a> <el-radio-group v-model="form.status">
</template> <el-radio
</el-table-column> v-for="dict in sys_notice_status"
<el-table-column label="公告类型" align="center" prop="noticeType" width="100"> :key="dict.value"
<template #default="scope"> :value="dict.value"
<dict-tag :options="sys_notice_type" :value="scope.row.noticeType" /> >{{ dict.label }}</el-radio>
</template> </el-radio-group>
</el-table-column> </el-form-item>
<el-table-column label="状态" align="center" prop="status" width="100"> </el-col>
<template #default="scope"> <el-col :span="24">
<dict-tag :options="sys_notice_status" :value="scope.row.status" /> <el-form-item label="内容">
</template> <editor v-model="form.noticeContent" :min-height="192"/>
</el-table-column> </el-form-item>
<el-table-column label="创建者" align="center" prop="createBy" width="100" /> </el-col>
<el-table-column label="创建时间" align="center" prop="createTime" width="100"> </el-row>
<template #default="scope"> </el-form>
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span> <template #footer>
</template> <div class="dialog-footer">
</el-table-column> <el-button type="primary" @click="submitForm"> </el-button>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-button @click="cancel"> </el-button>
<template #default="scope"> </div>
<el-button link type="primary" icon="User" @click="handleReadUsers(scope.row)" v-hasPermi="['system:notice:list']">阅读用户</el-button> </template>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']">修改</el-button> </el-dialog>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']" >删除</el-button> <notice-detail-view ref="noticeViewRef" />
</template> <read-users-dialog ref="readUsersRef" />
</el-table-column> </div>
</el-table> </template>
<pagination <script setup name="Notice">
v-show="total > 0" import NoticeDetailView from "@/layout/components/HeaderNotice/DetailView"
:total="total" import ReadUsersDialog from "./ReadUsers"
v-model:page="queryParams.pageNum" import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"
v-model:limit="queryParams.pageSize"
@pagination="getList" const { proxy } = getCurrentInstance()
/> const { sys_notice_status, sys_notice_type } = useDict("sys_notice_status", "sys_notice_type")
<!-- 添加或修改公告对话框 --> const tableRef = ref()
<el-dialog :title="title" v-model="open" width="780px" append-to-body> const open = ref(false)
<el-form ref="noticeRef" :model="form" :rules="rules" label-width="80px"> const title = ref("")
<el-row>
<el-col :span="12"> // 搜索项配置
<el-form-item label="公告标题" prop="noticeTitle"> const searchColumns = [
<el-input v-model="form.noticeTitle" placeholder="请输入公告标题" /> { label: "公告标题", prop: "noticeTitle", component: "input", placeholder: "请输入公告标题", width: "200px" },
</el-form-item> { label: "操作人员", prop: "createBy", component: "input", placeholder: "请输入操作人员", width: "200px" },
</el-col> { label: "类型", prop: "noticeType", component: "select", dict: "sys_notice_type", placeholder: "公告类型", width: "200px" }
<el-col :span="12"> ]
<el-form-item label="公告类型" prop="noticeType">
<el-select v-model="form.noticeType" placeholder="请选择"> // 表格列配置
<el-option const columns = [
v-for="dict in sys_notice_type" { label: "序号", prop: "noticeId", align: "center", width: 100 },
:key="dict.value" { label: "公告标题", prop: "noticeTitle", align: "center" },
:label="dict.label" { label: "公告类型", prop: "noticeType", align: "center", width: 100, dict: "sys_notice_type" },
:value="dict.value" { label: "状态", prop: "status", align: "center", width: 100, dict: "sys_notice_status" },
></el-option> { label: "创建者", prop: "createBy", align: "center", width: 100 },
</el-select> { label: "创建时间", prop: "createTime", align: "center", width: 100, parseTime: "{y}-{m}-{d}" },
</el-form-item> { label: "操作", prop: "action", align: "center", width: 220, showInToolbar: false }
</el-col> ]
<el-col :span="24">
<el-form-item label="状态"> // 查询函数(BasicTable 调用,返回 { rows, total }
<el-radio-group v-model="form.status"> function queryList(params) {
<el-radio return listNotice(params)
v-for="dict in sys_notice_status" }
:key="dict.value"
:value="dict.value" const data = reactive({
>{{ dict.label }}</el-radio> form: {},
</el-radio-group> rules: {
</el-form-item> noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
</el-col> noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
<el-col :span="24"> }
<el-form-item label="内容"> })
<editor v-model="form.noticeContent" :min-height="192"/>
</el-form-item> const { form, rules } = toRefs(data)
</el-col>
</el-row> /** 取消按钮 */
</el-form> function cancel() {
<template #footer> open.value = false
<div class="dialog-footer"> reset()
<el-button type="primary" @click="submitForm"> </el-button> }
<el-button @click="cancel"> </el-button>
</div> /** 表单重置 */
</template> function reset() {
</el-dialog> form.value = {
<notice-detail-view ref="noticeViewRef" /> noticeId: undefined,
<read-users-dialog ref="readUsersRef" /> noticeTitle: undefined,
</div> noticeType: undefined,
</template> noticeContent: undefined,
status: "0"
<script setup name="Notice"> }
import NoticeDetailView from "@/layout/components/HeaderNotice/DetailView" proxy.resetForm("noticeRef")
import ReadUsersDialog from "./ReadUsers" }
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"
/** 新增按钮操作 */
const { proxy } = getCurrentInstance() function handleAdd() {
const { sys_notice_status, sys_notice_type } = useDict("sys_notice_status", "sys_notice_type") reset()
open.value = true
const noticeList = ref([]) title.value = "添加公告"
const open = ref(false) }
const loading = ref(true)
const showSearch = ref(true) /**修改按钮操作 */
const ids = ref([]) function handleUpdate(row) {
const single = ref(true) reset()
const multiple = ref(true) const noticeId = row.noticeId
const total = ref(0) getNotice(noticeId).then(response => {
const title = ref("") form.value = response.data
open.value = true
const data = reactive({ title.value = "修改公告"
form: {}, })
queryParams: { }
pageNum: 1,
pageSize: 10, /** 提交按钮 */
noticeTitle: undefined, function submitForm() {
createBy: undefined, proxy.$refs["noticeRef"].validate(valid => {
status: undefined if (valid) {
}, if (form.value.noticeId != undefined) {
rules: { updateNotice(form.value).then(() => {
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }], proxy.$modal.msgSuccess("修改成功")
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }] open.value = false
}, tableRef.value.refresh()
}) })
} else {
const { queryParams, form, rules } = toRefs(data) addNotice(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
/** 查询公告列表 */ open.value = false
function getList() { tableRef.value.refresh()
loading.value = true })
listNotice(queryParams.value).then(response => { }
noticeList.value = response.rows }
total.value = response.total })
loading.value = false }
})
} /** 查看公告详情 */
function handleViewData(row) {
/** 取消按钮 */ proxy.$refs["noticeViewRef"].open(row)
function cancel() { }
open.value = false
reset() /** 查看已读用户 */
} function handleReadUsers(row) {
proxy.$refs["readUsersRef"].open(row)
/** 表单重置 */ }
function reset() {
form.value = { /** 删除按钮操作 */
noticeId: undefined, function handleDelete(noticeIds) {
noticeTitle: undefined, proxy.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
noticeType: undefined, return delNotice(noticeIds)
noticeContent: undefined, }).then(() => {
status: "0" tableRef.value.refresh()
} proxy.$modal.msgSuccess("删除成功")
proxy.resetForm("noticeRef") }).catch(() => {})
} }
</script>
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.noticeId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加公告"
}
/**修改按钮操作 */
function handleUpdate(row) {
reset()
const noticeId = row.noticeId || ids.value
getNotice(noticeId).then(response => {
form.value = response.data
open.value = true
title.value = "修改公告"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["noticeRef"].validate(valid => {
if (valid) {
if (form.value.noticeId != undefined) {
updateNotice(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addNotice(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 查看公告详情 */
function handleViewData(row) {
proxy.$refs["noticeViewRef"].open(row)
}
/** 查看已读用户 */
function handleReadUsers(row) {
proxy.$refs["readUsersRef"].open(row)
}
/** 删除按钮操作 */
function handleDelete(row) {
const noticeIds = row.noticeId || ids.value
proxy.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
return delNotice(noticeIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
getList()
</script>
+210 -287
View File
@@ -1,287 +1,210 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> <basic-table
<el-form-item label="岗位编码" prop="postCode"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.postCode" :search-columns="searchColumns"
placeholder="请输入岗位编码" :query="queryList"
clearable row-key="postId"
style="width: 200px" >
@keyup.enter="handleQuery" <template #toolbar="{ selection, ids }">
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="岗位名称" prop="postName"> type="primary"
<el-input plain
v-model="queryParams.postName" icon="Plus"
placeholder="请输入岗位名称" @click="handleAdd"
clearable v-hasPermi="['system:post:add']"
style="width: 200px" >新增</el-button>
@keyup.enter="handleQuery" </el-col>
/> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item label="状态" prop="status"> type="success"
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px"> plain
<el-option icon="Edit"
v-for="dict in sys_normal_disable" :disabled="selection.length !== 1"
:key="dict.value" @click="handleUpdate(selection[0])"
:label="dict.label" v-hasPermi="['system:post:edit']"
:value="dict.value" >修改</el-button>
/> </el-col>
</el-select> <el-col :span="1.5">
</el-form-item> <el-button
<el-form-item> type="danger"
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> plain
<el-button icon="Refresh" @click="resetQuery">重置</el-button> icon="Delete"
</el-form-item> :disabled="!selection.length"
</el-form> @click="handleDelete(ids)"
v-hasPermi="['system:post:remove']"
<el-row :gutter="10" class="mb8"> >删除</el-button>
<el-col :span="1.5"> </el-col>
<el-button <el-col :span="1.5">
type="primary" <el-button
plain type="warning"
icon="Plus" plain
@click="handleAdd" icon="Download"
v-hasPermi="['system:post:add']" @click="handleExport"
>新增</el-button> v-hasPermi="['system:post:export']"
</el-col> >导出</el-button>
<el-col :span="1.5"> </el-col>
<el-button </template>
type="success"
plain <template #col-action="{ row }">
icon="Edit" <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:post:edit']">修改</el-button>
:disabled="single" <el-button link type="primary" icon="Delete" @click="handleDelete(row.postId)" v-hasPermi="['system:post:remove']">删除</el-button>
@click="handleUpdate" </template>
v-hasPermi="['system:post:edit']" </basic-table>
>修改</el-button>
</el-col> <!-- 添加或修改岗位对话框 -->
<el-col :span="1.5"> <el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-button <el-form ref="postRef" :model="form" :rules="rules" label-width="80px">
type="danger" <el-form-item label="岗位名称" prop="postName">
plain <el-input v-model="form.postName" placeholder="请输入岗位名称" />
icon="Delete" </el-form-item>
:disabled="multiple" <el-form-item label="岗位编码" prop="postCode">
@click="handleDelete" <el-input v-model="form.postCode" placeholder="请输入编码名称" />
v-hasPermi="['system:post:remove']" </el-form-item>
>删除</el-button> <el-form-item label="岗位顺序" prop="postSort">
</el-col> <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
<el-col :span="1.5"> </el-form-item>
<el-button <el-form-item label="岗位状态" prop="status">
type="warning" <el-radio-group v-model="form.status">
plain <el-radio
icon="Download" v-for="dict in sys_normal_disable"
@click="handleExport" :key="dict.value"
v-hasPermi="['system:post:export']" :value="dict.value"
>导出</el-button> >{{ dict.label }}</el-radio>
</el-col> </el-radio-group>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> </el-form-item>
</el-row> <el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange"> </el-form-item>
<el-table-column type="selection" width="55" align="center" /> </el-form>
<el-table-column label="岗位编号" align="center" prop="postId" /> <template #footer>
<el-table-column label="岗位编码" align="center" prop="postCode" /> <div class="dialog-footer">
<el-table-column label="岗位名称" align="center" prop="postName" /> <el-button type="primary" @click="submitForm"> </el-button>
<el-table-column label="岗位排序" align="center" prop="postSort" /> <el-button @click="cancel"> </el-button>
<el-table-column label="状态" align="center" prop="status"> </div>
<template #default="scope"> </template>
<dict-tag :options="sys_normal_disable" :value="scope.row.status" /> </el-dialog>
</template> </div>
</el-table-column> </template>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope"> <script setup name="Post">
<span>{{ parseTime(scope.row.createTime) }}</span> import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post"
</template>
</el-table-column> const { proxy } = getCurrentInstance()
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width"> const { sys_normal_disable } = useDict("sys_normal_disable")
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']">修改</el-button> const tableRef = ref()
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']">删除</el-button> const open = ref(false)
</template> const title = ref("")
</el-table-column>
</el-table> // 搜索项配置
const searchColumns = [
<pagination { label: "岗位编码", prop: "postCode", component: "input", placeholder: "请输入岗位编码", width: "200px" },
v-show="total > 0" { label: "岗位名称", prop: "postName", component: "input", placeholder: "请输入岗位名称", width: "200px" },
:total="total" { label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "岗位状态", width: "200px" }
v-model:page="queryParams.pageNum" ]
v-model:limit="queryParams.pageSize"
@pagination="getList" // 表格列配置
/> const columns = [
{ label: "岗位编号", prop: "postId", align: "center" },
<!-- 添加或修改岗位对话框 --> { label: "岗位编码", prop: "postCode", align: "center" },
<el-dialog :title="title" v-model="open" width="500px" append-to-body> { label: "岗位名称", prop: "postName", align: "center" },
<el-form ref="postRef" :model="form" :rules="rules" label-width="80px"> { label: "岗位排序", prop: "postSort", align: "center" },
<el-form-item label="岗位名称" prop="postName"> { label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
<el-input v-model="form.postName" placeholder="请输入岗位名称" /> { label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
</el-form-item> { label: "操作", prop: "action", align: "center", width: 180, showInToolbar: false }
<el-form-item label="岗位编码" prop="postCode"> ]
<el-input v-model="form.postCode" placeholder="请输入编码名称" />
</el-form-item> // 查询函数(BasicTable 调用,返回 { rows, total }
<el-form-item label="岗位顺序" prop="postSort"> function queryList(params) {
<el-input-number v-model="form.postSort" controls-position="right" :min="0" /> return listPost(params)
</el-form-item> }
<el-form-item label="岗位状态" prop="status">
<el-radio-group v-model="form.status"> const data = reactive({
<el-radio form: {},
v-for="dict in sys_normal_disable" rules: {
:key="dict.value" postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
:value="dict.value" postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
>{{ dict.label }}</el-radio> postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
</el-radio-group> }
</el-form-item> })
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> const { form, rules } = toRefs(data)
</el-form-item>
</el-form> /** 取消按钮 */
<template #footer> function cancel() {
<div class="dialog-footer"> open.value = false
<el-button type="primary" @click="submitForm"> </el-button> reset()
<el-button @click="cancel"> </el-button> }
</div>
</template> /** 表单重置 */
</el-dialog> function reset() {
</div> form.value = {
</template> postId: undefined,
postCode: undefined,
<script setup name="Post"> postName: undefined,
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post" postSort: 0,
status: "0",
const { proxy } = getCurrentInstance() remark: undefined
const { sys_normal_disable } = useDict("sys_normal_disable") }
proxy.resetForm("postRef")
const postList = ref([]) }
const open = ref(false)
const loading = ref(true) /** 新增按钮操作 */
const showSearch = ref(true) function handleAdd() {
const ids = ref([]) reset()
const single = ref(true) open.value = true
const multiple = ref(true) title.value = "添加岗位"
const total = ref(0) }
const title = ref("")
/** 修改按钮操作 */
const data = reactive({ function handleUpdate(row) {
form: {}, reset()
queryParams: { const postId = row.postId
pageNum: 1, getPost(postId).then(response => {
pageSize: 10, form.value = response.data
postCode: undefined, open.value = true
postName: undefined, title.value = "修改岗位"
status: undefined })
}, }
rules: {
postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }], /** 提交按钮 */
postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }], function submitForm() {
postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }], proxy.$refs["postRef"].validate(valid => {
} if (valid) {
}) if (form.value.postId != undefined) {
updatePost(form.value).then(() => {
const { queryParams, form, rules } = toRefs(data) proxy.$modal.msgSuccess("修改成功")
open.value = false
/** 查询岗位列表 */ tableRef.value.refresh()
function getList() { })
loading.value = true } else {
listPost(queryParams.value).then(response => { addPost(form.value).then(() => {
postList.value = response.rows proxy.$modal.msgSuccess("新增成功")
total.value = response.total open.value = false
loading.value = false tableRef.value.refresh()
}) })
} }
}
/** 取消按钮 */ })
function cancel() { }
open.value = false
reset() /** 删除按钮操作 */
} function handleDelete(postIds) {
proxy.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
/** 表单重置 */ return delPost(postIds)
function reset() { }).then(() => {
form.value = { tableRef.value.refresh()
postId: undefined, proxy.$modal.msgSuccess("删除成功")
postCode: undefined, }).catch(() => {})
postName: undefined, }
postSort: 0,
status: "0", /** 导出按钮操作 */
remark: undefined function handleExport() {
} proxy.download("system/post/export", {
proxy.resetForm("postRef") ...tableRef.value.getQueryParams()
} }, `post_${new Date().getTime()}.xlsx`)
}
/** 搜索按钮操作 */ </script>
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.postId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加岗位"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const postId = row.postId || ids.value
getPost(postId).then(response => {
form.value = response.data
open.value = true
title.value = "修改岗位"
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["postRef"].validate(valid => {
if (valid) {
if (form.value.postId != undefined) {
updatePost(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addPost(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const postIds = row.postId || ids.value
proxy.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
return delPost(postIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/post/export", {
...queryParams.value
}, `post_${new Date().getTime()}.xlsx`)
}
getList()
</script>
+125 -179
View File
@@ -1,179 +1,125 @@
<template>
<template> <div class="app-container">
<div class="app-container"> <basic-table
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true"> ref="tableRef"
<el-form-item label="用户名称" prop="userName"> :columns="columns"
<el-input :search-columns="searchColumns"
v-model="queryParams.userName" :query="queryList"
placeholder="请输入用户名称" :extra-params="{ roleId: route.params.roleId }"
clearable row-key="userId"
style="width: 240px" @selection-change="handleSelectionChange"
@keyup.enter="handleQuery" >
/> <template #toolbar="{ selection }">
</el-form-item> <el-col :span="1.5">
<el-form-item label="手机号码" prop="phonenumber"> <el-button
<el-input type="primary"
v-model="queryParams.phonenumber" plain
placeholder="请输入手机号码" icon="Plus"
clearable @click="openSelectUser"
style="width: 240px" v-hasPermi="['system:role:add']"
@keyup.enter="handleQuery" >添加用户</el-button>
/> </el-col>
</el-form-item> <el-col :span="1.5">
<el-form-item> <el-button
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> type="danger"
<el-button icon="Refresh" @click="resetQuery">重置</el-button> plain
</el-form-item> icon="CircleClose"
</el-form> :disabled="!selection.length"
@click="cancelAuthUserAll"
<el-row :gutter="10" class="mb8"> v-hasPermi="['system:role:remove']"
<el-col :span="1.5"> >批量取消授权</el-button>
<el-button </el-col>
type="primary" <el-col :span="1.5">
plain <el-button
icon="Plus" type="warning"
@click="openSelectUser" plain
v-hasPermi="['system:role:add']" icon="Close"
>添加用户</el-button> @click="handleClose"
</el-col> >关闭</el-button>
<el-col :span="1.5"> </el-col>
<el-button </template>
type="danger"
plain <template #col-action="{ row }">
icon="CircleClose" <el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(row)" v-hasPermi="['system:role:remove']">取消授权</el-button>
:disabled="multiple" </template>
@click="cancelAuthUserAll" </basic-table>
v-hasPermi="['system:role:remove']"
>批量取消授权</el-button> <select-user ref="selectRef" :role-id="route.params.roleId" @ok="handleSelectOk" />
</el-col> </div>
<el-col :span="1.5"> </template>
<el-button
type="warning" <script setup name="AuthUser">
plain import selectUser from "./selectUser"
icon="Close" import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role"
@click="handleClose"
>关闭</el-button> const route = useRoute()
</el-col> const { proxy } = getCurrentInstance()
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> const tableRef = ref()
const userIds = ref([])
<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" /> const searchColumns = [
<el-table-column label="用户称" prop="nickName" :show-overflow-tooltip="true" /> { label: "用户称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "200px" },
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" /> { label: "手机号码", prop: "phonenumber", component: "input", placeholder: "请输入手机号码", width: "200px" }
<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" /> const columns = [
</template> { label: "用户名称", prop: "userName", align: "center" },
</el-table-column> { label: "用户昵称", prop: "nickName", align: "center" },
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> { label: "邮箱", prop: "email", align: "center" },
<template #default="scope"> { label: "手机", prop: "phonenumber", align: "center" },
<span>{{ parseTime(scope.row.createTime) }}</span> { label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
</template> { label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true },
</el-table-column> { label: "操作", prop: "action", align: "center", width: 120, showInToolbar: false }
<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> // 查询函数(BasicTable 调用,返回 { rows, total }
</template> function queryList(params) {
</el-table-column> return allocatedUserList(params)
</el-table> }
<pagination /** 多选框选中数据 */
v-show="total > 0" function handleSelectionChange(selection) {
:total="total" userIds.value = selection.map(item => item.userId)
v-model:page="queryParams.pageNum" }
v-model:limit="queryParams.pageSize"
@pagination="getList" /** 打开授权用户表弹窗 */
/> function openSelectUser() {
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" /> proxy.$refs["selectRef"].show()
</div> }
</template>
/** 选择用户回调:刷新列表(回到第一页) */
<script setup name="AuthUser"> function handleSelectOk() {
import selectUser from "./selectUser" tableRef.value?.reload()
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role" }
const route = useRoute() /** 取消授权按钮操作 */
const { proxy } = getCurrentInstance() function cancelAuthUser(row) {
const { sys_normal_disable } = useDict("sys_normal_disable") proxy.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function () {
return authUserCancel({ userId: row.userId, roleId: route.params.roleId })
const userList = ref([]) }).then(() => {
const loading = ref(true) tableRef.value?.refresh()
const showSearch = ref(true) proxy.$modal.msgSuccess("取消授权成功")
const multiple = ref(true) }).catch(() => {})
const total = ref(0) }
const userIds = ref([])
/** 批量取消授权按钮操作 */
const queryParams = reactive({ function cancelAuthUserAll() {
pageNum: 1, const roleId = route.params.roleId
pageSize: 10, const uIds = userIds.value.join(",")
roleId: route.params.roleId, proxy.$modal.confirm("是否取消选中用户授权数据项?").then(function () {
userName: undefined, return authUserCancelAll({ roleId: roleId, userIds: uIds })
phonenumber: undefined, }).then(() => {
}) tableRef.value?.refresh()
proxy.$modal.msgSuccess("取消授权成功")
/** 查询授权用户列表 */ }).catch(() => {})
function getList() { }
loading.value = true
allocatedUserList(queryParams).then(response => { /** 关闭按钮 */
userList.value = response.rows function handleClose() {
total.value = response.total const obj = { path: "/system/role" }
loading.value = false proxy.$tab.closeOpenPage(obj)
}) }
} </script>
/** 返回按钮 */
function handleClose() {
const obj = { path: "/system/role" }
proxy.$tab.closeOpenPage(obj)
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
userIds.value = selection.map(item => item.userId)
multiple.value = !selection.length
}
/** 打开授权用户表弹窗 */
function openSelectUser() {
proxy.$refs["selectRef"].show()
}
/** 取消授权按钮操作 */
function cancelAuthUser(row) {
proxy.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function () {
return authUserCancel({ userId: row.userId, roleId: queryParams.roleId })
}).then(() => {
getList()
proxy.$modal.msgSuccess("取消授权成功")
}).catch(() => {})
}
/** 批量取消授权按钮操作 */
function cancelAuthUserAll() {
const roleId = queryParams.roleId
const uIds = userIds.value.join(",")
proxy.$modal.confirm("是否取消选中用户授权数据项?").then(function () {
return authUserCancelAll({ roleId: roleId, userIds: uIds })
}).then(() => {
getList()
proxy.$modal.msgSuccess("取消授权成功")
}).catch(() => {})
}
getList()
</script>
File diff suppressed because it is too large Load Diff
+99 -144
View File
@@ -1,144 +1,99 @@
<template> <template>
<!-- 授权用户 --> <!-- 授权用户 -->
<el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body> <el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true"> <basic-table
<el-form-item label="用户名称" prop="userName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.userName" :search-columns="searchColumns"
placeholder="请输入用户名称" :query="queryList"
clearable :extra-params="{ roleId: props.roleId }"
style="width: 180px" row-key="userId"
@keyup.enter="handleQuery" size="small"
/> height="260px"
</el-form-item> :show-toolbar="false"
<el-form-item label="手机号码" prop="phonenumber"> :auto-load="false"
<el-input @row-click="clickRow"
v-model="queryParams.phonenumber" @selection-change="handleSelectionChange"
placeholder="请输入手机号码" />
clearable <template #footer>
style="width: 180px" <div class="dialog-footer">
@keyup.enter="handleQuery" <el-button type="primary" @click="handleSelectUser"> </el-button>
/> <el-button @click="visible = false"> </el-button>
</el-form-item> </div>
<el-form-item> </template>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> </el-dialog>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> </template>
</el-form-item>
</el-form> <script setup name="SelectUser">
<el-row> import { authUserSelectAll, unallocatedUserList } from "@/api/system/role"
<el-table @row-click="clickRow" ref="refTable" :data="userList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column> const props = defineProps({
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" /> roleId: {
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" /> type: [Number, String]
<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"> const { proxy } = getCurrentInstance()
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template> const tableRef = ref()
</el-table-column> const visible = ref(false)
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> const userIds = ref([])
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> // 搜索项配置
</template> const searchColumns = [
</el-table-column> { label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "200px" },
</el-table> { label: "手机号码", prop: "phonenumber", component: "input", placeholder: "请输入手机号码", width: "200px" }
<pagination ]
v-show="total > 0"
:total="total" // 表格列配置
v-model:page="queryParams.pageNum" const columns = [
v-model:limit="queryParams.pageSize" { label: "用户名称", prop: "userName", align: "center" },
@pagination="getList" { label: "用户昵称", prop: "nickName", align: "center" },
/> { label: "邮箱", prop: "email", align: "center" },
</el-row> { label: "手机", prop: "phonenumber", align: "center" },
<template #footer> { label: "状态", prop: "status", align: "center", dict: "sys_normal_disable" },
<div class="dialog-footer"> { label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
<el-button type="primary" @click="handleSelectUser"> </el-button> ]
<el-button @click="visible = false"> </el-button>
</div> // 查询函数(BasicTable 调用,返回 { rows, total }
</template> function queryList(params) {
</el-dialog> return unallocatedUserList(params)
</template> }
<script setup name="SelectUser"> // 显示弹框
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role" function show() {
visible.value = true
const props = defineProps({ nextTick(() => {
roleId: { tableRef.value?.reload()
type: [Number, String] })
} }
})
/** 选择行 */
const { proxy } = getCurrentInstance() function clickRow(row) {
const { sys_normal_disable } = useDict("sys_normal_disable") tableRef.value?.getTableRef()?.toggleRowSelection(row)
}
const userList = ref([])
const visible = ref(false) /** 多选框选中数据 */
const total = ref(0) function handleSelectionChange(selection) {
const userIds = ref([]) userIds.value = selection.map(item => item.userId)
}
const queryParams = reactive({
pageNum: 1, const emit = defineEmits(["ok"])
pageSize: 10, /** 选择授权用户操作 */
roleId: undefined, function handleSelectUser() {
userName: undefined, const uIds = tableRef.value?.getSelection().map(u => u.userId).join(",") || ""
phonenumber: undefined if (uIds === "") {
}) proxy.$modal.msgError("请选择要分配的用户")
return
// 显示弹框 }
function show() { authUserSelectAll({ roleId: props.roleId, userIds: uIds }).then(res => {
queryParams.roleId = props.roleId proxy.$modal.msgSuccess(res.msg)
getList() visible.value = false
visible.value = true emit("ok")
} })
}
/**选择行 */
function clickRow(row) { defineExpose({
proxy.$refs["refTable"].toggleRowSelection(row) show,
} })
</script>
// 多选框选中数据
function handleSelectionChange(selection) {
userIds.value = selection.map(item => item.userId)
}
// 查询表数据
function getList() {
unallocatedUserList(queryParams).then(res => {
userList.value = res.rows
total.value = res.total
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
const emit = defineEmits(["ok"])
/** 选择授权用户操作 */
function handleSelectUser() {
const roleId = queryParams.roleId
const uIds = userIds.value.join(",")
if (uIds == "") {
proxy.$modal.msgError("请选择要分配的用户")
return
}
authUserSelectAll({ roleId: roleId, userIds: uIds }).then(res => {
proxy.$modal.msgSuccess(res.msg)
visible.value = false
emit("ok")
})
}
defineExpose({
show,
})
</script>
+151 -123
View File
@@ -1,123 +1,151 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<h4 class="form-header h4">基本信息</h4> <h4 class="form-header h4">基本信息</h4>
<el-form :model="form" label-width="80px"> <el-form :model="form" label-width="80px">
<el-row> <el-row>
<el-col :span="8" :offset="2"> <el-col :span="8" :offset="2">
<el-form-item label="用户昵称" prop="nickName"> <el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled /> <el-input v-model="form.nickName" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8" :offset="2"> <el-col :span="8" :offset="2">
<el-form-item label="登录账号" prop="userName"> <el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled /> <el-input v-model="form.userName" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<h4 class="form-header h4">角色信息</h4> <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)"> <basic-table
<el-table-column label="序号" width="55" type="index" align="center"> ref="tableRef"
<template #default="scope"> :columns="columns"
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span> :query="queryList"
</template> :extra-params="extraParams"
</el-table-column> row-key="roleId"
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column> :show-index="true"
<el-table-column label="角色编号" align="center" prop="roleId" /> :show-toolbar="false"
<el-table-column label="角色名称" align="center" prop="roleName" /> @row-click="clickRow"
<el-table-column label="权限字符" align="center" prop="roleKey" /> @selection-change="handleSelectionChange"
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> />
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> <el-form label-width="100px">
</template> <div style="text-align: center;margin-left:-120px;margin-top:30px;">
</el-table-column> <el-button type="primary" @click="submitForm()">提交</el-button>
</el-table> <el-button @click="close()">返回</el-button>
</div>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" /> </el-form>
</div>
<el-form label-width="100px"> </template>
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
<el-button type="primary" @click="submitForm()">提交</el-button> <script setup name="AuthRole">
<el-button @click="close()">返回</el-button> import { getAuthRole, updateAuthRole } from "@/api/system/user"
</div>
</el-form> const route = useRoute()
</div> const { proxy } = getCurrentInstance()
</template>
const tableRef = ref()
<script setup name="AuthRole"> const form = ref({
import { getAuthRole, updateAuthRole } from "@/api/system/user" nickName: undefined,
userName: undefined,
const route = useRoute() userId: undefined
const { proxy } = getCurrentInstance() })
const allRoles = ref([])
const loading = ref(true) const currentPageRows = ref([])
const total = ref(0) const selectedRoleIds = ref(new Set())
const pageNum = ref(1)
const pageSize = ref(10) // 固定参数:用户 ID(每次请求合并传入)
const roleIds = ref([]) const extraParams = reactive({ userId: route.params.userId })
const roles = ref([])
const form = ref({ // 表格列配置
nickName: undefined, const columns = [
userName: undefined, { label: "角色编号", prop: "roleId", align: "center" },
userId: undefined { label: "角色名称", prop: "roleName", align: "center" },
}) { label: "权限字符", prop: "roleKey", align: "center" },
{ label: "创建时间", prop: "createTime", align: "center", width: 180, parseTime: true }
/** 单击选中行数据 */ ]
function clickRow(row) {
if (checkSelectable(row)) { /**
proxy.$refs["roleRef"].toggleRowSelection(row) * 查询函数:本页数据由 getAuthRole 一次性返回(user + roles),
} * BasicTable 走服务端分页机制,这里改为缓存全部角色后按页切片(客户端分页)。
} * 跨页选择通过 selectedRoleIds 集合维护(BasicTable 内置 selection 列不支持 reserve-selection)。
*/
/** 多选框选中数据 */ function queryList(params) {
function handleSelectionChange(selection) { const pageNum = params.pageNum || 1
roleIds.value = selection.map(item => item.roleId) const pageSize = params.pageSize || 10
} if (!params.userId) {
return Promise.resolve({ rows: [], total: 0 })
/** 保存选中的数据编号 */ }
function getRowKey(row) { if (!allRoles.value.length) {
return row.roleId return getAuthRole(params.userId).then(res => {
} form.value = res.user
allRoles.value = res.roles || []
// 检查角色状态 // 初始化已选中集合:原 flag 为 true 的角色
function checkSelectable(row) { selectedRoleIds.value = new Set(
return row.status === "0" ? true : false 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)
function close() { currentPageRows.value = rows
const obj = { path: "/system/user" } nextTick(() => applySelection())
proxy.$tab.closeOpenPage(obj) return { rows, total }
} })
} else {
/** 提交按钮 */ const total = allRoles.value.length
function submitForm() { const rows = allRoles.value.slice((pageNum - 1) * pageSize, pageNum * pageSize)
const userId = form.value.userId currentPageRows.value = rows
const rIds = roleIds.value.join(",") nextTick(() => applySelection())
updateAuthRole({ userId: userId, roleIds: rIds }).then(() => { return Promise.resolve({ rows, total })
proxy.$modal.msgSuccess("授权成功") }
close() }
})
} /** 按当前页回显选中状态(仅当前页可见行可被 toggleRowSelection */
function applySelection() {
(() => { const tableEl = tableRef.value?.getTableRef()
const userId = route.params && route.params.userId currentPageRows.value.forEach(row => {
if (userId) { if (selectedRoleIds.value.has(row.roleId)) {
loading.value = true tableEl?.toggleRowSelection(row, true)
getAuthRole(userId).then(response => { }
form.value = response.user })
roles.value = response.roles }
total.value = roles.value.length
nextTick(() => { /** 角色状态可选:仅正常(status==="0")角色可勾选 */
roles.value.forEach(row => { function checkSelectable(row) {
if (row.flag) { return row.status === "0"
proxy.$refs["roleRef"].toggleRowSelection(row) }
}
}) /** 单击选中行数据 */
}) function clickRow(row) {
loading.value = false if (checkSelectable(row)) {
}) tableRef.value?.getTableRef()?.toggleRowSelection(row)
} }
})() }
</script>
/** 多选框选中数据:按当前页回填/移除,维护跨页选中集合 */
function handleSelectionChange(selection) {
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 close() {
const obj = { path: "/system/user" }
proxy.$tab.closeOpenPage(obj)
}
/** 提交按钮 */
function submitForm() {
const userId = form.value.userId
const rIds = [...selectedRoleIds.value].join(",")
updateAuthRole({ userId: userId, roleIds: rIds }).then(() => {
proxy.$modal.msgSuccess("授权成功")
close()
})
}
</script>
+388 -459
View File
@@ -1,459 +1,388 @@
<template> <template>
<div class="app-container tree-sidebar-manage-wrap"> <div class="app-container tree-sidebar-manage-wrap">
<tree-panel title="组织机构" :tree-data="deptOptions" search-placeholder="请输入部门名称" storage-key="dept-sidebar-width" :defaultExpandAll="true" @node-click="handleNodeClick" @refresh="getDeptTree" ref="deptTreeRef" /> <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="tree-sidebar-content">
<div class="content-inner"> <div class="content-inner">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <basic-table
<el-form-item label="用户名称" prop="userName"> ref="tableRef"
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" /> :columns="columns"
</el-form-item> :search-columns="searchColumns"
<el-form-item label="手机号码" prop="phonenumber"> :query="queryList"
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" /> :extra-params="extraParams"
</el-form-item> row-key="userId"
<el-form-item label="状态" prop="status"> :search-label-width="'68px'"
<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" /> <template #toolbar="{ selection, ids }">
</el-select> <el-col :span="1.5">
</el-form-item> <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
<el-form-item label="创建时间" style="width: 308px"> </el-col>
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker> <el-col :span="1.5">
</el-form-item> <el-button type="success" plain icon="Edit" :disabled="selection.length !== 1" @click="handleUpdate(selection[0])" v-hasPermi="['system:user:edit']">修改</el-button>
<el-form-item> </el-col>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-col :span="1.5">
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button type="danger" plain icon="Delete" :disabled="!selection.length" @click="handleDelete(ids)" v-hasPermi="['system:user:remove']">删除</el-button>
</el-form-item> </el-col>
</el-form> <el-col :span="1.5">
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
<el-row :gutter="10" class="mb8"> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button> <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
</el-col> </el-col>
<el-col :span="1.5"> </template>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
</el-col> <template #col-userName="{ row }">
<el-col :span="1.5"> <a class="link-type" style="cursor:pointer" @click="handleViewData(row)">{{ row.userName }}</a>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button> </template>
</el-col>
<el-col :span="1.5"> <template #col-status="{ row }">
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button> <el-switch
</el-col> v-model="row.status"
<el-col :span="1.5"> active-value="0"
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button> inactive-value="1"
</el-col> @change="handleStatusChange(row)"
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" storageKey="xxxxxxxx"></right-toolbar> ></el-switch>
</el-row> </template>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> <template #col-action="{ row }">
<el-table-column type="selection" width="50" align="center" /> <el-tooltip content="修改" placement="top" v-if="row.userId !== 1">
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" /> <el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['system:user:edit']"></el-button>
<el-table-column label="用户名称" align="center" key="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true"> </el-tooltip>
<template #default="scope"> <el-tooltip content="删除" placement="top" v-if="row.userId !== 1">
<a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.userName }}</a> <el-button link type="primary" icon="Delete" @click="handleDelete(row.userId)" v-hasPermi="['system:user:remove']"></el-button>
</template> </el-tooltip>
</el-table-column> <el-tooltip content="重置密码" placement="top" v-if="row.userId !== 1">
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" /> <el-button link type="primary" icon="Key" @click="handleResetPwd(row)" v-hasPermi="['system:user:resetPwd']"></el-button>
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" /> </el-tooltip>
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" /> <el-tooltip content="分配角色" placement="top" v-if="row.userId !== 1">
<el-table-column label="状态" align="center" key="status" v-if="columns.status.visible"> <el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(row)" v-hasPermi="['system:user:edit']"></el-button>
<template #default="scope"> </el-tooltip>
<el-switch </template>
v-model="scope.row.status" </basic-table>
active-value="0" </div>
inactive-value="1" </div>
@change="handleStatusChange(scope.row)"
></el-switch> <!-- 添加或修改用户配置对话框 -->
</template> <el-dialog :title="title" v-model="open" width="600px" append-to-body>
</el-table-column> <el-form :model="form" :rules="rules" ref="userRef" label-width="80px">
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns.createTime.visible" width="160"> <el-row>
<template #default="scope"> <el-col :span="12">
<span>{{ parseTime(scope.row.createTime) }}</span> <el-form-item label="用户昵称" prop="nickName">
</template> <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
</el-table-column> </el-form-item>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width"> </el-col>
<template #default="scope"> <el-col :span="12">
<el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1"> <el-form-item label="归属部门" prop="deptId">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button> <el-tree-select v-model="form.deptId" :data="enabledDeptOptions" :props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="请选择归属部门" clearable check-strictly />
</el-tooltip> </el-form-item>
<el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1"> </el-col>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button> </el-row>
</el-tooltip> <el-row>
<el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1"> <el-col :span="12">
<el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button> <el-form-item label="手机号码" prop="phonenumber">
</el-tooltip> <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
<el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1"> </el-form-item>
<el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button> </el-col>
</el-tooltip> <el-col :span="12">
</template> <el-form-item label="邮箱" prop="email">
</el-table-column> <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
</el-table> </el-form-item>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> </el-col>
</div> </el-row>
</div> <el-row>
<el-col :span="12">
<!-- 添加或修改用户配置对话框 --> <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-dialog :title="title" v-model="open" width="600px" append-to-body> <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
<el-form :model="form" :rules="rules" ref="userRef" label-width="80px"> </el-form-item>
<el-row> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="用户昵称" prop="nickName"> <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password" :rules="pwdValidator">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" /> <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> </el-row>
<el-form-item label="归属部门" prop="deptId"> <el-row>
<el-tree-select v-model="form.deptId" :data="enabledDeptOptions" :props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="请选择归属部门" clearable check-strictly /> <el-col :span="12">
</el-form-item> <el-form-item label="用户性别">
</el-col> <el-select v-model="form.sex" placeholder="请选择">
</el-row> <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
<el-row> </el-select>
<el-col :span="12"> </el-form-item>
<el-form-item label="手机号码" prop="phonenumber"> </el-col>
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" /> <el-col :span="12">
</el-form-item> <el-form-item label="状态">
</el-col> <el-radio-group v-model="form.status">
<el-col :span="12"> <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
<el-form-item label="邮箱" prop="email"> </el-radio-group>
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" /> </el-form-item>
</el-form-item> </el-col>
</el-col> </el-row>
</el-row> <el-row>
<el-row> <el-col :span="12">
<el-col :span="12"> <el-form-item label="岗位">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName"> <el-select v-model="form.postIds" multiple placeholder="请选择">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" /> <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1"></el-option>
</el-form-item> </el-select>
</el-col> </el-form-item>
<el-col :span="12"> </el-col>
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password" :rules="pwdValidator"> <el-col :span="12">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password /> <el-form-item label="角色">
</el-form-item> <el-select v-model="form.roleIds" multiple placeholder="请选择">
</el-col> <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
</el-row> </el-select>
<el-row> </el-form-item>
<el-col :span="12"> </el-col>
<el-form-item label="用户性别"> </el-row>
<el-select v-model="form.sex" placeholder="请选择"> <el-row>
<el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> <el-col :span="24">
</el-select> <el-form-item label="备注">
</el-form-item> <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
</el-col> </el-form-item>
<el-col :span="12"> </el-col>
<el-form-item label="状态"> </el-row>
<el-radio-group v-model="form.status"> </el-form>
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> <template #footer>
</el-radio-group> <div class="dialog-footer">
</el-form-item> <el-button type="primary" @click="submitForm"> </el-button>
</el-col> <el-button @click="cancel"> </el-button>
</el-row> </div>
<el-row> </template>
<el-col :span="12"> </el-dialog>
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择"> <!-- 用户详情抽屉 -->
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1"></el-option> <user-view-drawer ref="userViewRef" />
</el-select> <!-- 用户导入对话框 -->
</el-form-item> <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()" />
</el-col> </div>
<el-col :span="12"> </template>
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择"> <script setup name="User">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option> import TreePanel from "@/components/TreePanel"
</el-select> import ExcelImportDialog from "@/components/ExcelImportDialog"
</el-form-item> import UserViewDrawer from "./view"
</el-col> import { usePasswordRule } from "@/utils/passwordRule"
</el-row> import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
<el-row>
<el-col :span="24"> const router = useRouter()
<el-form-item label="备注"> const { proxy } = getCurrentInstance()
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> const { pwdValidator, pwdPromptValidator } = usePasswordRule()
</el-form-item> const { sys_normal_disable, sys_user_sex } = useDict("sys_normal_disable", "sys_user_sex")
</el-col>
</el-row> const tableRef = ref()
</el-form> const open = ref(false)
<template #footer> const title = ref("")
<div class="dialog-footer"> const deptId = ref(undefined)
<el-button type="primary" @click="submitForm"> </el-button> const deptOptions = ref(undefined)
<el-button @click="cancel"> </el-button> const enabledDeptOptions = ref(undefined)
</div> const initPassword = ref(undefined)
</template> const postOptions = ref([])
</el-dialog> const roleOptions = ref([])
<!-- 用户详情抽屉 --> // 部门联动参数(不参与搜索重置,由树点击控制)
<user-view-drawer ref="userViewRef" /> const extraParams = computed(() => ({ deptId: deptId.value }))
<!-- 用户导入对话框 -->
<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" /> // 搜索项配置
</div> const searchColumns = [
</template> { label: "用户名称", prop: "userName", component: "input", placeholder: "请输入用户名称", width: "240px" },
{ label: "手机号码", prop: "phonenumber", component: "input", placeholder: "请输入手机号码", width: "240px" },
<script setup name="User"> { label: "状态", prop: "status", component: "select", dict: "sys_normal_disable", placeholder: "用户状态", width: "240px" },
import TreePanel from "@/components/TreePanel" { label: "创建时间", prop: "dateRange", component: "daterange", width: "308px" }
import ExcelImportDialog from "@/components/ExcelImportDialog" ]
import UserViewDrawer from "./view"
import { usePasswordRule } from "@/utils/passwordRule" // 表格列配置
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user" const columns = [
{ label: "用户编号", prop: "userId" },
const router = useRouter() { label: "用户名称", prop: "userName", showOverflowTooltip: true },
const { proxy } = getCurrentInstance() { label: "用户昵称", prop: "nickName", showOverflowTooltip: true },
const { pwdValidator, pwdPromptValidator } = usePasswordRule() { label: "部门", prop: "deptName", showOverflowTooltip: true, formatter: (row) => row.dept ? row.dept.deptName : "" },
const { sys_normal_disable, sys_user_sex } = useDict("sys_normal_disable", "sys_user_sex") { label: "手机号码", prop: "phonenumber", width: 120 },
{ label: "状态", prop: "status" },
const userList = ref([]) { label: "创建时间", prop: "createTime", width: 160, parseTime: true },
const open = ref(false) { label: "操作", prop: "action", width: 150, showInToolbar: false }
const loading = ref(true) ]
const showSearch = ref(true)
const ids = ref([]) // 查询函数
const single = ref(true) function queryList(params) {
const multiple = ref(true) const p = proxy.addDateRange({ ...params }, params.dateRange)
const total = ref(0) delete p.dateRange
const title = ref("") return listUser(p)
const dateRange = ref([]) }
const deptOptions = ref(undefined)
const enabledDeptOptions = ref(undefined) const data = reactive({
const initPassword = ref(undefined) form: {},
const postOptions = ref([]) rules: {
const roleOptions = ref([]) userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
// 列显隐信息 nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
const columns = ref({ email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
userId: { label: '用户编号', visible: true }, phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
userName: { label: '用户名称', visible: true }, }
nickName: { label: '用户昵称', visible: true }, })
deptName: { label: '部门', visible: true },
phonenumber: { label: '手机号码', visible: true }, const { form, rules } = toRefs(data)
status: { label: '状态', visible: true },
createTime: { label: '创建时间', visible: true } /** 查询部门下拉树结构 */
}) function getDeptTree() {
deptTreeSelect().then(response => {
const data = reactive({ deptOptions.value = response.data
form: {}, enabledDeptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
queryParams: { })
pageNum: 1, }
pageSize: 10,
userName: undefined, /** 过滤禁用的部门 */
phonenumber: undefined, function filterDisabledDept(deptList) {
status: undefined, return deptList.filter(dept => {
deptId: undefined if (dept.disabled) {
}, return false
rules: { }
userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }], if (dept.children && dept.children.length) {
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }], dept.children = filterDisabledDept(dept.children)
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }], }
phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }] return true
} })
}) }
const { queryParams, form, rules } = toRefs(data) /** 节点单击事件 */
function handleNodeClick(data) {
/** 查询用户列表 */ deptId.value = data.id
function getList() { tableRef.value.reload()
loading.value = true }
listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(res => {
loading.value = false /** 删除按钮操作 */
userList.value = res.rows function handleDelete(userIds) {
total.value = res.total proxy.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
}) return delUser(userIds)
} }).then(() => {
tableRef.value.refresh()
/** 查询部门下拉树结构 */ proxy.$modal.msgSuccess("删除成功")
function getDeptTree() { }).catch(() => {})
deptTreeSelect().then(response => { }
deptOptions.value = response.data
enabledDeptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data))) /** 导出按钮操作 */
}) function handleExport() {
} proxy.download("system/user/export", {
...tableRef.value.getQueryParams()
/** 过滤禁用的部门 */ }, `user_${new Date().getTime()}.xlsx`)
function filterDisabledDept(deptList) { }
return deptList.filter(dept => {
if (dept.disabled) { /** 用户状态修改 */
return false function handleStatusChange(row) {
} let text = row.status === "0" ? "启用" : "停用"
if (dept.children && dept.children.length) { proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
dept.children = filterDisabledDept(dept.children) return changeUserStatus(row.userId, row.status)
} }).then(() => {
return true proxy.$modal.msgSuccess(text + "成功")
}) }).catch(function () {
} row.status = row.status === "0" ? "1" : "0"
})
/** 节点单击事件 */ }
function handleNodeClick(data) {
queryParams.value.deptId = data.id /** 跳转角色分配 */
handleQuery() function handleAuthRole(row) {
} const userId = row.userId
router.push("/system/user-auth/role/" + userId)
/** 搜索按钮操作 */ }
function handleQuery() {
queryParams.value.pageNum = 1 /** 重置密码按钮操作 */
getList() function handleResetPwd(row) {
} proxy.$prompt(`请输入「${row.userName}」的新密码`, "重置密码", {
confirmButtonText: "确定",
/** 重置按钮操作 */ cancelButtonText: "取消",
function resetQuery() { closeOnClickModal: false,
dateRange.value = [] inputValidator: pwdPromptValidator
proxy.resetForm("queryRef") }).then(({ value }) => {
queryParams.value.deptId = undefined resetUserPwd(row.userId, value).then(() => {
proxy.$refs.deptTreeRef.setCurrentKey(null) proxy.$modal.msgSuccess("修改成功,新密码是:" + value)
handleQuery() })
} }).catch(() => {})
}
/** 删除按钮操作 */
function handleDelete(row) { /** 详情按钮操作 */
const userIds = row.userId || ids.value function handleViewData(row) {
proxy.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () { proxy.$refs["userViewRef"].open(row.userId)
return delUser(userIds) }
}).then(() => {
getList() /** 导入按钮操作 */
proxy.$modal.msgSuccess("删除成功") function handleImport() {
}).catch(() => {}) proxy.$refs["importUserRef"].open()
} }
/** 导出按钮操作 */ /** 重置操作表单 */
function handleExport() { function reset() {
proxy.download("system/user/export", { form.value = {
...queryParams.value, userId: undefined,
},`user_${new Date().getTime()}.xlsx`) deptId: undefined,
} userName: undefined,
nickName: undefined,
/** 用户状态修改 */ password: undefined,
function handleStatusChange(row) { phonenumber: undefined,
let text = row.status === "0" ? "启用" : "停用" email: undefined,
proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () { sex: undefined,
return changeUserStatus(row.userId, row.status) status: "0",
}).then(() => { remark: undefined,
proxy.$modal.msgSuccess(text + "成功") postIds: [],
}).catch(function () { roleIds: []
row.status = row.status === "0" ? "1" : "0" }
}) proxy.resetForm("userRef")
} }
/** 更多操作 */ /** 取消按钮 */
function handleCommand(command, row) { function cancel() {
switch (command) { open.value = false
case "handleResetPwd": reset()
handleResetPwd(row) }
break
case "handleAuthRole": /** 新增按钮操作 */
handleAuthRole(row) function handleAdd() {
break reset()
default: getUser().then(response => {
break postOptions.value = response.posts
} roleOptions.value = response.roles
} open.value = true
title.value = "添加用户"
/** 跳转角色分配 */ form.value.password = initPassword.value
function handleAuthRole(row) { })
const userId = row.userId }
router.push("/system/user-auth/role/" + userId)
} /** 修改按钮操作 */
function handleUpdate(row) {
/** 重置密码按钮操作 */ reset()
function handleResetPwd(row) { const userId = row.userId
proxy.$prompt(`请输入「${row.userName}」的新密码`, "重置密码", { getUser(userId).then(response => {
confirmButtonText: "确定", form.value = response.data
cancelButtonText: "取消", postOptions.value = response.posts
closeOnClickModal: false, roleOptions.value = response.roles
inputValidator: pwdPromptValidator form.value.postIds = response.postIds
}).then(({ value }) => { form.value.roleIds = response.roleIds
resetUserPwd(row.userId, value).then(() => { open.value = true
proxy.$modal.msgSuccess("修改成功,新密码是:" + value) title.value = "修改用户"
}) form.value.password = ""
}).catch(() => {}) })
} }
/** 选择条数 */ /** 提交按钮 */
function handleSelectionChange(selection) { function submitForm() {
ids.value = selection.map(item => item.userId) proxy.$refs["userRef"].validate(valid => {
single.value = selection.length != 1 if (valid) {
multiple.value = !selection.length if (form.value.userId != undefined) {
} updateUser(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
/** 详情按钮操作 */ open.value = false
function handleViewData(row) { tableRef.value.refresh()
proxy.$refs["userViewRef"].open(row.userId) })
} } else {
addUser(form.value).then(() => {
/** 导入按钮操作 */ proxy.$modal.msgSuccess("新增成功")
function handleImport() { open.value = false
proxy.$refs["importUserRef"].open() tableRef.value.refresh()
} })
}
/** 重置操作表单 */ }
function reset() { })
form.value = { }
userId: undefined,
deptId: undefined, onMounted(() => {
userName: undefined, getDeptTree()
nickName: undefined, proxy.getConfigKey("sys.user.initPassword").then(response => {
password: undefined, initPassword.value = response.msg
phonenumber: undefined, })
email: undefined, })
sex: undefined, </script>
status: "0",
remark: undefined,
postIds: [],
roleIds: []
}
proxy.resetForm("userRef")
}
/** 取消按钮 */
function cancel() {
open.value = false
reset()
}
/** 新增按钮操作 */
function handleAdd() {
reset()
getUser().then(response => {
postOptions.value = response.posts
roleOptions.value = response.roles
open.value = true
title.value = "添加用户"
form.value.password = initPassword.value
})
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const userId = row.userId || ids.value
getUser(userId).then(response => {
form.value = response.data
postOptions.value = response.posts
roleOptions.value = response.roles
form.value.postIds = response.postIds
form.value.roleIds = response.roleIds
open.value = true
title.value = "修改用户"
form.value.password = ""
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["userRef"].validate(valid => {
if (valid) {
if (form.value.userId != undefined) {
updateUser(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addUser(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
onMounted(() => {
getDeptTree()
getList()
proxy.getConfigKey("sys.user.initPassword").then(response => {
initPassword.value = response.msg
})
})
</script>
+92 -126
View File
@@ -1,126 +1,92 @@
<template> <template>
<!-- 导入表 --> <!-- 导入表 -->
<el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body> <el-dialog title="导入表" v-model="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true"> <basic-table
<el-form-item label="表名称" prop="tableName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.tableName" :search-columns="searchColumns"
placeholder="请输入表名称" :query="queryList"
clearable row-key="tableName"
style="width: 180px" size="small"
@keyup.enter="handleQuery" height="260px"
/> :show-toolbar="false"
</el-form-item> :auto-load="false"
<el-form-item label="表描述" prop="tableComment"> @row-click="clickRow"
<el-input @selection-change="handleSelectionChange"
v-model="queryParams.tableComment" />
placeholder="请输入表描述" <template #footer>
clearable <div class="dialog-footer">
style="width: 180px" <el-button type="primary" @click="handleImportTable"> </el-button>
@keyup.enter="handleQuery" <el-button @click="visible = false"> </el-button>
/> </div>
</el-form-item> </template>
<el-form-item> </el-dialog>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> </template>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> <script setup>
</el-form> import { listDbTable, importTable } from "@/api/tool/gen"
<el-row>
<el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px"> const tableRef = ref()
<el-table-column type="selection" width="55"></el-table-column> const visible = ref(false)
<el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column> const tables = ref([])
<el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column> const { proxy } = getCurrentInstance()
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="updateTime" label="更新时间"></el-table-column> // 搜索项配置
</el-table> const searchColumns = [
<pagination { label: "表名称", prop: "tableName", component: "input", placeholder: "请输入表名称", width: "200px" },
v-show="total>0" { label: "表描述", prop: "tableComment", component: "input", placeholder: "请输入表描述", width: "200px" }
:total="total" ]
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" // 表格列配置
@pagination="getList" const columns = [
/> { label: "表名称", prop: "tableName", align: "center" },
</el-row> { label: "表描述", prop: "tableComment", align: "center" },
<template #footer> { label: "创建时间", prop: "createTime", align: "center" },
<div class="dialog-footer"> { label: "更新时间", prop: "updateTime", align: "center" }
<el-button type="primary" @click="handleImportTable"> </el-button> ]
<el-button @click="visible = false"> </el-button>
</div> // 查询函数(BasicTable 调用,返回 { rows, total }
</template> function queryList(params) {
</el-dialog> return listDbTable(params)
</template> }
<script setup> const emit = defineEmits(["ok"])
import { listDbTable, importTable } from "@/api/tool/gen"
/** 显示弹框 */
const total = ref(0) function show() {
const visible = ref(false) visible.value = true
const tables = ref([]) nextTick(() => {
const dbTableList = ref([]) tableRef.value?.reload()
const { proxy } = getCurrentInstance() })
}
const queryParams = reactive({
pageNum: 1, /** 单击选择行 */
pageSize: 10, function clickRow(row) {
tableName: undefined, tableRef.value?.getTableRef()?.toggleRowSelection(row)
tableComment: undefined }
})
/** 多选框选中数据 */
const emit = defineEmits(["ok"]) function handleSelectionChange(selection) {
tables.value = selection.map(item => item.tableName)
/** 查询参数列表 */ }
function show() {
getList() /** 导入按钮操作 */
visible.value = true function handleImportTable() {
} const tableNames = tableRef.value?.getSelection().map(t => t.tableName).join(",") || ""
if (tableNames === "") {
/** 单击选择行 */ proxy.$modal.msgError("请选择要导入的表")
function clickRow(row) { return
proxy.$refs.table.toggleRowSelection(row) }
} importTable({ tables: tableNames, tplWebType: 'element-plus' }).then(res => {
proxy.$modal.msgSuccess(res.msg)
/** 多选框选中数据 */ if (res.code === 200) {
function handleSelectionChange(selection) { visible.value = false
tables.value = selection.map(item => item.tableName) emit("ok")
} }
})
/** 查询表数据 */ }
function getList() {
listDbTable(queryParams).then(res => { defineExpose({
dbTableList.value = res.rows show,
total.value = res.total })
}) </script>
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/** 导入按钮操作 */
function handleImportTable() {
const tableNames = tables.value.join(",")
if (tableNames == "") {
proxy.$modal.msgError("请选择要导入的表")
return
}
importTable({ tables: tableNames, tplWebType: 'element-plus' }).then(res => {
proxy.$modal.msgSuccess(res.msg)
if (res.code === 200) {
visible.value = false
emit("ok")
}
})
}
defineExpose({
show,
})
</script>
+249 -309
View File
@@ -1,309 +1,249 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> <basic-table
<el-form-item label="表名称" prop="tableName"> ref="tableRef"
<el-input :columns="columns"
v-model="queryParams.tableName" :search-columns="searchColumns"
placeholder="请输入表名称" :query="queryList"
clearable row-key="tableId"
style="width: 200px" show-index
@keyup.enter="handleQuery" :default-sort="defaultSort"
/> :default-params="defaultParams"
</el-form-item> @sort-change="handleSortChange"
<el-form-item label="表描述" prop="tableComment"> @selection-change="handleSelectionChange"
<el-input >
v-model="queryParams.tableComment" <template #toolbar="{ selection, ids }">
placeholder="请输入表描述" <el-col :span="1.5">
clearable <el-button
style="width: 200px" type="primary"
@keyup.enter="handleQuery" plain
/> icon="Download"
</el-form-item> :disabled="!selection.length"
<el-form-item label="创建时间" style="width: 308px"> @click="handleGenTable()"
<el-date-picker v-hasPermi="['tool:gen:code']"
v-model="dateRange" >生成</el-button>
value-format="YYYY-MM-DD" </el-col>
type="daterange" <el-col :span="1.5">
range-separator="-" <el-button
start-placeholder="开始日期" type="primary"
end-placeholder="结束日期" plain
></el-date-picker> icon="Plus"
</el-form-item> @click="openCreateTable"
<el-form-item> v-hasRole="['admin']"
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> >创建</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> </el-col>
</el-form-item> <el-col :span="1.5">
</el-form> <el-button
type="info"
<el-row :gutter="10" class="mb8"> plain
<el-col :span="1.5"> icon="Upload"
<el-button @click="openImportTable"
type="primary" v-hasPermi="['tool:gen:import']"
plain >导入</el-button>
icon="Download" </el-col>
:disabled="multiple" <el-col :span="1.5">
@click="handleGenTable" <el-button
v-hasPermi="['tool:gen:code']" type="success"
>生成</el-button> plain
</el-col> icon="Edit"
<el-col :span="1.5"> :disabled="selection.length !== 1"
<el-button @click="handleEditTable(selection[0])"
type="primary" v-hasPermi="['tool:gen:edit']"
plain >修改</el-button>
icon="Plus" </el-col>
@click="openCreateTable" <el-col :span="1.5">
v-hasRole="['admin']" <el-button
>创建</el-button> type="danger"
</el-col> plain
<el-col :span="1.5"> icon="Delete"
<el-button :disabled="!selection.length"
type="info" @click="handleDelete(ids)"
plain v-hasPermi="['tool:gen:remove']"
icon="Upload" >删除</el-button>
@click="openImportTable" </el-col>
v-hasPermi="['tool:gen:import']" </template>
>导入</el-button>
</el-col> <template #col-action="{ row }">
<el-col :span="1.5"> <el-tooltip content="预览" placement="top">
<el-button <el-button link type="primary" icon="View" @click="handlePreview(row)" v-hasPermi="['tool:gen:preview']"></el-button>
type="success" </el-tooltip>
plain <el-tooltip content="编辑" placement="top">
icon="Edit" <el-button link type="primary" icon="Edit" @click="handleEditTable(row)" v-hasPermi="['tool:gen:edit']"></el-button>
:disabled="single" </el-tooltip>
@click="handleEditTable" <el-tooltip content="删除" placement="top">
v-hasPermi="['tool:gen:edit']" <el-button link type="primary" icon="Delete" @click="handleDelete(row.tableId)" v-hasPermi="['tool:gen:remove']"></el-button>
>修改</el-button> </el-tooltip>
</el-col> <el-tooltip content="同步" placement="top">
<el-col :span="1.5"> <el-button link type="primary" icon="Refresh" @click="handleSynchDb(row)" v-hasPermi="['tool:gen:edit']"></el-button>
<el-button </el-tooltip>
type="danger" <el-tooltip content="生成代码" placement="top">
plain <el-button link type="primary" icon="Download" @click="handleGenTable(row)" v-hasPermi="['tool:gen:code']"></el-button>
icon="Delete" </el-tooltip>
:disabled="multiple" </template>
@click="handleDelete" </basic-table>
v-hasPermi="['tool:gen:remove']"
>删除</el-button> <!-- 预览界面 -->
</el-col> <el-dialog :title="preview.title" v-model="preview.open" width="80%" top="5vh" append-to-body class="scrollbar">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <el-tabs v-model="preview.activeName">
</el-row> <el-tab-pane
v-for="(value, key) in preview.data"
<el-table ref="genRef" v-loading="loading" :data="tableList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange"> :label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
<el-table-column type="selection" align="center" width="55"></el-table-column> :name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
<el-table-column label="序号" type="index" width="50" align="center"> :key="value"
<template #default="scope"> >
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span> <el-link underline="never" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">&nbsp;复制</el-link>
</template> <pre>{{ value }}</pre>
</el-table-column> </el-tab-pane>
<el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" /> </el-tabs>
<el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" /> </el-dialog>
<el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" /> <import-table ref="importRef" @ok="handleQuery" />
<el-table-column label="创建时间" align="center" prop="createTime" width="160" sortable="custom" :sort-orders="['descending', 'ascending']" /> <create-table ref="createRef" @ok="handleQuery" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" sortable="custom" :sort-orders="['descending', 'ascending']" /> </div>
<el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width"> </template>
<template #default="scope">
<el-tooltip content="预览" placement="top"> <script setup name="Gen">
<el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button> import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen"
</el-tooltip> import importTable from "./importTable"
<el-tooltip content="编辑" placement="top"> import createTable from "./createTable"
<el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
</el-tooltip> const route = useRoute()
<el-tooltip content="删除" placement="top"> const { proxy } = getCurrentInstance()
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
</el-tooltip> const tableRef = ref()
<el-tooltip content="同步" placement="top"> const importRef = ref()
<el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button> const createRef = ref()
</el-tooltip> const uniqueId = ref("")
<el-tooltip content="生成代码" placement="top"> const selectedTableNames = ref([])
<el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
</el-tooltip> // 默认排序
</template> const defaultSort = { prop: "createTime", order: "descending" }
</el-table-column> const defaultParams = {
</el-table> orderByColumn: "createTime",
<pagination isAsc: "descending"
v-show="total>0" }
:total="total"
v-model:page="queryParams.pageNum" const preview = reactive({
v-model:limit="queryParams.pageSize" open: false,
@pagination="getList" title: "代码预览",
/> data: {},
<!-- 预览界面 --> activeName: "domain.java"
<el-dialog :title="preview.title" v-model="preview.open" width="80%" top="5vh" append-to-body class="scrollbar"> })
<el-tabs v-model="preview.activeName">
<el-tab-pane // 搜索项配置
v-for="(value, key) in preview.data" const searchColumns = [
:label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))" { label: "表名称", prop: "tableName", component: "input", placeholder: "请输入表名称", width: "200px" },
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))" { label: "表描述", prop: "tableComment", component: "input", placeholder: "请输入表描述", width: "200px" },
:key="value" { label: "创建时间", prop: "dateRange", component: "daterange", width: "308px" }
> ]
<el-link underline="never" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">&nbsp;复制</el-link>
<pre>{{ value }}</pre> // 表格列配置
</el-tab-pane> const columns = [
</el-tabs> { label: "表名称", prop: "tableName", align: "center" },
</el-dialog> { label: "表描述", prop: "tableComment", align: "center" },
<import-table ref="importRef" @ok="handleQuery" /> { label: "实体", prop: "className", align: "center" },
<create-table ref="createRef" @ok="handleQuery" /> { label: "创建时间", prop: "createTime", align: "center", width: 160, sortable: "custom" },
</div> { label: "更新时间", prop: "updateTime", align: "center", width: 160, sortable: "custom" },
</template> { label: "操作", prop: "action", align: "center", width: 330, showInToolbar: false }
]
<script setup name="Gen">
import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen" // 查询函数
import router from "@/router" function queryList(params) {
import importTable from "./importTable" const p = proxy.addDateRange({ ...params }, params.dateRange)
import createTable from "./createTable" delete p.dateRange
return listTable(p)
const route = useRoute() }
const { proxy } = getCurrentInstance()
/** 搜索按钮操作(供子组件 @ok 回调) */
const tableList = ref([]) function handleQuery() {
const loading = ref(true) tableRef.value.reload()
const showSearch = ref(true) }
const ids = ref([])
const single = ref(true) /** 排序触发事件 */
const multiple = ref(true) function handleSortChange(column) {
const total = ref(0) tableRef.value.setQueryParams({ orderByColumn: column.prop, isAsc: column.order })
const tableNames = ref([]) tableRef.value.reload()
const dateRange = ref([]) }
const uniqueId = ref("")
const defaultSort = ref({ prop: "createTime", order: "descending" }) /** 多选框选中数据 */
function handleSelectionChange(selection) {
const data = reactive({ selectedTableNames.value = selection.map(item => item.tableName)
queryParams: { }
pageNum: 1,
pageSize: 10, // keep-alive 页面重新激活时,从路由参数恢复分页并重置搜索
tableName: undefined, onActivated(() => {
tableComment: undefined, const time = route.query.t
orderByColumn: defaultSort.value.prop, if (time != null && time != uniqueId.value) {
isAsc: defaultSort.value.order uniqueId.value = time
}, tableRef.value.getSearchFormRef()?.resetFields()
preview: { tableRef.value.setQueryParams({ pageNum: Number(route.query.pageNum) || 1 })
open: false, tableRef.value.refresh()
title: "代码预览", }
data: {}, })
activeName: "domain.java"
} /** 生成代码操作 */
}) function handleGenTable(row) {
const tbNames = row?.tableName || selectedTableNames.value
const { queryParams, preview } = toRefs(data) if (!tbNames || (Array.isArray(tbNames) && tbNames.length === 0)) {
proxy.$modal.msgError("请选择要生成的数据")
onActivated(() => { return
const time = route.query.t }
if (time != null && time != uniqueId.value) { if (row?.genType === "1") {
uniqueId.value = time genCode(row.tableName).then(response => {
queryParams.value.pageNum = Number(route.query.pageNum) proxy.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath)
dateRange.value = [] })
proxy.resetForm("queryForm") } else {
getList() const zipName = Array.isArray(tbNames) ? "ruoyi.zip" : tbNames + ".zip"
} proxy.$download.zip("/tool/gen/batchGenCode?tables=" + tbNames, zipName)
}) }
}
/** 查询表集合 */
function getList() { /** 同步数据库操作 */
loading.value = true function handleSynchDb(row) {
listTable(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { const tableName = row.tableName
tableList.value = response.rows proxy.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function () {
total.value = response.total return synchDb(tableName)
loading.value = false }).then(() => {
}) proxy.$modal.msgSuccess("同步成功")
} }).catch(() => {})
}
/** 搜索按钮操作 */
function handleQuery() { /** 打开导入表弹窗 */
queryParams.value.pageNum = 1 function openImportTable() {
getList() importRef.value.show()
} }
/** 生成代码操作 */ /** 打开创建表弹窗 */
function handleGenTable(row) { function openCreateTable() {
const tbNames = row.tableName || tableNames.value createRef.value.show()
if (tbNames == "") { }
proxy.$modal.msgError("请选择要生成的数据")
return /** 预览按钮 */
} function handlePreview(row) {
if (row.genType === "1") { previewTable(row.tableId).then(response => {
genCode(row.tableName).then(response => { preview.data = response.data
proxy.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath) preview.open = true
}) preview.activeName = "domain.java"
} else { })
const zipName = Array.isArray(tbNames) ? "ruoyi.zip" : tbNames + ".zip" }
proxy.$download.zip("/tool/gen/batchGenCode?tables=" + tbNames, zipName)
} /** 复制代码成功 */
} function copyTextSuccess() {
proxy.$modal.msgSuccess("复制成功")
/** 同步数据库操作 */ }
function handleSynchDb(row) {
const tableName = row.tableName /** 修改按钮操作 */
proxy.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function () { function handleEditTable(row) {
return synchDb(tableName) const params = { pageNum: tableRef.value.getQueryParams().pageNum }
}).then(() => { proxy.$tab.openPage("修改[" + row.tableName + "]生成配置", '/tool/gen-edit/index/' + row.tableId, params)
proxy.$modal.msgSuccess("同步成功") }
}).catch(() => {})
} /** 删除按钮操作 */
function handleDelete(tableIds) {
/** 打开导入表弹窗 */ proxy.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?').then(function () {
function openImportTable() { return delTable(tableIds)
proxy.$refs["importRef"].show() }).then(() => {
} tableRef.value.refresh()
proxy.$modal.msgSuccess("删除成功")
/** 打开创建表弹窗 */ }).catch(() => {})
function openCreateTable() { }
proxy.$refs["createRef"].show() </script>
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm("queryRef")
queryParams.value.pageNum = 1
proxy.$refs["genRef"].sort(defaultSort.value.prop, defaultSort.value.order)
}
/** 预览按钮 */
function handlePreview(row) {
previewTable(row.tableId).then(response => {
preview.value.data = response.data
preview.value.open = true
preview.value.activeName = "domain.java"
})
}
/** 复制代码成功 */
function copyTextSuccess() {
proxy.$modal.msgSuccess("复制成功")
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.tableId)
tableNames.value = selection.map(item => item.tableName)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 排序触发事件 */
function 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)
}
/** 删除按钮操作 */
function handleDelete(row) {
const tableIds = row.tableId || ids.value
proxy.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?').then(function () {
return delTable(tableIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
getList()
</script>