BUG和多余的文件
This commit is contained in:
parent
2489cf00d7
commit
28507236a7
@ -83,6 +83,7 @@ const queryParams = reactive({
|
||||
})
|
||||
const [registerTable] = useXTable({
|
||||
allSchemas: allSchemas,
|
||||
topActionSlots: false,
|
||||
getListApi: DefinitionApi.getProcessDefinitionPageApi,
|
||||
params: queryParams
|
||||
})
|
||||
|
@ -515,12 +515,15 @@ const handleChangeState = (row) => {
|
||||
|
||||
// 发布流程
|
||||
const handleDeploy = (row) => {
|
||||
message.confirm('是否部署该流程!!').then(async () => {
|
||||
await ModelApi.deployModelApi(row.id)
|
||||
message.success(t('部署成功'))
|
||||
// 刷新列表
|
||||
reload()
|
||||
})
|
||||
message
|
||||
.confirm('是否部署该流程!!')
|
||||
.then(async () => {
|
||||
await ModelApi.deployModelApi(row.id)
|
||||
message.success(t('部署成功'))
|
||||
// 刷新列表
|
||||
reload()
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// ========== 导入流程 ==========
|
||||
|
@ -175,6 +175,7 @@ const queryParams = reactive({
|
||||
})
|
||||
const [registerTable, { reload }] = useXTable({
|
||||
allSchemas: allSchemas,
|
||||
topActionSlots: false,
|
||||
params: queryParams,
|
||||
getListApi: TaskAssignRuleApi.getTaskAssignRuleList,
|
||||
isList: true
|
||||
|
@ -1,65 +0,0 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情" width="800">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="日志主键" min-width="120">
|
||||
{{ detailData.id }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="链路追踪">
|
||||
{{ detailData.traceId }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="应用名">
|
||||
{{ detailData.applicationName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户信息">
|
||||
{{ detailData.userId }}
|
||||
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="detailData.userType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户 IP">
|
||||
{{ detailData.userIp }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户 UA">
|
||||
{{ detailData.userAgent }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="请求信息">
|
||||
{{ detailData.requestMethod }} {{ detailData.requestUrl }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="请求参数">
|
||||
{{ detailData.requestParams }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="请求时间">
|
||||
{{ formatDate(detailData.beginTime) }} ~ {{ formatDate(detailData.endTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="请求耗时">{{ detailData.duration }} ms</el-descriptions-item>
|
||||
<el-descriptions-item label="操作结果">
|
||||
<div v-if="detailData.resultCode === 0">正常</div>
|
||||
<div v-else-if="detailData.resultCode > 0"
|
||||
>失败 | {{ detailData.resultCode }} | {{ detailData.resultMsg }}
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="ApiAccessLogDetail" setup>
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import * as ApiAccessLog from '@/api/infra/apiAccessLog'
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const detailLoading = ref(false) // 表单地加载中
|
||||
const detailData = ref() // 详情数据
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (data: ApiAccessLog.ApiAccessLogVO) => {
|
||||
dialogVisible.value = true
|
||||
// 设置数据
|
||||
detailLoading.value = true
|
||||
try {
|
||||
detailData.value = data
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
</script>
|
@ -1,79 +0,0 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情" width="800">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="日志主键" min-width="120">
|
||||
{{ detailData.id }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="链路追踪">
|
||||
{{ detailData.traceId }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="应用名">
|
||||
{{ detailData.applicationName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户编号">
|
||||
{{ detailData.userId }}
|
||||
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="detailData.userType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户 IP">
|
||||
{{ detailData.userIp }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户 UA">
|
||||
{{ detailData.userAgent }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="请求信息">
|
||||
{{ detailData.requestMethod }} {{ detailData.requestUrl }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="请求参数">
|
||||
{{ detailData.requestParams }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="异常时间">
|
||||
{{ formatDate(detailData.exceptionTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="异常名">
|
||||
{{ detailData.exceptionName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.exceptionStackTrace" label="异常堆栈">
|
||||
<el-input
|
||||
v-model="detailData.exceptionStackTrace"
|
||||
:autosize="{ maxRows: 20 }"
|
||||
:readonly="true"
|
||||
type="textarea"
|
||||
/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理状态">
|
||||
<dict-tag
|
||||
:type="DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS"
|
||||
:value="detailData.processStatus"
|
||||
/>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.processUserId" label="处理人">
|
||||
{{ detailData.processUserId }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.processTime" label="处理时间">
|
||||
{{ formatDate(detailData.processTime) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script lang="ts" name="ApiErrorLogDetail" setup>
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import * as ApiErrorLog from '@/api/infra/apiErrorLog'
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const detailLoading = ref(false) // 表单的加载中
|
||||
const detailData = ref() // 详情数据
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (data: ApiErrorLog.ApiErrorLogVO) => {
|
||||
dialogVisible.value = true
|
||||
// 设置数据
|
||||
detailLoading.value = true
|
||||
try {
|
||||
detailData.value = data
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
</script>
|
@ -1,149 +0,0 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" title="导入表" width="800px">
|
||||
<!-- 搜索栏 -->
|
||||
<el-form ref="queryFormRef" :inline="true" :model="queryParams" label-width="68px">
|
||||
<el-form-item label="数据源" prop="dataSourceConfigId">
|
||||
<el-select
|
||||
v-model="queryParams.dataSourceConfigId"
|
||||
class="!w-240px"
|
||||
placeholder="请选择数据源"
|
||||
>
|
||||
<el-option
|
||||
v-for="config in dataSourceConfigList"
|
||||
:key="config.id"
|
||||
:label="config.name"
|
||||
:value="config.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="表名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
class="!w-240px"
|
||||
clearable
|
||||
placeholder="请输入表名称"
|
||||
@keyup.enter="getList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="表描述" prop="comment">
|
||||
<el-input
|
||||
v-model="queryParams.comment"
|
||||
class="!w-240px"
|
||||
clearable
|
||||
placeholder="请输入表描述"
|
||||
@keyup.enter="getList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getList">
|
||||
<Icon class="mr-5px" icon="ep:search" />
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">
|
||||
<Icon class="mr-5px" icon="ep:refresh" />
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 列表 -->
|
||||
<el-row>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-loading="dbTableLoading"
|
||||
:data="dbTableList"
|
||||
height="260px"
|
||||
@row-click="handleRowClick"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column :show-overflow-tooltip="true" label="表名称" prop="name" />
|
||||
<el-table-column :show-overflow-tooltip="true" label="表描述" prop="comment" />
|
||||
</el-table>
|
||||
</el-row>
|
||||
<!-- 操作 -->
|
||||
<template #footer>
|
||||
<el-button :disabled="tableList.length === 0" type="primary" @click="handleImportTable">
|
||||
导入
|
||||
</el-button>
|
||||
<el-button @click="close">关闭</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script lang="ts" name="InfraCodegenImportTable" setup>
|
||||
import * as CodegenApi from '@/api/infra/codegen'
|
||||
import * as DataSourceConfigApi from '@/api/infra/dataSourceConfig'
|
||||
import { ElTable } from 'element-plus'
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dbTableLoading = ref(true) // 数据源的加载中
|
||||
const dbTableList = ref<CodegenApi.DatabaseTableVO[]>([]) // 表的列表
|
||||
const queryParams = reactive({
|
||||
name: undefined,
|
||||
comment: undefined,
|
||||
dataSourceConfigId: 0
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const dataSourceConfigList = ref<DataSourceConfigApi.DataSourceConfigVO[]>([]) // 数据源列表
|
||||
|
||||
/** 查询表数据 */
|
||||
const getList = async () => {
|
||||
dbTableLoading.value = true
|
||||
try {
|
||||
dbTableList.value = await CodegenApi.getSchemaTableList(queryParams)
|
||||
} finally {
|
||||
dbTableLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置操作 */
|
||||
const resetQuery = async () => {
|
||||
queryParams.name = undefined
|
||||
queryParams.comment = undefined
|
||||
queryParams.dataSourceConfigId = dataSourceConfigList.value[0].id as number
|
||||
await getList()
|
||||
}
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async () => {
|
||||
// 加载数据源的列表
|
||||
dataSourceConfigList.value = await DataSourceConfigApi.getDataSourceConfigList()
|
||||
queryParams.dataSourceConfigId = dataSourceConfigList.value[0].id as number
|
||||
dialogVisible.value = true
|
||||
// 加载表的列表
|
||||
await getList()
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 关闭弹窗 */
|
||||
const close = () => {
|
||||
dialogVisible.value = false
|
||||
tableList.value = []
|
||||
}
|
||||
|
||||
const tableRef = ref<typeof ElTable>() // 表格的 Ref
|
||||
const tableList = ref<string[]>([]) // 选中的表名
|
||||
|
||||
/** 处理某一行的点击 */
|
||||
const handleRowClick = (row) => {
|
||||
unref(tableRef)?.toggleRowSelection(row)
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection) => {
|
||||
tableList.value = selection.map((item) => item.name)
|
||||
}
|
||||
|
||||
/** 导入按钮操作 */
|
||||
const handleImportTable = async () => {
|
||||
await CodegenApi.createCodegenList({
|
||||
dataSourceConfigId: queryParams.dataSourceConfigId,
|
||||
tableNames: tableList.value
|
||||
})
|
||||
message.success('导入成功')
|
||||
emit('success')
|
||||
close()
|
||||
}
|
||||
const emit = defineEmits(['success'])
|
||||
</script>
|
@ -1,219 +0,0 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-model="dialogVisible"
|
||||
align-center
|
||||
class="app-infra-codegen-preview-container"
|
||||
title="代码预览"
|
||||
width="80%"
|
||||
>
|
||||
<div class="flex">
|
||||
<!-- 代码目录树 -->
|
||||
<el-card
|
||||
v-loading="loading"
|
||||
:gutter="12"
|
||||
class="w-1/3"
|
||||
element-loading-text="生成文件目录中..."
|
||||
shadow="hover"
|
||||
>
|
||||
<el-scrollbar height="calc(100vh - 88px - 40px)">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
:data="preview.fileTree"
|
||||
:expand-on-click-node="false"
|
||||
default-expand-all
|
||||
highlight-current
|
||||
node-key="id"
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
<!-- 代码 -->
|
||||
<el-card
|
||||
v-loading="loading"
|
||||
:gutter="12"
|
||||
class="w-2/3 ml-3"
|
||||
element-loading-text="加载代码中..."
|
||||
shadow="hover"
|
||||
>
|
||||
<el-tabs v-model="preview.activeName">
|
||||
<el-tab-pane
|
||||
v-for="item in previewCodegen"
|
||||
:key="item.filePath"
|
||||
:label="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)"
|
||||
:name="item.filePath"
|
||||
>
|
||||
<el-button class="float-right" text type="primary" @click="copy(item.code)">
|
||||
{{ t('common.copy') }}
|
||||
</el-button>
|
||||
<div>
|
||||
<pre><code class="hljs" v-html="highlightedCode(item)"></code></pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script lang="ts" name="InfraCodegenPreviewCode" setup>
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { handleTree2 } from '@/utils/tree'
|
||||
import * as CodegenApi from '@/api/infra/codegen'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const loading = ref(false) // 加载中的状态
|
||||
const preview = reactive({
|
||||
fileTree: [], // 文件树
|
||||
activeName: '' // 激活的文件名
|
||||
})
|
||||
const previewCodegen = ref<CodegenApi.CodegenPreviewVO[]>()
|
||||
|
||||
/** 点击文件 */
|
||||
const handleNodeClick = async (data, node) => {
|
||||
if (node && !node.isLeaf) {
|
||||
return false
|
||||
}
|
||||
preview.activeName = data.id
|
||||
}
|
||||
|
||||
/** 生成 files 目录 **/
|
||||
interface filesType {
|
||||
id: string
|
||||
label: string
|
||||
parentId: string
|
||||
}
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (id: number) => {
|
||||
dialogVisible.value = true
|
||||
try {
|
||||
loading.value = true
|
||||
// 生成代码
|
||||
const data = await CodegenApi.previewCodegen(id)
|
||||
previewCodegen.value = data
|
||||
// 处理文件
|
||||
let file = handleFiles(data)
|
||||
preview.fileTree = handleTree2(file, 'id', 'parentId', 'children', '/')
|
||||
// 点击首个文件
|
||||
preview.activeName = data[0].filePath
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 处理文件 */
|
||||
const handleFiles = (datas: CodegenApi.CodegenPreviewVO[]) => {
|
||||
let exists = {} // key:file 的 id;value:true
|
||||
let files: filesType[] = []
|
||||
// 遍历每个元素
|
||||
for (const data of datas) {
|
||||
let paths = data.filePath.split('/')
|
||||
let fullPath = '' // 从头开始的路径,用于生成 id
|
||||
// 特殊处理 java 文件
|
||||
if (paths[paths.length - 1].indexOf('.java') >= 0) {
|
||||
let newPaths: string[] = []
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
let path = paths[i]
|
||||
if (path !== 'java') {
|
||||
newPaths.push(path)
|
||||
continue
|
||||
}
|
||||
newPaths.push(path)
|
||||
// 特殊处理中间的 package,进行合并
|
||||
let tmp = ''
|
||||
while (i < paths.length) {
|
||||
path = paths[i + 1]
|
||||
if (
|
||||
path === 'controller' ||
|
||||
path === 'convert' ||
|
||||
path === 'dal' ||
|
||||
path === 'enums' ||
|
||||
path === 'service' ||
|
||||
path === 'vo' || // 下面三个,主要是兜底。可能考虑到有人改了包结构
|
||||
path === 'mysql' ||
|
||||
path === 'dataobject'
|
||||
) {
|
||||
break
|
||||
}
|
||||
tmp = tmp ? tmp + '.' + path : path
|
||||
i++
|
||||
}
|
||||
if (tmp) {
|
||||
newPaths.push(tmp)
|
||||
}
|
||||
}
|
||||
paths = newPaths
|
||||
}
|
||||
// 遍历每个 path, 拼接成树
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
// 已经添加到 files 中,则跳过
|
||||
let oldFullPath = fullPath
|
||||
// 下面的 replaceAll 的原因,是因为上面包处理了,导致和 tabs 不匹配,所以 replaceAll 下
|
||||
fullPath = fullPath.length === 0 ? paths[i] : fullPath.replaceAll('.', '/') + '/' + paths[i]
|
||||
if (exists[fullPath]) {
|
||||
continue
|
||||
}
|
||||
// 添加到 files 中
|
||||
exists[fullPath] = true
|
||||
files.push({
|
||||
id: fullPath,
|
||||
label: paths[i],
|
||||
parentId: oldFullPath || '/' // "/" 为根节点
|
||||
})
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
/** 复制 **/
|
||||
const copy = async (text: string) => {
|
||||
const { copy, copied, isSupported } = useClipboard({ source: text })
|
||||
if (!isSupported) {
|
||||
message.error(t('common.copyError'))
|
||||
return
|
||||
}
|
||||
await copy()
|
||||
if (unref(copied)) {
|
||||
message.success(t('common.copySuccess'))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码高亮
|
||||
*/
|
||||
import hljs from 'highlight.js' // 导入代码高亮文件
|
||||
import 'highlight.js/styles/github.css' // 导入代码高亮样式
|
||||
import java from 'highlight.js/lib/languages/java'
|
||||
import xml from 'highlight.js/lib/languages/java'
|
||||
import javascript from 'highlight.js/lib/languages/javascript'
|
||||
import sql from 'highlight.js/lib/languages/sql'
|
||||
import typescript from 'highlight.js/lib/languages/typescript'
|
||||
const highlightedCode = (item) => {
|
||||
const language = item.filePath.substring(item.filePath.lastIndexOf('.') + 1)
|
||||
const result = hljs.highlight(language, item.code || '', true)
|
||||
return result.value || ' '
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(async () => {
|
||||
// 注册代码高亮的各种语言
|
||||
hljs.registerLanguage('java', java)
|
||||
hljs.registerLanguage('xml', xml)
|
||||
hljs.registerLanguage('html', xml)
|
||||
hljs.registerLanguage('vue', xml)
|
||||
hljs.registerLanguage('javascript', javascript)
|
||||
hljs.registerLanguage('sql', sql)
|
||||
hljs.registerLanguage('typescript', typescript)
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.app-infra-codegen-preview-container {
|
||||
.el-scrollbar .el-scrollbar__wrap .el-scrollbar__view {
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,129 +0,0 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="80px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="参数分类" prop="category">
|
||||
<el-input v-model="formData.category" placeholder="请输入参数分类" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参数名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入参数名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参数键名" prop="key">
|
||||
<el-input v-model="formData.key" placeholder="请输入参数键名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参数键值" prop="value">
|
||||
<el-input v-model="formData.value" placeholder="请输入参数键值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否可见" prop="visible">
|
||||
<el-radio-group v-model="formData.visible">
|
||||
<el-radio
|
||||
v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
|
||||
:key="dict.value"
|
||||
:label="dict.value"
|
||||
>
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getBoolDictOptions } from '@/utils/dict'
|
||||
import * as ConfigApi from '@/api/infra/config'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref({
|
||||
id: undefined,
|
||||
category: '',
|
||||
name: '',
|
||||
key: '',
|
||||
value: '',
|
||||
visible: true,
|
||||
remark: ''
|
||||
})
|
||||
const formRules = reactive({
|
||||
category: [{ required: true, message: '参数分类不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }],
|
||||
key: [{ required: true, message: '参数键名不能为空', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '参数键值不能为空', trigger: 'blur' }],
|
||||
visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const openModal = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = await ConfigApi.getConfig(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
if (!formRef) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as ConfigApi.ConfigVO
|
||||
if (formType.value === 'create') {
|
||||
await ConfigApi.createConfig(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await ConfigApi.updateConfig(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
category: '',
|
||||
name: '',
|
||||
key: '',
|
||||
value: '',
|
||||
visible: true,
|
||||
remark: ''
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="100px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="数据源名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入参数名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数据源连接" prop="url">
|
||||
<el-input v-model="formData.url" placeholder="请输入数据源连接" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="formData.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="formData.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import * as DataSourceConfigApi from '@/api/infra/dataSourceConfig'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref<DataSourceConfigApi.DataSourceConfigVO>({
|
||||
id: undefined,
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
const formRules = reactive({
|
||||
name: [{ required: true, message: '数据源名称不能为空', trigger: 'blur' }],
|
||||
url: [{ required: true, message: '数据源连接不能为空', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '密码不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const openModal = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = await DataSourceConfigApi.getDataSourceConfig(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
if (!formRef) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as DataSourceConfigApi.DataSourceConfigVO
|
||||
if (formType.value === 'create') {
|
||||
await DataSourceConfigApi.createDataSourceConfig(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await DataSourceConfigApi.updateDataSourceConfig(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: ''
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:limit="1"
|
||||
accept=".jpg, .png, .gif"
|
||||
:auto-upload="false"
|
||||
drag
|
||||
:headers="headers"
|
||||
:action="url"
|
||||
:data="data"
|
||||
:disabled="formLoading"
|
||||
:on-change="handleFileChange"
|
||||
:on-progress="handleFileUploadProgress"
|
||||
:on-success="handleFileSuccess"
|
||||
>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em> </div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip" style="color: red">
|
||||
提示:仅允许导入 jpg、png、gif 格式文件!
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<el-button @click="submitFileForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Dialog } from '@/components/Dialog'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const url = import.meta.env.VITE_UPLOAD_URL
|
||||
const headers = { Authorization: 'Bearer ' + getAccessToken() }
|
||||
const data = ref({ path: '' })
|
||||
const uploadRef = ref()
|
||||
|
||||
/** 打开弹窗 */
|
||||
const openModal = async () => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.fileUpload')
|
||||
}
|
||||
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
/** 处理上传的文件发生变化 */
|
||||
const handleFileChange = (file) => {
|
||||
data.value.path = file.name
|
||||
}
|
||||
|
||||
/** 处理文件上传中 */
|
||||
const handleFileUploadProgress = () => {
|
||||
formLoading.value = true // 禁止修改
|
||||
}
|
||||
|
||||
/** 发起文件上传 */
|
||||
const submitFileForm = () => {
|
||||
unref(uploadRef)?.submit()
|
||||
}
|
||||
|
||||
/** 文件上传成功处理 */
|
||||
const handleFileSuccess = () => {
|
||||
// 清理
|
||||
dialogVisible.value = false
|
||||
formLoading.value = false
|
||||
unref(uploadRef)?.clearFiles()
|
||||
// 提示成功,并刷新
|
||||
message.success(t('common.createSuccess'))
|
||||
emit('success')
|
||||
}
|
||||
</script>
|
@ -1,154 +1,190 @@
|
||||
<template>
|
||||
<!-- 搜索 -->
|
||||
<content-wrap>
|
||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
|
||||
<el-form-item label="文件路径" prop="path">
|
||||
<el-input
|
||||
v-model="queryParams.path"
|
||||
placeholder="请输入文件路径"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
<ContentWrap>
|
||||
<!-- 列表 -->
|
||||
<XTable @register="registerTable">
|
||||
<template #toolbar_buttons>
|
||||
<XButton type="primary" preIcon="ep:upload" title="上传文件" @click="uploadDialog" />
|
||||
</template>
|
||||
<template #actionbtns_default="{ row }">
|
||||
<XTextButton
|
||||
preIcon="ep:copy-document"
|
||||
:title="t('common.copy')"
|
||||
@click="handleCopy(row.url)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="文件类型" prop="type" width="80">
|
||||
<el-input
|
||||
v-model="queryParams.type"
|
||||
placeholder="请输入文件类型"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
<XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" />
|
||||
<XTextButton
|
||||
preIcon="ep:delete"
|
||||
:title="t('action.del')"
|
||||
v-hasPermi="['infra:file:delete']"
|
||||
@click="deleteData(row.id)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker
|
||||
v-model="queryParams.createTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||
</template>
|
||||
</XTable>
|
||||
</ContentWrap>
|
||||
<XModal v-model="dialogVisible" :title="dialogTitle">
|
||||
<!-- 对话框(详情) -->
|
||||
<Descriptions :schema="allSchemas.detailSchema" :data="detailData">
|
||||
<template #url="{ row }">
|
||||
<el-image
|
||||
v-if="row.type === 'jpg' || 'png' || 'gif'"
|
||||
style="width: 100px; height: 100px"
|
||||
:src="row.url"
|
||||
:key="row.url"
|
||||
lazy
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button type="primary" @click="openModal">
|
||||
<Icon icon="ep:upload" class="mr-5px" /> 上传文件
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</content-wrap>
|
||||
|
||||
<!-- 列表 -->
|
||||
<content-wrap>
|
||||
<el-table v-loading="loading" :data="list" align="center">
|
||||
<el-table-column label="文件名" align="center" prop="name" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="文件路径" align="center" prop="path" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="URL" align="center" prop="url" :show-overflow-tooltip="true" />
|
||||
<el-table-column
|
||||
label="文件大小"
|
||||
align="center"
|
||||
prop="size"
|
||||
width="120"
|
||||
:formatter="fileSizeFormatter"
|
||||
<span>{{ row.url }}</span>
|
||||
</template>
|
||||
</Descriptions>
|
||||
<!-- 操作按钮 -->
|
||||
<template #footer>
|
||||
<XButton :title="t('dialog.close')" @click="dialogVisible = false" />
|
||||
</template>
|
||||
</XModal>
|
||||
<XModal v-model="uploadDialogVisible" :title="uploadDialogTitle">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:action="updateUrl + '?updateSupport=' + updateSupport"
|
||||
:headers="uploadHeaders"
|
||||
:drag="true"
|
||||
:limit="1"
|
||||
:multiple="true"
|
||||
:show-file-list="true"
|
||||
:disabled="uploadDisabled"
|
||||
:before-upload="beforeUpload"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handleFileSuccess"
|
||||
:on-error="excelUploadError"
|
||||
:before-remove="beforeRemove"
|
||||
:on-change="handleFileChange"
|
||||
:auto-upload="false"
|
||||
accept=".jpg, .png, .gif"
|
||||
>
|
||||
<Icon icon="ep:upload-filled" />
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">请上传 .jpg, .png, .gif 标准格式文件</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<!-- 按钮:保存 -->
|
||||
<XButton
|
||||
type="primary"
|
||||
preIcon="ep:upload-filled"
|
||||
:title="t('action.save')"
|
||||
@click="submitFileForm()"
|
||||
/>
|
||||
<el-table-column label="文件类型" align="center" prop="type" width="180px" />
|
||||
<el-table-column
|
||||
label="上传时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
width="180"
|
||||
:formatter="dateFormatter"
|
||||
/>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['infra:config:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</content-wrap>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<file-upload-form ref="modalRef" @success="getList" />
|
||||
<!-- 按钮:关闭 -->
|
||||
<XButton :title="t('dialog.close')" @click="uploadDialogVisible = false" />
|
||||
</template>
|
||||
</XModal>
|
||||
</template>
|
||||
<script setup lang="ts" name="Config">
|
||||
import { fileSizeFormatter } from '@/utils'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import * as FileApi from '@/api/infra/file'
|
||||
import FileUploadForm from './form.vue'
|
||||
const message = useMessage() // 消息弹窗
|
||||
<script setup lang="ts" name="FileList">
|
||||
import type { UploadInstance, UploadRawFile, UploadProps, UploadFile } from 'element-plus'
|
||||
// 业务相关的 import
|
||||
import { allSchemas } from './fileList.data'
|
||||
import * as FileApi from '@/api/infra/fileList'
|
||||
import { getAccessToken, getTenantId } from '@/utils/auth'
|
||||
// import { useClipboard } from '@vueuse/core'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const total = ref(0) // 列表的总页数
|
||||
const list = ref([]) // 列表的数据
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: undefined,
|
||||
type: undefined,
|
||||
createTime: []
|
||||
// 列表相关的变量
|
||||
const [registerTable, { reload, deleteData }] = useXTable({
|
||||
allSchemas: allSchemas,
|
||||
getListApi: FileApi.getFilePageApi,
|
||||
deleteApi: FileApi.deleteFileApi
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await FileApi.getFilePage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
const detailData = ref() // 详情 Ref
|
||||
const dialogVisible = ref(false) // 是否显示弹出层
|
||||
const dialogTitle = ref('') // 弹出层标题
|
||||
const uploadDialogVisible = ref(false)
|
||||
const uploadDialogTitle = ref('上传')
|
||||
const updateSupport = ref(0)
|
||||
const uploadDisabled = ref(false)
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
let updateUrl = import.meta.env.VITE_UPLOAD_URL
|
||||
const uploadHeaders = ref()
|
||||
// 文件上传之前判断
|
||||
const beforeUpload = (file: UploadRawFile) => {
|
||||
const isImg = file.type === 'image/jpeg' || 'image/gif' || 'image/png'
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isImg) message.error('上传文件只能是 jpeg / gif / png 格式!')
|
||||
if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
|
||||
return isImg && isLt5M
|
||||
}
|
||||
// 处理上传的文件发生变化
|
||||
const handleFileChange = (uploadFile: UploadFile): void => {
|
||||
// uploadRef.value.data.path = uploadFile.name
|
||||
console.log(uploadFile, 'uploadFile')
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// 文件上传
|
||||
const submitFileForm = () => {
|
||||
uploadHeaders.value = {
|
||||
Authorization: 'Bearer ' + getAccessToken(),
|
||||
'tenant-id': getTenantId()
|
||||
}
|
||||
uploadDisabled.value = true
|
||||
uploadRef.value!.submit()
|
||||
}
|
||||
// 文件上传成功
|
||||
const handleFileSuccess = async (response: any): Promise<void> => {
|
||||
if (response.code !== 0) {
|
||||
message.error(response.msg)
|
||||
return
|
||||
}
|
||||
message.success('上传成功')
|
||||
uploadDialogVisible.value = false
|
||||
uploadDisabled.value = false
|
||||
await reload()
|
||||
}
|
||||
const beforeRemove: UploadProps['beforeRemove'] = () => {
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// 文件数超出提示
|
||||
const handleExceed = (): void => {
|
||||
message.error('最多只能上传一个文件!')
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// 上传错误提示
|
||||
const excelUploadError = (): void => {
|
||||
message.error('导入数据失败,请您重新上传!')
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
// 详情操作
|
||||
const handleDetail = (row: FileApi.FileVO) => {
|
||||
// 设置数据
|
||||
detailData.value = row
|
||||
dialogTitle.value = t('action.detail')
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
// 打开上传对话框
|
||||
const uploadDialog = () => {
|
||||
uploadDialogVisible.value = true
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
|
||||
/** 添加/修改操作 */
|
||||
const modalRef = ref()
|
||||
const openModal = () => {
|
||||
modalRef.value.openModal()
|
||||
// ========== 复制相关 ==========
|
||||
const handleCopy = async (text: string) => {
|
||||
// const { copy, copied, isSupported } = useClipboard({ source: text, read: true })
|
||||
// if (!isSupported.value) {
|
||||
// message.error(t('common.copyError'))
|
||||
// } else {
|
||||
// await copy()
|
||||
// if (unref(copied.value)) {
|
||||
// message.success(t('common.copySuccess'))
|
||||
// }
|
||||
// }
|
||||
let url = text
|
||||
let oInput = document.createElement('textarea')
|
||||
oInput.value = url
|
||||
document.body.appendChild(oInput)
|
||||
oInput.select() // 选择对象;
|
||||
// console.log(oInput.value)
|
||||
document.execCommand('Copy') // 执行浏览器复制命令
|
||||
message.success(t('common.copySuccess'))
|
||||
oInput.remove()
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
await FileApi.deleteFile(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
@ -1,193 +0,0 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="配置名" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入配置名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formData.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="存储器" prop="storage">
|
||||
<el-select
|
||||
v-model="formData.storage"
|
||||
placeholder="请选择存储器"
|
||||
:disabled="formData.id !== undefined"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in getDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="parseInt(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- DB -->
|
||||
<!-- Local / FTP / SFTP -->
|
||||
<el-form-item
|
||||
v-if="formData.storage >= 10 && formData.storage <= 12"
|
||||
label="基础路径"
|
||||
prop="config.basePath"
|
||||
>
|
||||
<el-input v-model="formData.config.basePath" placeholder="请输入基础路径" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formData.storage >= 11 && formData.storage <= 12"
|
||||
label="主机地址"
|
||||
prop="config.host"
|
||||
>
|
||||
<el-input v-model="formData.config.host" placeholder="请输入主机地址" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formData.storage >= 11 && formData.storage <= 12"
|
||||
label="主机端口"
|
||||
prop="config.port"
|
||||
>
|
||||
<el-input-number :min="0" v-model="formData.config.port" placeholder="请输入主机端口" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formData.storage >= 11 && formData.storage <= 12"
|
||||
label="用户名"
|
||||
prop="config.username"
|
||||
>
|
||||
<el-input v-model="formData.config.username" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formData.storage >= 11 && formData.storage <= 12"
|
||||
label="密码"
|
||||
prop="config.password"
|
||||
>
|
||||
<el-input v-model="formData.config.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.storage === 11" label="连接模式" prop="config.mode">
|
||||
<el-radio-group v-model="formData.config.mode">
|
||||
<el-radio key="Active" label="Active">主动模式</el-radio>
|
||||
<el-radio key="Passive" label="Passive">主动模式</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- S3 -->
|
||||
<el-form-item v-if="formData.storage === 20" label="节点地址" prop="config.endpoint">
|
||||
<el-input v-model="formData.config.endpoint" placeholder="请输入节点地址" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.storage === 20" label="存储 bucket" prop="config.bucket">
|
||||
<el-input v-model="formData.config.bucket" placeholder="请输入 bucket" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.storage === 20" label="accessKey" prop="config.accessKey">
|
||||
<el-input v-model="formData.config.accessKey" placeholder="请输入 accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.storage === 20" label="accessSecret" prop="config.accessSecret">
|
||||
<el-input v-model="formData.config.accessSecret" placeholder="请输入 accessSecret" />
|
||||
</el-form-item>
|
||||
<!-- 通用 -->
|
||||
<el-form-item v-if="formData.storage === 20" label="自定义域名">
|
||||
<!-- 无需参数校验,所以去掉 prop -->
|
||||
<el-input v-model="formData.config.domain" placeholder="请输入自定义域名" />
|
||||
</el-form-item>
|
||||
<el-form-item v-else-if="formData.storage" label="自定义域名" prop="config.domain">
|
||||
<el-input v-model="formData.config.domain" placeholder="请输入自定义域名" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
||||
import * as FileConfigApi from '@/api/infra/fileConfig'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref({
|
||||
id: undefined,
|
||||
name: '',
|
||||
storage: '',
|
||||
remark: '',
|
||||
config: {}
|
||||
})
|
||||
const formRules = reactive({
|
||||
name: [{ required: true, message: '配置名不能为空', trigger: 'blur' }],
|
||||
storage: [{ required: true, message: '存储器不能为空', trigger: 'change' }],
|
||||
config: {
|
||||
basePath: [{ required: true, message: '基础路径不能为空', trigger: 'blur' }],
|
||||
host: [{ required: true, message: '主机地址不能为空', trigger: 'blur' }],
|
||||
port: [{ required: true, message: '主机端口不能为空', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '密码不能为空', trigger: 'blur' }],
|
||||
mode: [{ required: true, message: '连接模式不能为空', trigger: 'change' }],
|
||||
endpoint: [{ required: true, message: '节点地址不能为空', trigger: 'blur' }],
|
||||
bucket: [{ required: true, message: '存储 bucket 不能为空', trigger: 'blur' }],
|
||||
accessKey: [{ required: true, message: 'accessKey 不能为空', trigger: 'blur' }],
|
||||
accessSecret: [{ required: true, message: 'accessSecret 不能为空', trigger: 'blur' }],
|
||||
domain: [{ required: true, message: '自定义域名不能为空', trigger: 'blur' }]
|
||||
}
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const openModal = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = await FileConfigApi.getFileConfig(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
if (!formRef) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as unknown as FileConfigApi.FileConfigVO
|
||||
if (formType.value === 'create') {
|
||||
await FileConfigApi.createFileConfig(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await FileConfigApi.updateFileConfig(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
name: '',
|
||||
storage: '',
|
||||
remark: '',
|
||||
config: {}
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
@ -1,190 +0,0 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 列表 -->
|
||||
<XTable @register="registerTable">
|
||||
<template #toolbar_buttons>
|
||||
<XButton type="primary" preIcon="ep:upload" title="上传文件" @click="uploadDialog" />
|
||||
</template>
|
||||
<template #actionbtns_default="{ row }">
|
||||
<XTextButton
|
||||
preIcon="ep:copy-document"
|
||||
:title="t('common.copy')"
|
||||
@click="handleCopy(row.url)"
|
||||
/>
|
||||
<XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" />
|
||||
<XTextButton
|
||||
preIcon="ep:delete"
|
||||
:title="t('action.del')"
|
||||
v-hasPermi="['infra:file:delete']"
|
||||
@click="deleteData(row.id)"
|
||||
/>
|
||||
</template>
|
||||
</XTable>
|
||||
</ContentWrap>
|
||||
<XModal v-model="dialogVisible" :title="dialogTitle">
|
||||
<!-- 对话框(详情) -->
|
||||
<Descriptions :schema="allSchemas.detailSchema" :data="detailData">
|
||||
<template #url="{ row }">
|
||||
<el-image
|
||||
v-if="row.type === 'jpg' || 'png' || 'gif'"
|
||||
style="width: 100px; height: 100px"
|
||||
:src="row.url"
|
||||
:key="row.url"
|
||||
lazy
|
||||
/>
|
||||
<span>{{ row.url }}</span>
|
||||
</template>
|
||||
</Descriptions>
|
||||
<!-- 操作按钮 -->
|
||||
<template #footer>
|
||||
<XButton :title="t('dialog.close')" @click="dialogVisible = false" />
|
||||
</template>
|
||||
</XModal>
|
||||
<XModal v-model="uploadDialogVisible" :title="uploadDialogTitle">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:action="updateUrl + '?updateSupport=' + updateSupport"
|
||||
:headers="uploadHeaders"
|
||||
:drag="true"
|
||||
:limit="1"
|
||||
:multiple="true"
|
||||
:show-file-list="true"
|
||||
:disabled="uploadDisabled"
|
||||
:before-upload="beforeUpload"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handleFileSuccess"
|
||||
:on-error="excelUploadError"
|
||||
:before-remove="beforeRemove"
|
||||
:on-change="handleFileChange"
|
||||
:auto-upload="false"
|
||||
accept=".jpg, .png, .gif"
|
||||
>
|
||||
<Icon icon="ep:upload-filled" />
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">请上传 .jpg, .png, .gif 标准格式文件</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<!-- 按钮:保存 -->
|
||||
<XButton
|
||||
type="primary"
|
||||
preIcon="ep:upload-filled"
|
||||
:title="t('action.save')"
|
||||
@click="submitFileForm()"
|
||||
/>
|
||||
<!-- 按钮:关闭 -->
|
||||
<XButton :title="t('dialog.close')" @click="uploadDialogVisible = false" />
|
||||
</template>
|
||||
</XModal>
|
||||
</template>
|
||||
<script setup lang="ts" name="FileList">
|
||||
import type { UploadInstance, UploadRawFile, UploadProps, UploadFile } from 'element-plus'
|
||||
// 业务相关的 import
|
||||
import { allSchemas } from './fileList.data'
|
||||
import * as FileApi from '@/api/infra/fileList'
|
||||
import { getAccessToken, getTenantId } from '@/utils/auth'
|
||||
// import { useClipboard } from '@vueuse/core'
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
// 列表相关的变量
|
||||
const [registerTable, { reload, deleteData }] = useXTable({
|
||||
allSchemas: allSchemas,
|
||||
getListApi: FileApi.getFilePageApi,
|
||||
deleteApi: FileApi.deleteFileApi
|
||||
})
|
||||
|
||||
const detailData = ref() // 详情 Ref
|
||||
const dialogVisible = ref(false) // 是否显示弹出层
|
||||
const dialogTitle = ref('') // 弹出层标题
|
||||
const uploadDialogVisible = ref(false)
|
||||
const uploadDialogTitle = ref('上传')
|
||||
const updateSupport = ref(0)
|
||||
const uploadDisabled = ref(false)
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
let updateUrl = import.meta.env.VITE_UPLOAD_URL
|
||||
const uploadHeaders = ref()
|
||||
// 文件上传之前判断
|
||||
const beforeUpload = (file: UploadRawFile) => {
|
||||
const isImg = file.type === 'image/jpeg' || 'image/gif' || 'image/png'
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isImg) message.error('上传文件只能是 jpeg / gif / png 格式!')
|
||||
if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
|
||||
return isImg && isLt5M
|
||||
}
|
||||
// 处理上传的文件发生变化
|
||||
const handleFileChange = (uploadFile: UploadFile): void => {
|
||||
// uploadRef.value.data.path = uploadFile.name
|
||||
console.log(uploadFile, 'uploadFile')
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// 文件上传
|
||||
const submitFileForm = () => {
|
||||
uploadHeaders.value = {
|
||||
Authorization: 'Bearer ' + getAccessToken(),
|
||||
'tenant-id': getTenantId()
|
||||
}
|
||||
uploadDisabled.value = true
|
||||
uploadRef.value!.submit()
|
||||
}
|
||||
// 文件上传成功
|
||||
const handleFileSuccess = async (response: any): Promise<void> => {
|
||||
if (response.code !== 0) {
|
||||
message.error(response.msg)
|
||||
return
|
||||
}
|
||||
message.success('上传成功')
|
||||
uploadDialogVisible.value = false
|
||||
uploadDisabled.value = false
|
||||
await reload()
|
||||
}
|
||||
const beforeRemove: UploadProps['beforeRemove'] = () => {
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// 文件数超出提示
|
||||
const handleExceed = (): void => {
|
||||
message.error('最多只能上传一个文件!')
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// 上传错误提示
|
||||
const excelUploadError = (): void => {
|
||||
message.error('导入数据失败,请您重新上传!')
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
|
||||
// 详情操作
|
||||
const handleDetail = (row: FileApi.FileVO) => {
|
||||
// 设置数据
|
||||
detailData.value = row
|
||||
dialogTitle.value = t('action.detail')
|
||||
dialogVisible.value = true
|
||||
}
|
||||
// 打开上传对话框
|
||||
const uploadDialog = () => {
|
||||
uploadDialogVisible.value = true
|
||||
uploadDisabled.value = false
|
||||
}
|
||||
// ========== 复制相关 ==========
|
||||
const handleCopy = async (text: string) => {
|
||||
// const { copy, copied, isSupported } = useClipboard({ source: text, read: true })
|
||||
// if (!isSupported.value) {
|
||||
// message.error(t('common.copyError'))
|
||||
// } else {
|
||||
// await copy()
|
||||
// if (unref(copied.value)) {
|
||||
// message.success(t('common.copySuccess'))
|
||||
// }
|
||||
// }
|
||||
let url = text
|
||||
let oInput = document.createElement('textarea')
|
||||
oInput.value = url
|
||||
document.body.appendChild(oInput)
|
||||
oInput.select() // 选择对象;
|
||||
// console.log(oInput.value)
|
||||
document.execCommand('Copy') // 执行浏览器复制命令
|
||||
message.success(t('common.copySuccess'))
|
||||
oInput.remove()
|
||||
}
|
||||
</script>
|
@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" title="任务详细" width="700px">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="任务编号" min-width="60">
|
||||
{{ detailData.id }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="任务名称">
|
||||
{{ detailData.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="任务名称">
|
||||
<dict-tag :type="DICT_TYPE.INFRA_JOB_STATUS" :value="detailData.status" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理器的名字">
|
||||
{{ detailData.handlerName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理器的参数">
|
||||
{{ detailData.handlerParam }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="Cron 表达式">
|
||||
{{ detailData.cronExpression }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="重试次数">
|
||||
{{ detailData.retryCount }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="重试间隔">
|
||||
{{ detailData.retryInterval + ' 毫秒' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="监控超时时间">
|
||||
{{ detailData.monitorTimeout > 0 ? detailData.monitorTimeout + ' 毫秒' : '未开启' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="后续执行时间">
|
||||
<el-timeline>
|
||||
<el-timeline-item
|
||||
v-for="(nextTime, index) in nextTimes"
|
||||
:key="index"
|
||||
:timestamp="formatDate(nextTime)"
|
||||
>
|
||||
第 {{ index + 1 }} 次
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script lang="ts" name="InfraJobDetail" setup>
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import * as JobApi from '@/api/infra/job'
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const detailLoading = ref(false) // 表单的加载中
|
||||
const detailData = ref({}) // 详情数据
|
||||
const nextTimes = ref([]) // 下一轮执行时间的数组
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (id: number) => {
|
||||
dialogVisible.value = true
|
||||
// 查看,设置数据
|
||||
if (id) {
|
||||
detailLoading.value = true
|
||||
try {
|
||||
detailData.value = await JobApi.getJob(id)
|
||||
// 获取下一次执行时间
|
||||
nextTimes.value = await JobApi.getJobNextTimes(id)
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
</script>
|
@ -1,128 +0,0 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="任务名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入任务名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="处理器的名字" prop="handlerName">
|
||||
<el-input
|
||||
:readonly="formData.id !== undefined"
|
||||
v-model="formData.handlerName"
|
||||
placeholder="请输入处理器的名字"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理器的参数" prop="handlerParam">
|
||||
<el-input v-model="formData.handlerParam" placeholder="请输入处理器的参数" />
|
||||
</el-form-item>
|
||||
<el-form-item label="CRON 表达式" prop="cronExpression">
|
||||
<crontab v-model="formData.cronExpression" />
|
||||
</el-form-item>
|
||||
<el-form-item label="重试次数" prop="retryCount">
|
||||
<el-input
|
||||
v-model="formData.retryCount"
|
||||
placeholder="请输入重试次数。设置为 0 时,不进行重试"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="重试间隔" prop="retryInterval">
|
||||
<el-input
|
||||
v-model="formData.retryInterval"
|
||||
placeholder="请输入重试间隔,单位:毫秒。设置为 0 时,无需间隔"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="监控超时时间" prop="monitorTimeout">
|
||||
<el-input v-model="formData.monitorTimeout" placeholder="请输入监控超时时间,单位:毫秒" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="submitForm" :loading="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts" name="JobForm">
|
||||
import * as JobApi from '@/api/infra/job'
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref({
|
||||
id: undefined,
|
||||
name: '',
|
||||
handlerName: '',
|
||||
handlerParam: '',
|
||||
cronExpression: ''
|
||||
})
|
||||
const formRules = reactive({
|
||||
name: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
|
||||
handlerName: [{ required: true, message: '处理器的名字不能为空', trigger: 'blur' }],
|
||||
cronExpression: [{ required: true, message: 'CRON 表达式不能为空', trigger: 'blur' }],
|
||||
retryCount: [{ required: true, message: '重试次数不能为空', trigger: 'blur' }],
|
||||
retryInterval: [{ required: true, message: '重试间隔不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = await JobApi.getJob(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 提交按钮 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
if (!formRef) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as unknown as JobApi.JobVO
|
||||
if (formType.value === 'create') {
|
||||
await JobApi.createJob(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await JobApi.updateJob(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
name: '',
|
||||
handlerName: '',
|
||||
handlerParam: '',
|
||||
cronExpression: ''
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" title="任务详细" width="700px">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="日志编号" min-width="60">
|
||||
{{ detailData.id }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="任务编号">
|
||||
{{ detailData.jobId }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理器的名字">
|
||||
{{ detailData.handlerName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理器的参数">
|
||||
{{ detailData.handlerParam }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="第几次执行">
|
||||
{{ detailData.executeIndex }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行时间">
|
||||
{{ formatDate(detailData.beginTime) + ' ~ ' + formatDate(detailData.endTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行时长">
|
||||
{{ detailData.duration + ' 毫秒' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="任务状态">
|
||||
<dict-tag :type="DICT_TYPE.INFRA_JOB_LOG_STATUS" :value="detailData.status" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行结果">
|
||||
{{ detailData.duration + ' result' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script lang="ts" name="JobLogDetail" setup>
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import * as JobLogApi from '@/api/infra/jobLog'
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const detailLoading = ref(false) // 表单的加载中
|
||||
const detailData = ref({}) // 详情数据
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (id: number) => {
|
||||
dialogVisible.value = true
|
||||
// 查看,设置数据
|
||||
if (id) {
|
||||
detailLoading.value = true
|
||||
try {
|
||||
detailData.value = await JobLogApi.getJobLog(id)
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
</script>
|
@ -1,193 +0,0 @@
|
||||
<template>
|
||||
<content-wrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="处理器的名字" prop="handlerName">
|
||||
<el-input
|
||||
v-model="queryParams.handlerName"
|
||||
placeholder="请输入处理器的名字"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始执行时间" prop="beginTime">
|
||||
<el-date-picker
|
||||
v-model="queryParams.beginTime"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="选择开始执行时间"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束执行时间" prop="endTime">
|
||||
<el-date-picker
|
||||
v-model="queryParams.endTime"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="选择结束执行时间"
|
||||
clearable
|
||||
:default-time="new Date('1 23:59:59')"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="请选择任务状态"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_JOB_LOG_STATUS)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['infra:job:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</content-wrap>
|
||||
|
||||
<!-- 列表 -->
|
||||
<content-wrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="日志编号" align="center" prop="id" />
|
||||
<el-table-column label="任务编号" align="center" prop="jobId" />
|
||||
<el-table-column label="处理器的名字" align="center" prop="handlerName" />
|
||||
<el-table-column label="处理器的参数" align="center" prop="handlerParam" />
|
||||
<el-table-column label="第几次执行" align="center" prop="executeIndex" />
|
||||
<el-table-column label="执行时间" align="center" width="170s">
|
||||
<template #default="scope">
|
||||
<span>{{ formatDate(scope.row.beginTime) + ' ~ ' + formatDate(scope.row.endTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="执行时长" align="center" prop="duration">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.duration + ' 毫秒' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="任务状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.INFRA_JOB_LOG_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click="openDetail(scope.row.id)"
|
||||
v-hasPermi="['infra:job:query']"
|
||||
>
|
||||
详细
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</content-wrap>
|
||||
|
||||
<!-- 表单弹窗:查看 -->
|
||||
<JobLogDetail ref="detailRef" />
|
||||
</template>
|
||||
<script setup lang="ts" name="JobLog">
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import JobLogDetail from './JobLogDetail.vue'
|
||||
import * as JobLogApi from '@/api/infra/jobLog'
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { query } = useRoute() // 查询参数
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const total = ref(0) // 列表的总页数
|
||||
const list = ref([]) // 列表的数据
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
jobId: query.id,
|
||||
handlerName: undefined,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
status: undefined
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const exportLoading = ref(false) // 导出的加载中
|
||||
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await JobLogApi.getJobLogPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 查看操作 */
|
||||
const detailRef = ref()
|
||||
const openDetail = (rowId?: number) => {
|
||||
detailRef.value.open(rowId)
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
// 导出的二次确认
|
||||
await message.exportConfirm()
|
||||
// 发起导出
|
||||
exportLoading.value = true
|
||||
const data = await JobLogApi.exportJobLog(queryParams)
|
||||
download.excel(data, '定时任务执行日志.xls')
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
@ -1,44 +0,0 @@
|
||||
export const parseTime = (time) => {
|
||||
if (!time) {
|
||||
return null
|
||||
}
|
||||
const format = '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
|
||||
time = parseInt(time)
|
||||
} else if (typeof time === 'string') {
|
||||
time = time
|
||||
.replace(new RegExp(/-/gm), '/')
|
||||
.replace('T', ' ')
|
||||
.replace(new RegExp(/\.[\d]{3}/gm), '')
|
||||
}
|
||||
if (typeof time === 'number' && time.toString().length === 10) {
|
||||
time = time * 1000
|
||||
}
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
m: date.getMonth() + 1,
|
||||
d: date.getDate(),
|
||||
h: date.getHours(),
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') {
|
||||
return ['日', '一', '二', '三', '四', '五', '六'][value]
|
||||
}
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
})
|
||||
return time_str
|
||||
}
|
@ -61,7 +61,12 @@
|
||||
<el-row class="mt-3">
|
||||
<el-col :span="24" class="card-box" shadow="hover">
|
||||
<el-card>
|
||||
<el-table v-loading="keyListLoad" :data="keyList" row-key="id" @row-click="openKeyTemplate">
|
||||
<el-table
|
||||
v-loading="keyListLoad"
|
||||
:data="keyList"
|
||||
row-key="id"
|
||||
@row-click="openKeyTemplate"
|
||||
>
|
||||
<el-table-column prop="keyTemplate" label="Key 模板" width="200" />
|
||||
<el-table-column prop="keyType" label="Key 类型" width="100" />
|
||||
<el-table-column prop="valueType" label="Value 类型" />
|
||||
@ -105,8 +110,12 @@
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>缓存内容</span>
|
||||
<XTextButton preIcon="ep:refresh" title="清理全部" @click="handleDeleteKeys(keyTemplate)"
|
||||
class="float-right p-1" />
|
||||
<XTextButton
|
||||
preIcon="ep:refresh"
|
||||
title="清理全部"
|
||||
class="float-right p-1"
|
||||
@click="handleDeleteKeys(keyTemplate)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions :column="1">
|
||||
@ -119,7 +128,6 @@
|
||||
</XModal>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
// import * as echarts from 'echarts'
|
||||
import * as RedisApi from '@/api/infra/redis'
|
||||
import { RedisKeyInfo, RedisMonitorInfoVO } from '@/api/infra/redis/types'
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
@ -137,98 +145,6 @@ const readRedisInfo = async () => {
|
||||
keyList.value = redisKeysInfo
|
||||
keyListLoad.value = false //加载完成
|
||||
}
|
||||
// 图表
|
||||
// const commandStatsRef = ref<HTMLElement>()
|
||||
// const usedmemory = ref<HTMLDivElement>()
|
||||
// const loadEchartOptions = (stats) => {
|
||||
// const commandStats = [] as any[]
|
||||
// const nameList = [] as string[]
|
||||
// stats.forEach((row) => {
|
||||
// commandStats.push({
|
||||
// name: row.command,
|
||||
// value: row.calls
|
||||
// })
|
||||
// nameList.push(row.command)
|
||||
// })
|
||||
|
||||
// const commandStatsInstance = echarts.init(commandStatsRef.value!, 'macarons')
|
||||
|
||||
// commandStatsInstance.setOption({
|
||||
// title: {
|
||||
// text: '命令统计',
|
||||
// left: 'center'
|
||||
// },
|
||||
// tooltip: {
|
||||
// trigger: 'item',
|
||||
// formatter: '{a} <br/>{b} : {c} ({d}%)'
|
||||
// },
|
||||
// legend: {
|
||||
// type: 'scroll',
|
||||
// orient: 'vertical',
|
||||
// right: 30,
|
||||
// top: 10,
|
||||
// bottom: 20,
|
||||
// data: nameList,
|
||||
// textStyle: {
|
||||
// color: '#a1a1a1'
|
||||
// }
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// name: '命令',
|
||||
// type: 'pie',
|
||||
// radius: [20, 120],
|
||||
// center: ['40%', '60%'],
|
||||
// data: commandStats,
|
||||
// roseType: 'radius',
|
||||
// label: {
|
||||
// show: true
|
||||
// },
|
||||
// emphasis: {
|
||||
// label: {
|
||||
// show: true
|
||||
// },
|
||||
// itemStyle: {
|
||||
// shadowBlur: 10,
|
||||
// shadowOffsetX: 0,
|
||||
// shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
|
||||
// const usedMemoryInstance = echarts.init(usedmemory.value!, 'macarons')
|
||||
// usedMemoryInstance.setOption({
|
||||
// title: {
|
||||
// text: '内存使用情况',
|
||||
// left: 'center'
|
||||
// },
|
||||
// tooltip: {
|
||||
// formatter: '{b} <br/>{a} : ' + cache.value!.info.used_memory_human
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// name: '峰值',
|
||||
// type: 'gauge',
|
||||
// min: 0,
|
||||
// max: 100,
|
||||
// progress: {
|
||||
// show: true
|
||||
// },
|
||||
// detail: {
|
||||
// formatter: cache.value!.info.used_memory_human
|
||||
// },
|
||||
// data: [
|
||||
// {
|
||||
// value: parseFloat(cache.value!.info.used_memory_human),
|
||||
// name: '内存消耗'
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// }
|
||||
const dialogVisible = ref(false)
|
||||
const keyTemplate = ref('')
|
||||
const cacheKeys = ref()
|
||||
@ -398,7 +314,7 @@ const initCommandStatsChart = async () => {
|
||||
})
|
||||
commandStatsRefChika.legend.data = nameList
|
||||
commandStatsRefChika.series[0].data = commandStats
|
||||
} catch { }
|
||||
} catch {}
|
||||
}
|
||||
const usedMemoryInstance = async () => {
|
||||
try {
|
||||
@ -421,7 +337,7 @@ const usedMemoryInstance = async () => {
|
||||
usedmemoryEchartChika.tooltip = {
|
||||
formatter: '{b} <br/>{a} : ' + cache.value!.info.used_memory_human
|
||||
}
|
||||
} catch { }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
|
@ -4,7 +4,7 @@
|
||||
<XTable @register="registerTable">
|
||||
<template #accountId_search>
|
||||
<el-select v-model="queryParams.accountId">
|
||||
<el-option :key="undefined" label="全部" :value="undefined" />
|
||||
<el-option :key="undefined" label="全部" value="" />
|
||||
<el-option
|
||||
v-for="item in accountOptions"
|
||||
:key="item.id"
|
||||
|
@ -4,7 +4,7 @@
|
||||
<XTable @register="registerTable">
|
||||
<template #accountId_search>
|
||||
<el-select v-model="queryParams.accountId">
|
||||
<el-option :key="undefined" label="全部" :value="undefined" />
|
||||
<el-option :key="undefined" label="全部" value="" />
|
||||
<el-option
|
||||
v-for="item in accountOptions"
|
||||
:key="item.id"
|
||||
|
@ -1,91 +0,0 @@
|
||||
<template>
|
||||
<!-- 弹窗 -->
|
||||
<XModal :title="modelTitle" :loading="modelLoading" v-model="modelVisible">
|
||||
<!-- 表单:添加/修改 -->
|
||||
<Form
|
||||
ref="formRef"
|
||||
v-if="['create', 'update'].includes(actionType)"
|
||||
:schema="allSchemas.formSchema"
|
||||
:rules="rules"
|
||||
/>
|
||||
<!-- 表单:详情 -->
|
||||
<Descriptions
|
||||
v-if="actionType === 'detail'"
|
||||
:schema="allSchemas.detailSchema"
|
||||
:data="detailData"
|
||||
/>
|
||||
<template #footer>
|
||||
<!-- 按钮:保存 -->
|
||||
<XButton
|
||||
v-if="['create', 'update'].includes(actionType)"
|
||||
type="primary"
|
||||
:title="t('action.save')"
|
||||
:loading="actionLoading"
|
||||
@click="submitForm()"
|
||||
/>
|
||||
<!-- 按钮:关闭 -->
|
||||
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="modelVisible = false" />
|
||||
</template>
|
||||
</XModal>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { FormExpose } from '@/components/Form'
|
||||
import * as PostApi from '@/api/system/post'
|
||||
import { rules, allSchemas } from './post.data'
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
// 弹窗相关的变量
|
||||
const modelVisible = ref(false) // 是否显示弹出层
|
||||
const modelTitle = ref('') // 弹出层标题
|
||||
const modelLoading = ref(false) // 弹出层loading
|
||||
const actionType = ref('') // 操作按钮的类型
|
||||
const actionLoading = ref(false) // 按钮 Loading
|
||||
const formRef = ref<FormExpose>() // 表单 Ref
|
||||
const detailData = ref() // 详情 Ref
|
||||
|
||||
// 打开弹窗
|
||||
const openModal = async (type: string, id?: number) => {
|
||||
modelVisible.value = true
|
||||
modelLoading.value = true
|
||||
modelTitle.value = t('action.' + type)
|
||||
actionType.value = type
|
||||
// 设置数据
|
||||
if (id) {
|
||||
const res = await PostApi.getPostApi(id)
|
||||
if (type === 'update') {
|
||||
unref(formRef)?.setValues(res)
|
||||
} else if (type === 'detail') {
|
||||
detailData.value = res
|
||||
}
|
||||
}
|
||||
modelLoading.value = false
|
||||
}
|
||||
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
|
||||
|
||||
// 提交新增/修改的表单
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
const elForm = unref(formRef)?.getElFormRef()
|
||||
if (!elForm) return
|
||||
const valid = await elForm.validate()
|
||||
if (!valid) return
|
||||
// 提交请求
|
||||
actionLoading.value = true
|
||||
try {
|
||||
const data = unref(formRef)?.formModel as PostApi.PostVO
|
||||
if (actionType.value === 'create') {
|
||||
await PostApi.createPostApi(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await PostApi.updatePostApi(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
modelVisible.value = false
|
||||
emit('success')
|
||||
} finally {
|
||||
actionLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user