mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-11-04 20:59:23 +08:00 
			
		
		
		
	@@ -5,6 +5,7 @@ export * from './dept'
 | 
				
			|||||||
export * from './notice'
 | 
					export * from './notice'
 | 
				
			||||||
export * from './dict'
 | 
					export * from './dict'
 | 
				
			||||||
export * from './file'
 | 
					export * from './file'
 | 
				
			||||||
 | 
					export * from './storage'
 | 
				
			||||||
export * from './option'
 | 
					export * from './option'
 | 
				
			||||||
export * from './user-center'
 | 
					export * from './user-center'
 | 
				
			||||||
export * from './message'
 | 
					export * from './message'
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								src/apis/system/storage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/apis/system/storage.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					import type * as T from './type'
 | 
				
			||||||
 | 
					import http from '@/utils/http'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type * from './type'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BASE_URL = '/system/storage'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @desc 查询存储列表 */
 | 
				
			||||||
 | 
					export function listStorage(query: T.StoragePageQuery) {
 | 
				
			||||||
 | 
					  return http.get<PageRes<T.StorageResp[]>>(`${BASE_URL}`, query)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @desc 查询存储详情 */
 | 
				
			||||||
 | 
					export function getStorage(id: string) {
 | 
				
			||||||
 | 
					  return http.get<T.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}`)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -231,6 +231,34 @@ export interface FileQuery {
 | 
				
			|||||||
export interface FilePageQuery extends FileQuery, PageQuery {
 | 
					export interface FilePageQuery extends FileQuery, PageQuery {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 存储类型 */
 | 
				
			||||||
 | 
					export interface 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 {
 | 
				
			||||||
 | 
					  description?: string
 | 
				
			||||||
 | 
					  status?: number
 | 
				
			||||||
 | 
					  sort: Array<string>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface StoragePageQuery extends StorageQuery, PageQuery {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** 客户端类型 */
 | 
					/** 客户端类型 */
 | 
				
			||||||
export interface ClientResp {
 | 
					export interface ClientResp {
 | 
				
			||||||
  id: string
 | 
					  id: string
 | 
				
			||||||
@@ -306,7 +334,6 @@ export interface SiteConfig {
 | 
				
			|||||||
  SITE_TITLE: OptionResp
 | 
					  SITE_TITLE: OptionResp
 | 
				
			||||||
  SITE_DESCRIPTION: OptionResp
 | 
					  SITE_DESCRIPTION: OptionResp
 | 
				
			||||||
  SITE_COPYRIGHT: OptionResp
 | 
					  SITE_COPYRIGHT: OptionResp
 | 
				
			||||||
  SITE_DOMAIN: OptionResp
 | 
					 | 
				
			||||||
  SITE_BEIAN: OptionResp
 | 
					  SITE_BEIAN: OptionResp
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -333,18 +360,6 @@ export interface MailConfig {
 | 
				
			|||||||
  MAIL_SSL_PORT: OptionResp
 | 
					  MAIL_SSL_PORT: OptionResp
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** 存储配置类型 */
 | 
					 | 
				
			||||||
export interface StorageConfig {
 | 
					 | 
				
			||||||
  STORAGE_DEFAULT: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_BUCKET: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_ENDPOINT: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_OSS_ACCESS_KEY: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_OSS_SECRET_KEY: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_OSS_BUCKET: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_OSS_ENDPOINT: OptionResp
 | 
					 | 
				
			||||||
  STORAGE_OSS_REGION: OptionResp
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** 登录配置类型 */
 | 
					/** 登录配置类型 */
 | 
				
			||||||
export interface LoginConfig {
 | 
					export interface LoginConfig {
 | 
				
			||||||
  LOGIN_CAPTCHA_ENABLED: OptionResp
 | 
					  LOGIN_CAPTCHA_ENABLED: OptionResp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,26 +72,24 @@
 | 
				
			|||||||
          </a-upload>
 | 
					          </a-upload>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item class="input-item" field="SITE_TITLE" :label="siteConfig.SITE_TITLE.name" :help="siteConfig.SITE_TITLE.description">
 | 
					      <a-form-item class="input-item" field="SITE_TITLE" :label="siteConfig.SITE_TITLE.name">
 | 
				
			||||||
        <a-input v-model.trim="form.SITE_TITLE" placeholder="请输入网站名称" :max-length="18" show-word-limit />
 | 
					        <a-input v-model.trim="form.SITE_TITLE" class="input-width" placeholder="请输入系统标题" :max-length="18" show-word-limit />
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item class="input-item" field="SITE_DESCRIPTION" :label="siteConfig.SITE_DESCRIPTION.name" :help="siteConfig.SITE_DESCRIPTION.description">
 | 
					      <a-form-item class="input-item" field="SITE_DESCRIPTION" :label="siteConfig.SITE_DESCRIPTION.name">
 | 
				
			||||||
        <a-textarea
 | 
					        <a-textarea
 | 
				
			||||||
          v-model.trim="form.SITE_DESCRIPTION"
 | 
					          v-model.trim="form.SITE_DESCRIPTION"
 | 
				
			||||||
          placeholder="请输入网站描述"
 | 
					          class="input-width"
 | 
				
			||||||
 | 
					          placeholder="请输入系统描述"
 | 
				
			||||||
          :auto-size="{ minRows: 1, maxRows: 3 }"
 | 
					          :auto-size="{ minRows: 1, maxRows: 3 }"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item class="input-item" field="SITE_COPYRIGHT" :label="siteConfig.SITE_COPYRIGHT.name" :help="siteConfig.SITE_COPYRIGHT.description">
 | 
					      <a-form-item class="input-item" field="SITE_COPYRIGHT" :label="siteConfig.SITE_COPYRIGHT.name">
 | 
				
			||||||
        <a-input v-model.trim="form.SITE_COPYRIGHT" placeholder="请输入版权声明" />
 | 
					        <a-input v-model.trim="form.SITE_COPYRIGHT" class="input-width" placeholder="请输入版权信息" />
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item class="input-item" field="SITE_DOMAIN" :label="siteConfig.SITE_DOMAIN.name" :help="siteConfig.SITE_DOMAIN.description">
 | 
					      <a-form-item field="SITE_BEIAN" :label="siteConfig.SITE_BEIAN.name">
 | 
				
			||||||
        <a-input v-model.trim="form.SITE_DOMAIN" placeholder="请输入网站域名" />
 | 
					        <a-input v-model.trim="form.SITE_BEIAN" class="input-width" placeholder="请输入备案号" :max-length="30" show-word-limit />
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item field="SITE_BEIAN" :label="siteConfig.SITE_BEIAN.name" :help="siteConfig.SITE_BEIAN.description">
 | 
					      <a-space style="margin-bottom: 16px">
 | 
				
			||||||
        <a-input v-model.trim="form.SITE_BEIAN" placeholder="请输入网站备案号" :max-length="30" show-word-limit />
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					 | 
				
			||||||
      <a-space style="margin-top: 16px">
 | 
					 | 
				
			||||||
        <a-button v-if="!isUpdate" v-permission="['system:config:update']" type="primary" @click="onUpdate">
 | 
					        <a-button v-if="!isUpdate" v-permission="['system:config:update']" type="primary" @click="onUpdate">
 | 
				
			||||||
          <template #icon>
 | 
					          <template #icon>
 | 
				
			||||||
            <icon-edit />
 | 
					            <icon-edit />
 | 
				
			||||||
@@ -146,9 +144,9 @@ const [form] = useResetReactive({
 | 
				
			|||||||
  SITE_COPYRIGHT: '',
 | 
					  SITE_COPYRIGHT: '',
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
const rules: FormInstance['rules'] = {
 | 
					const rules: FormInstance['rules'] = {
 | 
				
			||||||
  SITE_TITLE: [{ required: true, message: '请输入网站名称' }],
 | 
					  SITE_TITLE: [{ required: true, message: '请输入系统标题' }],
 | 
				
			||||||
  SITE_DESCRIPTION: [{ required: true, message: '请输入网站描述' }],
 | 
					  SITE_DESCRIPTION: [{ required: true, message: '请输入系统描述' }],
 | 
				
			||||||
  SITE_COPYRIGHT: [{ required: true, message: '请输入版权声明' }],
 | 
					  SITE_COPYRIGHT: [{ required: true, message: '请输入版权信息' }],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const siteConfig = ref<SiteConfig>({
 | 
					const siteConfig = ref<SiteConfig>({
 | 
				
			||||||
@@ -157,7 +155,6 @@ const siteConfig = ref<SiteConfig>({
 | 
				
			|||||||
  SITE_TITLE: {},
 | 
					  SITE_TITLE: {},
 | 
				
			||||||
  SITE_DESCRIPTION: {},
 | 
					  SITE_DESCRIPTION: {},
 | 
				
			||||||
  SITE_COPYRIGHT: {},
 | 
					  SITE_COPYRIGHT: {},
 | 
				
			||||||
  SITE_DOMAIN: {},
 | 
					 | 
				
			||||||
  SITE_BEIAN: {},
 | 
					  SITE_BEIAN: {},
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
const faviconFile = ref<FileItem>({ uid: '-1' })
 | 
					const faviconFile = ref<FileItem>({ uid: '-1' })
 | 
				
			||||||
@@ -169,7 +166,6 @@ const reset = () => {
 | 
				
			|||||||
  form.SITE_LOGO = siteConfig.value.SITE_LOGO.value || ''
 | 
					  form.SITE_LOGO = siteConfig.value.SITE_LOGO.value || ''
 | 
				
			||||||
  form.SITE_TITLE = siteConfig.value.SITE_TITLE.value || ''
 | 
					  form.SITE_TITLE = siteConfig.value.SITE_TITLE.value || ''
 | 
				
			||||||
  form.SITE_DESCRIPTION = siteConfig.value.SITE_DESCRIPTION.value || ''
 | 
					  form.SITE_DESCRIPTION = siteConfig.value.SITE_DESCRIPTION.value || ''
 | 
				
			||||||
  form.SITE_DOMAIN = siteConfig.value.SITE_DOMAIN.value || ''
 | 
					 | 
				
			||||||
  form.SITE_COPYRIGHT = siteConfig.value.SITE_COPYRIGHT.value || ''
 | 
					  form.SITE_COPYRIGHT = siteConfig.value.SITE_COPYRIGHT.value || ''
 | 
				
			||||||
  form.SITE_BEIAN = siteConfig.value.SITE_BEIAN.value || ''
 | 
					  form.SITE_BEIAN = siteConfig.value.SITE_BEIAN.value || ''
 | 
				
			||||||
  faviconFile.value.url = siteConfig.value.SITE_FAVICON.value
 | 
					  faviconFile.value.url = siteConfig.value.SITE_FAVICON.value
 | 
				
			||||||
@@ -317,8 +313,7 @@ onMounted(() => {
 | 
				
			|||||||
  line-height: 46px;
 | 
					  line-height: 46px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:deep(.form .arco-input-wrapper),
 | 
					.input-width {
 | 
				
			||||||
:deep(.form .arco-textarea-wrapper) {
 | 
					 | 
				
			||||||
  width: 500px;
 | 
					  width: 500px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -332,8 +327,9 @@ onMounted(() => {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// responsive
 | 
					// responsive
 | 
				
			||||||
:deep(.mobile .form .arco-input-wrapper),
 | 
					.mobile {
 | 
				
			||||||
:deep(.mobile .form .arco-textarea-wrapper) {
 | 
					  .input-width {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
@@ -9,56 +9,25 @@
 | 
				
			|||||||
      :layout="width >= 500 ? 'horizontal' : 'vertical'"
 | 
					      :layout="width >= 500 ? 'horizontal' : 'vertical'"
 | 
				
			||||||
      :disabled="!isUpdate"
 | 
					      :disabled="!isUpdate"
 | 
				
			||||||
      scroll-to-first-error
 | 
					      scroll-to-first-error
 | 
				
			||||||
      class="form"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <a-form-item
 | 
					 | 
				
			||||||
        field="MAIL_PROTOCOL"
 | 
					 | 
				
			||||||
        :label="mailConfig.MAIL_PROTOCOL.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_PROTOCOL.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
 | 
					      <a-form-item field="MAIL_PROTOCOL" :label="mailConfig.MAIL_PROTOCOL.name" hide-asterisk>
 | 
				
			||||||
        <a-select v-model.trim="form.MAIL_PROTOCOL">
 | 
					        <a-select v-model.trim="form.MAIL_PROTOCOL">
 | 
				
			||||||
          <a-option label="SMTP" value="smtp" />
 | 
					          <a-option label="SMTP" value="smtp" />
 | 
				
			||||||
        </a-select>
 | 
					        </a-select>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="MAIL_HOST" :label="mailConfig.MAIL_HOST.name" hide-asterisk>
 | 
				
			||||||
        field="MAIL_HOST"
 | 
					        <a-input v-model.trim="form.MAIL_HOST" class="input-width" />
 | 
				
			||||||
        :label="mailConfig.MAIL_HOST.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_HOST.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input v-model.trim="form.MAIL_HOST" />
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="MAIL_PORT" :label="mailConfig.MAIL_PORT.name" hide-asterisk>
 | 
				
			||||||
        field="MAIL_PORT"
 | 
					        <a-input-number v-model="form.MAIL_PORT" class="input-width" :min="0" />
 | 
				
			||||||
        :label="mailConfig.MAIL_PORT.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_PORT.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input-number v-model="form.MAIL_PORT" :min="0" />
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="MAIL_USERNAME" :label="mailConfig.MAIL_USERNAME.name" hide-asterisk>
 | 
				
			||||||
        field="MAIL_USERNAME"
 | 
					        <a-input v-model.trim="form.MAIL_USERNAME" class="input-width" />
 | 
				
			||||||
        :label="mailConfig.MAIL_USERNAME.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_USERNAME.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input v-model.trim="form.MAIL_USERNAME" />
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="MAIL_PASSWORD" :label="mailConfig.MAIL_PASSWORD?.name" hide-asterisk>
 | 
				
			||||||
        field="MAIL_PASSWORD"
 | 
					        <a-input-password v-model.trim="form.MAIL_PASSWORD" class="input-width" />
 | 
				
			||||||
        :label="mailConfig.MAIL_PASSWORD?.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_PASSWORD.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input-password v-model.trim="form.MAIL_PASSWORD" />
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="MAIL_SSL_ENABLED" :label="mailConfig.MAIL_SSL_ENABLED?.name" hide-asterisk>
 | 
				
			||||||
        field="MAIL_SSL_ENABLED"
 | 
					 | 
				
			||||||
        :label="mailConfig.MAIL_SSL_ENABLED?.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_SSL_ENABLED.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-switch
 | 
					        <a-switch
 | 
				
			||||||
          v-model="form.MAIL_SSL_ENABLED"
 | 
					          v-model="form.MAIL_SSL_ENABLED"
 | 
				
			||||||
          type="round"
 | 
					          type="round"
 | 
				
			||||||
@@ -70,13 +39,10 @@
 | 
				
			|||||||
        </a-switch>
 | 
					        </a-switch>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        v-if="form.MAIL_SSL_ENABLED === '1'"
 | 
					        v-if="form.MAIL_SSL_ENABLED === '1'" field="MAIL_SSL_PORT" :label="mailConfig.MAIL_SSL_PORT.name"
 | 
				
			||||||
        field="MAIL_SSL_PORT"
 | 
					 | 
				
			||||||
        :label="mailConfig.MAIL_SSL_PORT.name"
 | 
					 | 
				
			||||||
        :help="mailConfig.MAIL_SSL_PORT.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					        hide-asterisk
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number v-model="form.MAIL_SSL_PORT" :min="0" />
 | 
					        <a-input-number v-model="form.MAIL_SSL_PORT" class="input-width" :min="0" />
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-space style="margin-bottom: 16px">
 | 
					      <a-space style="margin-bottom: 16px">
 | 
				
			||||||
        <a-button v-if="!isUpdate" v-permission="['system:config:update']" type="primary" @click="onUpdate">
 | 
					        <a-button v-if="!isUpdate" v-permission="['system:config:update']" type="primary" @click="onUpdate">
 | 
				
			||||||
@@ -220,8 +186,7 @@ onMounted(() => {
 | 
				
			|||||||
  margin-bottom: 5px;
 | 
					  margin-bottom: 5px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:deep(.form .arco-input-wrapper),
 | 
					.input-width, :deep(.arco-select-view-single) {
 | 
				
			||||||
:deep(.arco-select-view-single) {
 | 
					 | 
				
			||||||
  width: 220px;
 | 
					  width: 220px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,49 +9,35 @@
 | 
				
			|||||||
      :layout="width >= 500 ? 'horizontal' : 'vertical'"
 | 
					      :layout="width >= 500 ? 'horizontal' : 'vertical'"
 | 
				
			||||||
      :disabled="!isUpdate"
 | 
					      :disabled="!isUpdate"
 | 
				
			||||||
      scroll-to-first-error
 | 
					      scroll-to-first-error
 | 
				
			||||||
      class="form"
 | 
					 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        field="PASSWORD_ERROR_LOCK_COUNT"
 | 
					        field="PASSWORD_ERROR_LOCK_COUNT" :label="securityConfig.PASSWORD_ERROR_LOCK_COUNT.name"
 | 
				
			||||||
        :label="securityConfig.PASSWORD_ERROR_LOCK_COUNT.name"
 | 
					        :help="securityConfig.PASSWORD_ERROR_LOCK_COUNT.description" hide-asterisk
 | 
				
			||||||
        :help="securityConfig.PASSWORD_ERROR_LOCK_COUNT.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number
 | 
					        <a-input-number
 | 
				
			||||||
          v-model="form.PASSWORD_ERROR_LOCK_COUNT"
 | 
					          v-model="form.PASSWORD_ERROR_LOCK_COUNT" class="input-width" :default-value="0" :precision="0"
 | 
				
			||||||
          :default-value="0"
 | 
					          :min="0" :max="10"
 | 
				
			||||||
          :precision="0"
 | 
					 | 
				
			||||||
          :min="0"
 | 
					 | 
				
			||||||
          :max="10"
 | 
					 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #append>次</template>
 | 
					          <template #append>次</template>
 | 
				
			||||||
        </a-input-number>
 | 
					        </a-input-number>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        field="PASSWORD_ERROR_LOCK_MINUTES"
 | 
					        field="PASSWORD_ERROR_LOCK_MINUTES" :label="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.name"
 | 
				
			||||||
        :label="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.name"
 | 
					        :help="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.description" hide-asterisk
 | 
				
			||||||
        :help="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number
 | 
					        <a-input-number
 | 
				
			||||||
          v-model="form.PASSWORD_ERROR_LOCK_MINUTES"
 | 
					          v-model="form.PASSWORD_ERROR_LOCK_MINUTES" class="input-width" :precision="0" :min="1"
 | 
				
			||||||
          :precision="0"
 | 
					 | 
				
			||||||
          :min="1"
 | 
					 | 
				
			||||||
          :max="1440"
 | 
					          :max="1440"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #append>分钟</template>
 | 
					          <template #append>分钟</template>
 | 
				
			||||||
        </a-input-number>
 | 
					        </a-input-number>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        field="PASSWORD_EXPIRATION_DAYS"
 | 
					        field="PASSWORD_EXPIRATION_DAYS" :label="securityConfig.PASSWORD_EXPIRATION_DAYS.name"
 | 
				
			||||||
        :label="securityConfig.PASSWORD_EXPIRATION_DAYS.name"
 | 
					        :help="securityConfig.PASSWORD_EXPIRATION_DAYS.description" hide-asterisk
 | 
				
			||||||
        :help="securityConfig.PASSWORD_EXPIRATION_DAYS.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number
 | 
					        <a-input-number
 | 
				
			||||||
          v-model="form.PASSWORD_EXPIRATION_DAYS"
 | 
					          v-model="form.PASSWORD_EXPIRATION_DAYS" class="input-width" :precision="0" :min="0"
 | 
				
			||||||
          :precision="0"
 | 
					 | 
				
			||||||
          :min="0"
 | 
					 | 
				
			||||||
          :max="999"
 | 
					          :max="999"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #append>天</template>
 | 
					          <template #append>天</template>
 | 
				
			||||||
@@ -59,62 +45,43 @@
 | 
				
			|||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        :label="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.name"
 | 
					        :label="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.name"
 | 
				
			||||||
        field="PASSWORD_EXPIRATION_WARNING_DAYS"
 | 
					        field="PASSWORD_EXPIRATION_WARNING_DAYS" :help="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.description"
 | 
				
			||||||
        :help="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					        hide-asterisk
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number
 | 
					        <a-input-number
 | 
				
			||||||
          v-model="form.PASSWORD_EXPIRATION_WARNING_DAYS"
 | 
					          v-model="form.PASSWORD_EXPIRATION_WARNING_DAYS" class="input-width" :precision="0" :min="0"
 | 
				
			||||||
          :precision="0"
 | 
					 | 
				
			||||||
          :min="0"
 | 
					 | 
				
			||||||
          :max="998"
 | 
					          :max="998"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #append>天</template>
 | 
					          <template #append>天</template>
 | 
				
			||||||
        </a-input-number>
 | 
					        </a-input-number>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        field="PASSWORD_REPETITION_TIMES"
 | 
					        field="PASSWORD_REPETITION_TIMES" :label="securityConfig.PASSWORD_REPETITION_TIMES.name"
 | 
				
			||||||
        :label="securityConfig.PASSWORD_REPETITION_TIMES.name"
 | 
					        :help="securityConfig.PASSWORD_REPETITION_TIMES.description" hide-asterisk
 | 
				
			||||||
        :help="securityConfig.PASSWORD_REPETITION_TIMES.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number
 | 
					        <a-input-number
 | 
				
			||||||
          v-model="form.PASSWORD_REPETITION_TIMES"
 | 
					          v-model="form.PASSWORD_REPETITION_TIMES" class="input-width" :precision="0" :min="3"
 | 
				
			||||||
          :precision="0"
 | 
					 | 
				
			||||||
          :min="3"
 | 
					 | 
				
			||||||
          :max="32"
 | 
					          :max="32"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #append>次</template>
 | 
					          <template #append>次</template>
 | 
				
			||||||
        </a-input-number>
 | 
					        </a-input-number>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        field="PASSWORD_MIN_LENGTH"
 | 
					        field="PASSWORD_MIN_LENGTH" :label="securityConfig.PASSWORD_MIN_LENGTH.name"
 | 
				
			||||||
        :label="securityConfig.PASSWORD_MIN_LENGTH.name"
 | 
					        :help="securityConfig.PASSWORD_MIN_LENGTH.description" hide-asterisk
 | 
				
			||||||
        :help="securityConfig.PASSWORD_MIN_LENGTH.description"
 | 
					 | 
				
			||||||
        hide-asterisk
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-input-number
 | 
					        <a-input-number v-model="form.PASSWORD_MIN_LENGTH" class="input-width" :precision="0" :min="8" :max="32" />
 | 
				
			||||||
          v-model="form.PASSWORD_MIN_LENGTH"
 | 
					 | 
				
			||||||
          :precision="0"
 | 
					 | 
				
			||||||
          :min="8"
 | 
					 | 
				
			||||||
          :max="32"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item
 | 
				
			||||||
        field="PASSWORD_ALLOW_CONTAIN_USERNAME"
 | 
					        field="PASSWORD_ALLOW_CONTAIN_USERNAME"
 | 
				
			||||||
        :label="securityConfig.PASSWORD_ALLOW_CONTAIN_USERNAME.name"
 | 
					        :label="securityConfig.PASSWORD_ALLOW_CONTAIN_USERNAME.name"
 | 
				
			||||||
        :help="securityConfig.PASSWORD_ALLOW_CONTAIN_USERNAME.description"
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <a-switch v-model="form.PASSWORD_ALLOW_CONTAIN_USERNAME" type="round" :checked-value="1" :unchecked-value="0">
 | 
					        <a-switch v-model="form.PASSWORD_ALLOW_CONTAIN_USERNAME" type="round" :checked-value="1" :unchecked-value="0">
 | 
				
			||||||
          <template #checked>是</template>
 | 
					          <template #checked>是</template>
 | 
				
			||||||
          <template #unchecked>否</template>
 | 
					          <template #unchecked>否</template>
 | 
				
			||||||
        </a-switch>
 | 
					        </a-switch>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="PASSWORD_REQUIRE_SYMBOLS" :label="securityConfig.PASSWORD_REQUIRE_SYMBOLS.name">
 | 
				
			||||||
        field="PASSWORD_REQUIRE_SYMBOLS"
 | 
					 | 
				
			||||||
        :label="securityConfig.PASSWORD_REQUIRE_SYMBOLS.name"
 | 
					 | 
				
			||||||
        :help="securityConfig.PASSWORD_REQUIRE_SYMBOLS.description"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-switch v-model="form.PASSWORD_REQUIRE_SYMBOLS" type="round" :checked-value="1" :unchecked-value="0">
 | 
					        <a-switch v-model="form.PASSWORD_REQUIRE_SYMBOLS" type="round" :checked-value="1" :unchecked-value="0">
 | 
				
			||||||
          <template #checked>是</template>
 | 
					          <template #checked>是</template>
 | 
				
			||||||
          <template #unchecked>否</template>
 | 
					          <template #unchecked>否</template>
 | 
				
			||||||
@@ -171,7 +138,7 @@ const rules: FormInstance['rules'] = {
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
      validator: (value, callback) => {
 | 
					      validator: (value, callback) => {
 | 
				
			||||||
        if (form.PASSWORD_EXPIRATION_DAYS > 0 && value >= form.PASSWORD_EXPIRATION_DAYS) {
 | 
					        if (form.PASSWORD_EXPIRATION_DAYS > 0 && value >= form.PASSWORD_EXPIRATION_DAYS) {
 | 
				
			||||||
          callback('密码到期提醒时间应小于密码有效期')
 | 
					          callback('密码到期前的提示时间应小于密码有效期')
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          callback()
 | 
					          callback()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -271,7 +238,7 @@ onMounted(() => {
 | 
				
			|||||||
  margin-bottom: 5px;
 | 
					  margin-bottom: 5px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:deep(.form .arco-input-wrapper) {
 | 
					.input-width {
 | 
				
			||||||
  width: 200px;
 | 
					  width: 200px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,261 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
  <a-spin :loading="loading">
 | 
					 | 
				
			||||||
    <a-form
 | 
					 | 
				
			||||||
      ref="formRef"
 | 
					 | 
				
			||||||
      :model="form"
 | 
					 | 
				
			||||||
      :rules="form.STORAGE_DEFAULT === 'LOCAL' ? localRules : ossRules"
 | 
					 | 
				
			||||||
      auto-label-width
 | 
					 | 
				
			||||||
      label-align="left"
 | 
					 | 
				
			||||||
      :layout="width >= 500 ? 'horizontal' : 'vertical'"
 | 
					 | 
				
			||||||
      :disabled="!isUpdate"
 | 
					 | 
				
			||||||
      scroll-to-first-error
 | 
					 | 
				
			||||||
      class="form"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      <!-- 默认存储 -->
 | 
					 | 
				
			||||||
      <a-form-item
 | 
					 | 
				
			||||||
        field="STORAGE_DEFAULT"
 | 
					 | 
				
			||||||
        :label="storageConfig.STORAGE_DEFAULT.name"
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-radio-group v-model="form.STORAGE_DEFAULT">
 | 
					 | 
				
			||||||
          <a-radio value="LOCAL">本地存储</a-radio>
 | 
					 | 
				
			||||||
          <a-radio value="OSS">对象存储</a-radio>
 | 
					 | 
				
			||||||
        </a-radio-group>
 | 
					 | 
				
			||||||
      </a-form-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <fieldset>
 | 
					 | 
				
			||||||
        <legend>本地存储配置</legend>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_LOCAL_BUCKET"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_LOCAL_BUCKET.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_LOCAL_BUCKET.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input v-model="form.STORAGE_LOCAL_BUCKET" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_LOCAL_ENDPOINT"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_LOCAL_ENDPOINT.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_LOCAL_ENDPOINT.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input v-model="form.STORAGE_LOCAL_ENDPOINT" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
      </fieldset>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <fieldset>
 | 
					 | 
				
			||||||
        <legend>对象存储配置</legend>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_OSS_ACCESS_KEY"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_OSS_ACCESS_KEY.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_OSS_ACCESS_KEY.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input v-model="form.STORAGE_OSS_ACCESS_KEY" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_OSS_SECRET_KEY"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_OSS_SECRET_KEY.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_OSS_SECRET_KEY.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input-password v-model="form.STORAGE_OSS_SECRET_KEY" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_OSS_BUCKET"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_OSS_BUCKET.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_OSS_BUCKET.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input v-model="form.STORAGE_OSS_BUCKET" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_OSS_ENDPOINT"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_OSS_ENDPOINT.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_OSS_ENDPOINT.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input v-model="form.STORAGE_OSS_ENDPOINT" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
        <a-form-item
 | 
					 | 
				
			||||||
          field="STORAGE_OSS_REGION"
 | 
					 | 
				
			||||||
          :label="storageConfig.STORAGE_OSS_REGION.name"
 | 
					 | 
				
			||||||
          :help="storageConfig.STORAGE_OSS_REGION.description"
 | 
					 | 
				
			||||||
          hide-asterisk
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <a-input v-model="form.STORAGE_OSS_REGION" />
 | 
					 | 
				
			||||||
        </a-form-item>
 | 
					 | 
				
			||||||
      </fieldset>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <!-- 操作按钮 -->
 | 
					 | 
				
			||||||
      <a-space style="margin-bottom: 16px">
 | 
					 | 
				
			||||||
        <a-button v-if="!isUpdate" v-permission="['system:config:update']" type="primary" @click="onUpdate">
 | 
					 | 
				
			||||||
          <template #icon>
 | 
					 | 
				
			||||||
            <icon-edit />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
          修改
 | 
					 | 
				
			||||||
        </a-button>
 | 
					 | 
				
			||||||
        <a-button v-if="!isUpdate" v-permission="['system:config:reset']" @click="onResetValue">
 | 
					 | 
				
			||||||
          <template #icon>
 | 
					 | 
				
			||||||
            <icon-undo />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
          恢复默认
 | 
					 | 
				
			||||||
        </a-button>
 | 
					 | 
				
			||||||
        <a-button v-if="isUpdate" type="primary" @click="handleSave">
 | 
					 | 
				
			||||||
          <template #icon>
 | 
					 | 
				
			||||||
            <icon-save />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
          保存
 | 
					 | 
				
			||||||
        </a-button>
 | 
					 | 
				
			||||||
        <a-button v-if="isUpdate" @click="reset">
 | 
					 | 
				
			||||||
          <template #icon>
 | 
					 | 
				
			||||||
            <icon-refresh />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
          重置
 | 
					 | 
				
			||||||
        </a-button>
 | 
					 | 
				
			||||||
        <a-button v-if="isUpdate" @click="handleCancel">
 | 
					 | 
				
			||||||
          <template #icon>
 | 
					 | 
				
			||||||
            <icon-undo />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
          取消
 | 
					 | 
				
			||||||
        </a-button>
 | 
					 | 
				
			||||||
      </a-space>
 | 
					 | 
				
			||||||
    </a-form>
 | 
					 | 
				
			||||||
  </a-spin>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script setup lang="ts">
 | 
					 | 
				
			||||||
import { useWindowSize } from '@vueuse/core'
 | 
					 | 
				
			||||||
import { type FormInstance, Message, Modal } from '@arco-design/web-vue'
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  type OptionResp,
 | 
					 | 
				
			||||||
  type SecurityConfig,
 | 
					 | 
				
			||||||
  type StorageConfig,
 | 
					 | 
				
			||||||
  listOption,
 | 
					 | 
				
			||||||
  resetOptionValue,
 | 
					 | 
				
			||||||
  updateOption,
 | 
					 | 
				
			||||||
} from '@/apis/system'
 | 
					 | 
				
			||||||
import { useResetReactive } from '@/hooks'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
defineOptions({ name: 'StorageSetting' })
 | 
					 | 
				
			||||||
const { width } = useWindowSize()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const loading = ref<boolean>(false)
 | 
					 | 
				
			||||||
const formRef = ref<FormInstance>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const [form] = useResetReactive({
 | 
					 | 
				
			||||||
  STORAGE_DEFAULT: 'LOCAL', // 默认选中本地存储
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_BUCKET: '',
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_ENDPOINT: '',
 | 
					 | 
				
			||||||
  STORAGE_OSS_ACCESS_KEY: '',
 | 
					 | 
				
			||||||
  STORAGE_OSS_SECRET_KEY: '',
 | 
					 | 
				
			||||||
  STORAGE_OSS_BUCKET: '',
 | 
					 | 
				
			||||||
  STORAGE_OSS_ENDPOINT: '',
 | 
					 | 
				
			||||||
  STORAGE_OSS_REGION: '',
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const localRules: FormInstance['rules'] = {
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_BUCKET: [{ required: true, message: '请输入本地存储路径' }],
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_ENDPOINT: [{ required: true, message: '请输入本地资源访问地址' }],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ossRules: FormInstance['rules'] = {
 | 
					 | 
				
			||||||
  STORAGE_OSS_ACCESS_KEY: [{ required: true, message: '请输入Access Key' }],
 | 
					 | 
				
			||||||
  STORAGE_OSS_SECRET_KEY: [{ required: true, message: '请输入Secret Key' }],
 | 
					 | 
				
			||||||
  STORAGE_OSS_BUCKET: [{ required: true, message: '请输入对象存储桶名称' }],
 | 
					 | 
				
			||||||
  STORAGE_OSS_ENDPOINT: [{ required: true, message: '请输入对象存储终端节点' }],
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const storageConfig = ref<StorageConfig>({
 | 
					 | 
				
			||||||
  STORAGE_DEFAULT: {},
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_BUCKET: {},
 | 
					 | 
				
			||||||
  STORAGE_LOCAL_ENDPOINT: {},
 | 
					 | 
				
			||||||
  STORAGE_OSS_ACCESS_KEY: {},
 | 
					 | 
				
			||||||
  STORAGE_OSS_SECRET_KEY: {},
 | 
					 | 
				
			||||||
  STORAGE_OSS_BUCKET: {},
 | 
					 | 
				
			||||||
  STORAGE_OSS_ENDPOINT: {},
 | 
					 | 
				
			||||||
  STORAGE_OSS_REGION: {},
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const reset = () => {
 | 
					 | 
				
			||||||
  formRef.value?.resetFields()
 | 
					 | 
				
			||||||
  Object.keys(form).forEach((key) => {
 | 
					 | 
				
			||||||
    form[key] = storageConfig.value[key]?.value || form[key] // 兜底设置默认值
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const isUpdate = ref(false)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const onUpdate = () => {
 | 
					 | 
				
			||||||
  isUpdate.value = true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const handleCancel = () => {
 | 
					 | 
				
			||||||
  reset()
 | 
					 | 
				
			||||||
  isUpdate.value = false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const queryForm = { category: 'STORAGE' }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getDataList = async () => {
 | 
					 | 
				
			||||||
  loading.value = true
 | 
					 | 
				
			||||||
  const { data } = await listOption(queryForm)
 | 
					 | 
				
			||||||
  storageConfig.value = data.reduce((obj: SecurityConfig, option: OptionResp) => {
 | 
					 | 
				
			||||||
    obj[option.code] = { ...option, value: option.value }
 | 
					 | 
				
			||||||
    return obj
 | 
					 | 
				
			||||||
  }, {})
 | 
					 | 
				
			||||||
  handleCancel()
 | 
					 | 
				
			||||||
  loading.value = false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const handleSave = async () => {
 | 
					 | 
				
			||||||
  const isInvalid = await formRef.value?.validate()
 | 
					 | 
				
			||||||
  if (isInvalid) return
 | 
					 | 
				
			||||||
  await updateOption(
 | 
					 | 
				
			||||||
    Object.entries(form).map(([key, value]) => ({ id: storageConfig.value[key].id, code: key, value })),
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  await getDataList()
 | 
					 | 
				
			||||||
  Message.success('保存成功')
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const handleResetValue = async () => {
 | 
					 | 
				
			||||||
  await resetOptionValue(queryForm)
 | 
					 | 
				
			||||||
  Message.success('恢复成功')
 | 
					 | 
				
			||||||
  await getDataList()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const onResetValue = () => {
 | 
					 | 
				
			||||||
  Modal.warning({
 | 
					 | 
				
			||||||
    title: '警告',
 | 
					 | 
				
			||||||
    content: '确认恢复存储配置为默认值吗?',
 | 
					 | 
				
			||||||
    hideCancel: false,
 | 
					 | 
				
			||||||
    maskClosable: false,
 | 
					 | 
				
			||||||
    onOk: handleResetValue,
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
onMounted(() => {
 | 
					 | 
				
			||||||
  getDataList()
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style scoped lang="scss">
 | 
					 | 
				
			||||||
:deep(.form .arco-input-wrapper) {
 | 
					 | 
				
			||||||
  width: 400px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fieldset {
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  width: fit-content;
 | 
					 | 
				
			||||||
  min-width: 0;
 | 
					 | 
				
			||||||
  padding: 15px;
 | 
					 | 
				
			||||||
  margin-bottom: 15px;
 | 
					 | 
				
			||||||
  border: 1px solid var(--color-neutral-3);
 | 
					 | 
				
			||||||
  border-radius: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
fieldset legend {
 | 
					 | 
				
			||||||
  color: rgb(var(--gray-10));
 | 
					 | 
				
			||||||
  padding: 2px 5px 2px 5px;
 | 
					 | 
				
			||||||
  border: 1px solid var(--color-neutral-3);
 | 
					 | 
				
			||||||
  border-radius: 3px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
@@ -6,19 +6,16 @@
 | 
				
			|||||||
      </a-space>
 | 
					      </a-space>
 | 
				
			||||||
    </a-row> -->
 | 
					    </a-row> -->
 | 
				
			||||||
    <a-tabs v-model:active-key="activeKey" type="card-gutter" size="large" @change="change">
 | 
					    <a-tabs v-model:active-key="activeKey" type="card-gutter" size="large" @change="change">
 | 
				
			||||||
      <a-tab-pane key="site">
 | 
					      <a-tab-pane key="1">
 | 
				
			||||||
        <template #title><icon-apps /> 网站配置</template>
 | 
					        <template #title><icon-settings /> 基础配置</template>
 | 
				
			||||||
      </a-tab-pane>
 | 
					      </a-tab-pane>
 | 
				
			||||||
      <a-tab-pane key="security">
 | 
					      <a-tab-pane key="2">
 | 
				
			||||||
        <template #title><icon-safe /> 安全配置</template>
 | 
					        <template #title><icon-safe /> 安全配置</template>
 | 
				
			||||||
      </a-tab-pane>
 | 
					      </a-tab-pane>
 | 
				
			||||||
      <a-tab-pane key="mail">
 | 
					      <a-tab-pane key="3">
 | 
				
			||||||
        <template #title><icon-email /> 邮件配置</template>
 | 
					        <template #title><icon-email /> 邮件配置</template>
 | 
				
			||||||
      </a-tab-pane>
 | 
					      </a-tab-pane>
 | 
				
			||||||
      <a-tab-pane key="storage">
 | 
					      <a-tab-pane key="4">
 | 
				
			||||||
        <template #title><icon-storage /> 存储配置</template>
 | 
					 | 
				
			||||||
      </a-tab-pane>
 | 
					 | 
				
			||||||
      <a-tab-pane key="login">
 | 
					 | 
				
			||||||
        <template #title><icon-lock /> 登录配置</template>
 | 
					        <template #title><icon-lock /> 登录配置</template>
 | 
				
			||||||
      </a-tab-pane>
 | 
					      </a-tab-pane>
 | 
				
			||||||
    </a-tabs>
 | 
					    </a-tabs>
 | 
				
			||||||
@@ -30,37 +27,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { useRoute, useRouter } from 'vue-router'
 | 
					import { useRoute, useRouter } from 'vue-router'
 | 
				
			||||||
import SiteSetting from './components/SiteSetting.vue'
 | 
					import BasicSetting from './components/BasicSetting.vue'
 | 
				
			||||||
import SecuritySetting from './components/SecuritySetting.vue'
 | 
					import SecuritySetting from './components/SecuritySetting.vue'
 | 
				
			||||||
import MailSetting from './components/MailSetting.vue'
 | 
					import MailSetting from './components/MailSetting.vue'
 | 
				
			||||||
import LoginSetting from './components/LoginSetting.vue'
 | 
					import LoginSetting from './components/LoginSetting.vue'
 | 
				
			||||||
import StorageSetting from './components/StorageSetting.vue'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({ name: 'SystemConfig' })
 | 
					defineOptions({ name: 'SystemConfig' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PanMap: Record<string, Component> = {
 | 
					const PanMap: Record<string, Component> = {
 | 
				
			||||||
  site: SiteSetting,
 | 
					  1: BasicSetting,
 | 
				
			||||||
  security: SecuritySetting,
 | 
					  2: SecuritySetting,
 | 
				
			||||||
  mail: MailSetting,
 | 
					  3: MailSetting,
 | 
				
			||||||
  storage: StorageSetting,
 | 
					  4: LoginSetting,
 | 
				
			||||||
  login: LoginSetting,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute()
 | 
					const route = useRoute()
 | 
				
			||||||
const router = useRouter()
 | 
					const router = useRouter()
 | 
				
			||||||
const activeKey = ref('site')
 | 
					const activeKey = ref('1')
 | 
				
			||||||
watch(
 | 
					watch(
 | 
				
			||||||
  () => route.query,
 | 
					  () => route.query,
 | 
				
			||||||
  () => {
 | 
					  () => {
 | 
				
			||||||
    if (route.query.tab) {
 | 
					    if (route.query.tabKey) {
 | 
				
			||||||
      activeKey.value = String(route.query.tab)
 | 
					      activeKey.value = String(route.query.tabKey)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  { immediate: true },
 | 
					  { immediate: true },
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
const change = (key: string | number) => {
 | 
					const change = (key: string | number) => {
 | 
				
			||||||
  activeKey.value = key as string
 | 
					  activeKey.value = key as string
 | 
				
			||||||
  router.replace({ path: route.path, query: { tab: key } })
 | 
					  router.replace({ path: route.path, query: { tabKey: key } })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										198
									
								
								src/views/system/storage/StorageAddDrawer.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/views/system/storage/StorageAddDrawer.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,198 @@
 | 
				
			|||||||
 | 
					<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="请选择类型" :disabled="isUpdate" />
 | 
				
			||||||
 | 
					      </a-form-item>
 | 
				
			||||||
 | 
					      <a-form-item v-if="form.type === 1" label="访问密钥" field="accessKey">
 | 
				
			||||||
 | 
					        <a-input v-model.trim="form.accessKey" placeholder="请输入访问密钥" :max-length="255" />
 | 
				
			||||||
 | 
					      </a-form-item>
 | 
				
			||||||
 | 
					      <a-form-item v-if="form.type === 1" label="私有密钥" field="secretKey">
 | 
				
			||||||
 | 
					        <a-input
 | 
				
			||||||
 | 
					          v-model.trim="form.secretKey"
 | 
				
			||||||
 | 
					          placeholder="请输入私有密钥"
 | 
				
			||||||
 | 
					          :max-length="255"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </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="请输入域名" />
 | 
				
			||||||
 | 
					        <template #extra>
 | 
				
			||||||
 | 
					          <div v-if="defaultDomain">
 | 
				
			||||||
 | 
					            <span>留空默认域名:{{ defaultDomain }}</span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </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 { type FormInstance, Message } from '@arco-design/web-vue'
 | 
				
			||||||
 | 
					import { useWindowSize } from '@vueuse/core'
 | 
				
			||||||
 | 
					import { addStorage, getStorage, updateStorage } from '@/apis/system/storage'
 | 
				
			||||||
 | 
					import { useResetReactive } from '@/hooks'
 | 
				
			||||||
 | 
					import { useDict } from '@/hooks/app'
 | 
				
			||||||
 | 
					import { encryptByRsa } from '@/utils/encrypt'
 | 
				
			||||||
 | 
					import { isIPv4 } from '@/utils/validate'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emit = defineEmits<{
 | 
				
			||||||
 | 
					  (e: 'save-success'): void
 | 
				
			||||||
 | 
					}>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { width } = useWindowSize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const dataId = ref('')
 | 
				
			||||||
 | 
					const visible = ref(false)
 | 
				
			||||||
 | 
					const isUpdate = computed(() => !!dataId.value)
 | 
				
			||||||
 | 
					const title = computed(() => (isUpdate.value ? '修改存储' : '新增存储'))
 | 
				
			||||||
 | 
					const formRef = ref<FormInstance>()
 | 
				
			||||||
 | 
					const { storage_type_enum } = useDict('storage_type_enum')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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] = useResetReactive({
 | 
				
			||||||
 | 
					  type: 2,
 | 
				
			||||||
 | 
					  isDefault: false,
 | 
				
			||||||
 | 
					  sort: 999,
 | 
				
			||||||
 | 
					  status: 1,
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					/** 获取url的protocol和endpoint */
 | 
				
			||||||
 | 
					const stripProtocol = (url: string): { endpoint: string, protocol: string } => {
 | 
				
			||||||
 | 
					  if (url.startsWith('http://')) {
 | 
				
			||||||
 | 
					    return { endpoint: url.substring(7), protocol: 'http://' }
 | 
				
			||||||
 | 
					  } else if (url.startsWith('https://')) {
 | 
				
			||||||
 | 
					    return { endpoint: url.substring(8), protocol: 'https://' }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return { endpoint: url, protocol: 'http://' }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 按规则拼接当前默认domain */
 | 
				
			||||||
 | 
					const defaultDomain = computed(() => {
 | 
				
			||||||
 | 
					  const { endpoint: initialEndpoint, bucketName, domain, type } = form
 | 
				
			||||||
 | 
					  if (domain || type !== 1 || !initialEndpoint || !bucketName) {
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const { endpoint, protocol } = stripProtocol(initialEndpoint)
 | 
				
			||||||
 | 
					  return isIPv4(endpoint) ? `${protocol}${endpoint}/${bucketName}/` : `${protocol}${bucketName}.${endpoint}/`
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 重置
 | 
				
			||||||
 | 
					const reset = () => {
 | 
				
			||||||
 | 
					  formRef.value?.resetFields()
 | 
				
			||||||
 | 
					  resetForm()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 保存
 | 
				
			||||||
 | 
					const save = async () => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const isInvalid = await formRef.value?.validate()
 | 
				
			||||||
 | 
					    if (isInvalid) return false
 | 
				
			||||||
 | 
					    const data = {
 | 
				
			||||||
 | 
					      ...form,
 | 
				
			||||||
 | 
					      secretKey: form.type === 1 && !form.secretKey.includes('*') ? encryptByRsa(form.secretKey) : null,
 | 
				
			||||||
 | 
					      domain: form.domain || defaultDomain.value,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (isUpdate.value) {
 | 
				
			||||||
 | 
					      await updateStorage(data, dataId.value)
 | 
				
			||||||
 | 
					      Message.success('修改成功')
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      await addStorage(data)
 | 
				
			||||||
 | 
					      Message.success('新增成功')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    emit('save-success')
 | 
				
			||||||
 | 
					    return true
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    return false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 新增
 | 
				
			||||||
 | 
					const onAdd = () => {
 | 
				
			||||||
 | 
					  reset()
 | 
				
			||||||
 | 
					  dataId.value = ''
 | 
				
			||||||
 | 
					  visible.value = true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 修改
 | 
				
			||||||
 | 
					const onUpdate = async (id: string) => {
 | 
				
			||||||
 | 
					  reset()
 | 
				
			||||||
 | 
					  dataId.value = id
 | 
				
			||||||
 | 
					  const { data } = await getStorage(id)
 | 
				
			||||||
 | 
					  Object.assign(form, data)
 | 
				
			||||||
 | 
					  visible.value = true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineExpose({ onAdd, onUpdate })
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										153
									
								
								src/views/system/storage/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/views/system/storage/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="gi_table_page">
 | 
				
			||||||
 | 
					    <GiTable
 | 
				
			||||||
 | 
					      title=""
 | 
				
			||||||
 | 
					      row-key="id"
 | 
				
			||||||
 | 
					      :data="dataList"
 | 
				
			||||||
 | 
					      :columns="columns"
 | 
				
			||||||
 | 
					      :loading="loading"
 | 
				
			||||||
 | 
					      :scroll="{ x: '100%', y: '100%', minWidth: 1300 }"
 | 
				
			||||||
 | 
					      :pagination="pagination"
 | 
				
			||||||
 | 
					      :disabled-tools="['size']"
 | 
				
			||||||
 | 
					      :disabled-column-keys="['name']"
 | 
				
			||||||
 | 
					      @refresh="search"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <template #toolbar-left>
 | 
				
			||||||
 | 
					        <a-input-search v-model="queryForm.description" placeholder="搜索名称/编码/描述" allow-clear @search="search" />
 | 
				
			||||||
 | 
					        <a-select
 | 
				
			||||||
 | 
					          v-model="queryForm.status"
 | 
				
			||||||
 | 
					          :options="DisEnableStatusList"
 | 
				
			||||||
 | 
					          placeholder="请选择状态"
 | 
				
			||||||
 | 
					          allow-clear
 | 
				
			||||||
 | 
					          style="width: 150px"
 | 
				
			||||||
 | 
					          @change="search"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <a-button @click="reset">
 | 
				
			||||||
 | 
					          <template #icon><icon-refresh /></template>
 | 
				
			||||||
 | 
					          <template #default>重置</template>
 | 
				
			||||||
 | 
					        </a-button>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <template #toolbar-right>
 | 
				
			||||||
 | 
					        <a-button v-permission="['system:storage:add']" type="primary" @click="onAdd">
 | 
				
			||||||
 | 
					          <template #icon><icon-plus /></template>
 | 
				
			||||||
 | 
					          <template #default>新增</template>
 | 
				
			||||||
 | 
					        </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>
 | 
				
			||||||
 | 
					          <a-link v-permission="['system:storage:update']" title="修改" @click="onUpdate(record)">修改</a-link>
 | 
				
			||||||
 | 
					          <a-link
 | 
				
			||||||
 | 
					            v-permission="['system:storage:delete']"
 | 
				
			||||||
 | 
					            status="danger"
 | 
				
			||||||
 | 
					            :disabled="record.isDefault"
 | 
				
			||||||
 | 
					            :title="record.isDefault ? '默认存储不能删除' : '删除'"
 | 
				
			||||||
 | 
					            @click="onDelete(record)"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            删除
 | 
				
			||||||
 | 
					          </a-link>
 | 
				
			||||||
 | 
					        </a-space>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </GiTable>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <StorageAddDrawer ref="StorageAddDrawerRef" @save-success="search" />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import StorageAddDrawer from './StorageAddDrawer.vue'
 | 
				
			||||||
 | 
					import { type StorageQuery, type StorageResp, deleteStorage, listStorage } from '@/apis/system/storage'
 | 
				
			||||||
 | 
					import type { TableInstanceColumns } from '@/components/GiTable/type'
 | 
				
			||||||
 | 
					import { DisEnableStatusList } from '@/constant/common'
 | 
				
			||||||
 | 
					import { useTable } from '@/hooks'
 | 
				
			||||||
 | 
					import { useDict } from '@/hooks/app'
 | 
				
			||||||
 | 
					import { isMobile } from '@/utils'
 | 
				
			||||||
 | 
					import has from '@/utils/has'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({ name: 'SystemStorage' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { storage_type_enum } = useDict('storage_type_enum')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const queryForm = reactive<StorageQuery>({
 | 
				
			||||||
 | 
					  sort: ['createTime,desc'],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const {
 | 
				
			||||||
 | 
					  tableData: dataList,
 | 
				
			||||||
 | 
					  loading,
 | 
				
			||||||
 | 
					  pagination,
 | 
				
			||||||
 | 
					  search,
 | 
				
			||||||
 | 
					  handleDelete,
 | 
				
			||||||
 | 
					} = useTable((page) => listStorage({ ...queryForm, ...page }), { immediate: true })
 | 
				
			||||||
 | 
					const columns: TableInstanceColumns[] = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    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: '状态', dataIndex: 'status', slotName: 'status', align: 'center' },
 | 
				
			||||||
 | 
					  { title: '类型', dataIndex: 'type', slotName: 'type', align: 'center', ellipsis: true, tooltip: true },
 | 
				
			||||||
 | 
					  { 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', ellipsis: true, tooltip: true, show: false },
 | 
				
			||||||
 | 
					  { title: '创建时间', dataIndex: 'createTime', width: 180 },
 | 
				
			||||||
 | 
					  { title: '修改人', dataIndex: 'updateUserString', ellipsis: true, tooltip: true, show: false },
 | 
				
			||||||
 | 
					  { title: '修改时间', dataIndex: 'updateTime', width: 180, show: false },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    title: '操作',
 | 
				
			||||||
 | 
					    dataIndex: 'action',
 | 
				
			||||||
 | 
					    slotName: 'action',
 | 
				
			||||||
 | 
					    width: 130,
 | 
				
			||||||
 | 
					    align: 'center',
 | 
				
			||||||
 | 
					    fixed: !isMobile() ? 'right' : undefined,
 | 
				
			||||||
 | 
					    show: has.hasPermOr(['system:storage:update', 'system:storage:delete']),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 重置
 | 
				
			||||||
 | 
					const reset = () => {
 | 
				
			||||||
 | 
					  queryForm.description = undefined
 | 
				
			||||||
 | 
					  queryForm.status = undefined
 | 
				
			||||||
 | 
					  search()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 删除
 | 
				
			||||||
 | 
					const onDelete = (record: StorageResp) => {
 | 
				
			||||||
 | 
					  return handleDelete(() => deleteStorage(record.id), {
 | 
				
			||||||
 | 
					    content: `是否确定删除存储「${record.name}」?`,
 | 
				
			||||||
 | 
					    showModal: true,
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StorageAddDrawerRef = ref<InstanceType<typeof StorageAddDrawer>>()
 | 
				
			||||||
 | 
					// 新增
 | 
				
			||||||
 | 
					const onAdd = () => {
 | 
				
			||||||
 | 
					  StorageAddDrawerRef.value?.onAdd()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 修改
 | 
				
			||||||
 | 
					const onUpdate = (record: StorageResp) => {
 | 
				
			||||||
 | 
					  StorageAddDrawerRef.value?.onUpdate(record.id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped lang="scss"></style>
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/views/system/storage/type.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/views/system/storage/type.ts
									
									
									
									
									
										Normal 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user