Files
mp-10584/src/views/system/setting/components/upload.vue
赵忠林 d1b7943e5d refactor(system): 重构系统设置组件以支持按键更新
- 将 updateSetting 替换为 updateSettingByKey 方法调用
- 为所有设置组件添加默认的 settingId 和 settingKey 初始值
- 在表单提交前确保 settingKey 正确赋值
- 优化 watch 数据监听逻辑以支持按键匹配
- 重构数据处理流程以支持数组和对象格式的数据
- 统一错误处理和边界条件检查
- 修复表单重置和初始化逻辑
- 标准化各组件中的 settingKey 默认值设定
2026-02-27 18:37:37 +08:00

304 lines
9.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-card :bordered="false">
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 3, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="styleResponsive ? { md: 9, sm: 19, xs: 24 } : { flex: '1' }"
>
<a-form-item label="默认上传方式" name="uploadMethod">
<a-radio-group v-model:value="form.uploadMethod" @click="onMethod">
<a-radio-button disabled value="file">本地</a-radio-button>
<a-radio-button value="oss">阿里云</a-radio-button>
<a-radio-button disabled value="cos">腾讯云</a-radio-button>
<a-radio-button disabled value="kodo">七牛云</a-radio-button>
</a-radio-group>
</a-form-item>
<template v-if="form.uploadMethod !== 'file'">
<a-form-item label="存储空间名称" name="bucketName">
<a-input v-model:value="form.bucketName" placeholder="存储空间名称" />
</a-form-item>
<a-form-item label="Region域名" name="bucketEndpoint">
<a-input
v-model:value="form.bucketEndpoint"
placeholder="https://oss-cn-shenzhen.aliyuncs.com"
/>
</a-form-item>
<a-form-item label="accessKeyId" name="accessKeyId">
<a-input v-model:value="form.accessKeyId" placeholder="accessKeyId" />
</a-form-item>
<a-form-item label="accessKeySecret" name="accessKeySecret">
<a-input-password
v-model:value="form.accessKeySecret"
placeholder="accessKeySecret"
/>
</a-form-item>
<a-form-item label="空间域名" name="bucketDomain">
<a-input
v-model:value="form.bucketDomain"
placeholder="https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com"
/>
</a-form-item>
</template>
<!-- 私有云 -->
<template v-if="form.uploadMethod === 'file'">
<a-form-item label="域名" name="fileUrl">
<a-input-group compact>
<a-input
v-model:value="form.fileUrl"
placeholder="请输入文件服务器域名"
style="width: calc(100% - 50px)"
/>
<a-tooltip title="复制">
<a-button @click="onCopyText(`https://file.wsdns.cn`)">
<template #icon><CopyOutlined /></template>
</a-button>
</a-tooltip>
</a-input-group>
</a-form-item>
</template>
<!-- 阿里云 -->
<template v-if="form.uploadMethod === 'oss'">
<a-form-item label="去申请">
<a href="https://oss.console.aliyun.com" target="_blank"
>https://oss.console.aliyun.com</a
>
</a-form-item>
</template>
<!-- 腾讯云 -->
<template v-if="form.uploadMethod === 'cos'">
<a-form-item label="去申请">
<a href="https://cloud.tencent.com/product/cos" target="_blank"
>https://cloud.tencent.com/product/cos</a
>
</a-form-item>
</template>
<!-- 七牛云 -->
<template v-if="form.uploadMethod === 'kodo'">
<a-form-item label="去申请">
<a href="https://www.qiniu.com/products/kodo" target="_blank"
>https://www.qiniu.com/products/kodo</a
>
</a-form-item>
</template>
<a-form-item label="使用临时存储" v-if="form.uploadMethod === 'oss'">
<div style="margin-top: 6px">
<a class="" @click="onDemoOss">立即填入</a>
<div class="ele-text-secondary"
>仅供体验及测试使用空间大小和有流量有一定限制不推荐使用正式使用请单独申请独立的云存储</div
>
</div>
</a-form-item>
<a-form-item label="操作">
<a-button type="primary" class="ele-btn-icon" @click="save">
<span>保存</span>
</a-button>
</a-form-item>
</a-form>
</a-card>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue';
import { copyText } from '@/utils/common';
import { message } from 'ant-design-vue';
import { CopyOutlined } from '@ant-design/icons-vue';
import { Setting } from '@/api/system/setting/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { FormInstance } from 'ant-design-vue/es/form';
import useFormData from '@/utils/use-form-data';
import { addSetting, updateSettingByKey } from '@/api/system/setting';
const props = defineProps<{
value?: string;
// 修改回显的数据
data?: Setting | null;
}>();
// 保存字段信息(设定好key和描述,content里的字段是随意加的会自动转为json保存到数据库)
const settingKey = ref('upload');
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
// 是否是修改
const isUpdate = ref(false);
//
const formRef = ref<FormInstance | null>(null);
// 表单数据
const { form, resetFields, assignFields } = useFormData<Setting>({
settingId: undefined,
settingKey: settingKey.value,
uploadMethod: 'oss',
fileUrl: 'https://file.wsdns.cn',
bucketName: '',
bucketEndpoint: '',
accessKeyId: '',
accessKeySecret: '',
bucketDomain: '',
tenantId: localStorage.getItem('TenantId')
});
// 表单验证规则
const rules = reactive({
uploadMethod: [
{
required: true,
type: 'string',
message: '请设置上传方式',
trigger: 'blur'
}
],
bucketName: [
{
required: true,
type: 'string',
message: '请填写存储空间名称',
trigger: 'blur'
}
],
accessKeyId: [
{
required: true,
type: 'string',
message: '请填写accessKeyId',
trigger: 'blur'
}
],
accessKeySecret: [
{
required: true,
type: 'string',
message: '请填写accessKeySecret',
trigger: 'blur'
}
],
bucketDomain: [
{
required: true,
type: 'string',
message: '请填写存储空间域名',
trigger: 'blur'
}
]
});
const onCopyText = (text) => {
copyText(text);
};
const onMethod = (_e) => {
resetFields();
};
const onDemoOss = () => {
form.uploadMethod = 'oss';
form.bucketName = 'oss-gxwebsoft';
form.bucketEndpoint = 'https://oss-cn-shenzhen.aliyuncs.com';
form.accessKeyId = 'LTAI4GKGZ9Z2Z8JZ77c3GNZP';
form.accessKeySecret = 'BiDkpS7UXj72HWwDWaFZxiXjNFBNCM';
form.bucketDomain = 'https://oss.wsdns.cn';
form.settingKey = settingKey.value;
};
/* 保存编辑 */
const save = () => {
console.log(form);
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
// Make sure key is stable even if the parent passes a changing `value` prop.
form.settingKey = settingKey.value;
const appForm = {
...form,
content: JSON.stringify(form)
};
// `getByKey` may not return `settingId`; update by key is safer here.
const saveOrUpdate = isUpdate.value ? updateSettingByKey : addSetting;
saveOrUpdate(appForm)
.then((_msg) => {
message.success('保存成功');
})
.catch((e) => {
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.data,
(data) => {
// Parent shares one `data` ref across tabs; ignore unrelated keys to avoid polluting this form.
if (!data || typeof data !== 'object') {
isUpdate.value = false;
resetFields();
form.settingKey = settingKey.value;
form.settingId = undefined;
return;
}
// Be tolerant to endpoints returning arrays or nested payloads.
const normalized: any = Array.isArray(data)
? data.find((d) => d?.settingKey === settingKey.value) ?? data[0]
: (data as any).data && typeof (data as any).data === 'object'
? (data as any).data
: data;
// Some endpoints return the full Setting row (with `content`), others return merged fields directly.
let parsedContent: any | undefined;
const rawContent = (normalized as any).content;
if (rawContent) {
if (typeof rawContent === 'string') {
try {
parsedContent = JSON.parse(rawContent);
} catch {
parsedContent = undefined;
}
} else if (typeof rawContent === 'object') {
parsedContent = rawContent;
}
}
const contentOrRow = parsedContent ?? normalized;
const hasUploadFields =
'uploadMethod' in contentOrRow ||
'bucketName' in contentOrRow ||
'bucketEndpoint' in contentOrRow ||
'bucketDomain' in contentOrRow ||
'fileUrl' in contentOrRow;
const incomingKey =
(contentOrRow as any).settingKey ?? (normalized as any).settingKey;
const belongsToUpload =
incomingKey === settingKey.value || hasUploadFields;
if (!belongsToUpload) {
isUpdate.value = false;
resetFields();
form.settingKey = settingKey.value;
form.settingId = undefined;
return;
}
isUpdate.value = true;
assignFields(contentOrRow);
// Keep stable key; id is optional.
form.settingKey = settingKey.value;
form.settingId = (normalized as any).settingId;
},
{ immediate: true }
);
</script>
<style lang="less">
.small {
color: var(--text-color-secondary);
font-size: 14px !important;
}
</style>