feat: 新增存储管理

This commit is contained in:
2024-04-10 22:13:25 +08:00
parent 3533e020c6
commit 8142f07ce7
6 changed files with 381 additions and 0 deletions

View File

@@ -1,2 +1,3 @@
export * from './dept'
export * from './log'
export * from './storage'

View File

@@ -0,0 +1,29 @@
import http from '@/utils/http'
import type * as System from './type'
const BASE_URL = '/system/storage'
/** @desc 查询存储列表 */
export function listStorage(query: System.StorageQuery) {
return http.get<PageRes<System.StorageResp[]>>(`${BASE_URL}`, query)
}
/** @desc 查询存储详情 */
export function getStorage(id: string) {
return http.get<System.StorageResp>(`${BASE_URL}/${id}`)
}
/** @desc 新增存储 */
export function addStorage(data: any) {
return http.post(`${BASE_URL}`, data)
}
/** @desc 修改存储 */
export function updateStorage(data: any, id: string) {
return http.put(`${BASE_URL}/${id}`, data)
}
/** @desc 删除存储 */
export function deleteStorage(id: string) {
return http.del(`${BASE_URL}/${id}`)
}

View File

@@ -52,3 +52,28 @@ export interface LogQuery extends PageQuery {
createTime?: string
status?: number
}
/** 系统存储类型 */
export type StorageResp = {
id: string
name: string
code: string
type: number
accessKey: string
secretKey: string
endpoint: string
bucketName: string
domain: string
description: string
isDefault: boolean
sort: number
status: number
createUserString: string
createTime: string
updateUserString: string
updateTime: string
}
export interface StorageQuery extends PageQuery {
description?: string
status?: number
}

View File

@@ -0,0 +1,166 @@
<template>
<a-drawer
v-model:visible="visible"
:title="title"
:mask-closable="false"
:esc-to-close="false"
:width="width >= 600 ? 600 : '100%'"
@before-ok="save"
@close="reset"
>
<a-form ref="formRef" :model="form" :rules="rules" size="large" auto-label-width>
<a-form-item label="名称" field="name">
<a-input v-model.trim="form.name" placeholder="请输入名称" />
</a-form-item>
<a-form-item label="编码" field="code">
<a-input v-model.trim="form.code" placeholder="请输入编码" :disabled="isUpdate" />
</a-form-item>
<a-form-item label="类型" field="type">
<a-select v-model.trim="form.type" :options="storage_type_enum" placeholder="请选择类型" />
</a-form-item>
<a-form-item v-if="form.type === 1" label="访问密钥" field="accessKey">
<a-input v-model.trim="form.accessKey" placeholder="请输入访问密钥" />
</a-form-item>
<a-form-item v-if="form.type === 1" label="私有密钥" field="secretKey">
<a-input v-model.trim="form.secretKey" placeholder="请输入私有密钥" />
</a-form-item>
<a-form-item v-if="form.type === 1" label="终端节点" field="endpoint">
<a-input v-model.trim="form.endpoint" placeholder="请输入终端节点" />
</a-form-item>
<a-form-item label="桶名称" field="bucketName">
<a-input v-model.trim="form.bucketName" placeholder="请输入桶名称" />
</a-form-item>
<a-form-item v-if="form.type === 1" label="域名" field="domain">
<a-input v-model.trim="form.domain" placeholder="请输入域名" />
</a-form-item>
<a-form-item
v-if="form.type === 2"
label="域名"
field="domain"
:rules="[
{
required: true,
message: '请输入域名'
}
]"
>
<a-input v-model.trim="form.domain" placeholder="请输入域名" />
</a-form-item>
<a-form-item label="排序" field="sort">
<a-input-number v-model="form.sort" placeholder="请输入排序" :min="1" mode="button" />
</a-form-item>
<a-form-item label="描述" field="description">
<a-textarea
v-model.trim="form.description"
placeholder="请输入描述"
show-word-limit
:max-length="200"
:auto-size="{ minRows: 3, maxRows: 5 }"
/>
</a-form-item>
<a-form-item label="默认存储" field="isDefault">
<a-switch
v-model="form.isDefault"
type="round"
:checked-value="true"
:unchecked-value="false"
checked-text=""
unchecked-text=""
/>
</a-form-item>
<a-form-item label="状态" field="status">
<a-switch
v-model="form.status"
type="round"
:checked-value="1"
:unchecked-value="2"
checked-text="启用"
unchecked-text="禁用"
/>
</a-form-item>
</a-form>
</a-drawer>
</template>
<script setup lang="ts">
import { getStorage, addStorage, updateStorage } from '@/apis'
import type { StorageReq } from './type'
import { Message, type FormInstance } from "@arco-design/web-vue";
import { useForm } from '@/hooks'
import { useDict } from '@/hooks/app'
import { useWindowSize } from '@vueuse/core'
const { width } = useWindowSize()
const { storage_type_enum } = useDict('storage_type_enum')
const dataId = ref('')
const isUpdate = computed(() => !!dataId.value)
const title = computed(() => (isUpdate.value ? '修改存储' : '新增存储'))
const formRef = ref<FormInstance>()
const rules: FormInstance['rules'] = {
name: [{ required: true, message: '请输入名称' }],
code: [{ required: true, message: '请输入编码' }],
type: [{ required: true, message: '请选择类型' }],
accessKey: [{ required: true, message: '请输入访问密钥' }],
secretKey: [{ required: true, message: '请输入私有密钥' }],
endpoint: [{ required: true, message: '请输入终端节点' }],
bucketName: [{ required: true, message: '请输入桶名称' }]
}
const { form, resetForm } = useForm<StorageReq>({
name: '',
code: '',
type: 2,
sort: 999,
status: 1
})
// 重置
const reset = () => {
formRef.value?.resetFields()
resetForm()
}
const visible = ref(false)
// 新增
const onAdd = () => {
reset()
dataId.value = ''
visible.value = true
}
// 修改
const onUpdate = async (id: string) => {
reset()
dataId.value = id
const res = await getStorage(id)
Object.assign(form, res.data)
visible.value = true
}
// 保存
const save = async () => {
try {
const isInvalid = await formRef.value?.validate()
if (isInvalid) return false
if (isUpdate.value) {
await updateStorage(form, dataId.value)
Message.success('修改成功')
} else {
await addStorage(form)
Message.success('新增成功')
}
emit('save-success')
return true
} catch (error) {
return false
}
}
const emit = defineEmits<{
(e: 'save-success'): void
}>()
defineExpose({ onAdd, onUpdate })
</script>

View File

@@ -0,0 +1,146 @@
<template>
<div class="gi_page">
<a-card title="存储管理" class="general-card">
<GiTable
ref="tableRef"
row-key="id"
:data="dataList"
:columns="columns"
:loading="loading"
:scroll="{ x: '100%', y: '100%', minWidth: 1300 }"
:pagination="pagination"
:disabledColumnKeys="['name']"
@refresh="search"
>
<template #custom-left>
<a-input v-model="queryForm.description" placeholder="请输入关键词" allow-clear @change="search">
<template #prefix><icon-search /></template>
</a-input>
<a-select
v-model="queryForm.status"
:options="DisEnableStatusList"
placeholder="请选择状态"
allow-clear
style="width: 150px"
@change="search"
/>
<a-button @click="reset">重置</a-button>
</template>
<template #custom-right>
<a-button type="primary" @click="onAdd">
<template #icon><icon-plus /></template>
<span>新增</span>
</a-button>
</template>
<template #name="{ record }">
<a-space fill>
<span>{{ record.name }}</span>
<a-tag v-if="record.isDefault" color="arcoblue" size="small" class="gi_round">
<template #default>默认</template>
</a-tag>
</a-space>
</template>
<template #type="{ record }">
<GiCellTag :value="record.type" :dict="storage_type_enum" />
</template>
<template #status="{ record }">
<GiCellStatus :status="record.status" />
</template>
<template #action="{ record }">
<a-space>
<template #split>
<a-divider direction="vertical" :margin="0" />
</template>
<a-link @click="onUpdate(record)">修改</a-link>
<a-link
status="danger"
:title="record.isDefault ? '默认存储库不能删除' : undefined"
:disabled="record.disabled"
@click="onDelete(record)"
>
删除
</a-link>
</a-space>
</template>
</GiTable>
</a-card>
<AddStorageModal ref="AddStorageModalRef" @save-success="search" />
</div>
</template>
<script setup lang="ts">
import { listStorage, deleteStorage, type StorageResp } from '@/apis'
import type { TableInstance } from '@arco-design/web-vue'
import AddStorageModal from './AddStorageModal.vue'
import { useTable } from '@/hooks'
import { useDict } from '@/hooks/app'
import { isMobile } from '@/utils'
import { DisEnableStatusList } from '@/constant/common'
defineOptions({ name: 'Storage' })
const { storage_type_enum } = useDict('storage_type_enum')
const columns: TableInstance['columns'] = [
{
title: '序号',
width: 66,
align: 'center',
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize)
},
{ title: '名称', dataIndex: 'name', slotName: 'name', width: 140, ellipsis: true, tooltip: true },
{ title: '编码', dataIndex: 'code', ellipsis: true, tooltip: true },
{ title: '状态', slotName: 'status', align: 'center' },
{ title: '类型', slotName: 'type', align: 'center' },
{ title: '访问密钥', dataIndex: 'accessKey', ellipsis: true, tooltip: true },
{ title: '终端节点', dataIndex: 'endpoint', ellipsis: true, tooltip: true },
{ title: '桶名称', dataIndex: 'bucketName', ellipsis: true, tooltip: true },
{ title: '域名', dataIndex: 'domain', ellipsis: true, tooltip: true },
{ title: '描述', dataIndex: 'description', ellipsis: true, tooltip: true },
{ title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true },
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
{ title: '修改人', dataIndex: 'updateUserString', show: false, ellipsis: true, tooltip: true },
{ title: '修改时间', dataIndex: 'updateTime', width: 180, show: false },
{ title: '操作', slotName: 'action', width: 130, align: 'center', fixed: !isMobile() ? 'right' : undefined }
]
const queryForm = reactive({
description: undefined,
status: undefined,
sort: ['createTime,desc']
})
const {
tableData: dataList,
loading,
pagination,
search,
handleDelete
} = useTable((p) => listStorage({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
// 重置
const reset = () => {
queryForm.description = undefined
queryForm.status = undefined
search()
}
// 删除
const onDelete = (item: StorageResp) => {
return handleDelete(() => deleteStorage(item.id), { content: `是否确定删除存储 [${item.name}]`, showModal: true })
}
const AddStorageModalRef = ref<InstanceType<typeof AddStorageModal>>()
// 新增
const onAdd = () => {
AddStorageModalRef.value?.onAdd()
}
// 修改
const onUpdate = (item: StorageResp) => {
AddStorageModalRef.value?.onUpdate(item.id)
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,14 @@
export interface StorageReq {
name: string
code: string
type: number
accessKey: string
secretKey: string
endpoint: string
bucketName: string
domain: string
sort: number
description: string
isDefault: boolean
status: 1 | 2
}