|
|
@@ -10,9 +10,9 @@
|
|
|
<!-- 装修类型 -->
|
|
|
<el-form-item label="装修类型" prop="renovationType">
|
|
|
<el-radio-group v-model="formData.renovationType">
|
|
|
- <el-radio :label="1">新房装修</el-radio>
|
|
|
- <el-radio :label="2">旧房改造</el-radio>
|
|
|
- <el-radio :label="3">局部装修</el-radio>
|
|
|
+ <el-radio :label="1"> 新房装修 </el-radio>
|
|
|
+ <el-radio :label="2"> 旧房改造 </el-radio>
|
|
|
+ <el-radio :label="3"> 局部装修 </el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
|
|
|
@@ -106,7 +106,9 @@
|
|
|
@clear="handleCityClear"
|
|
|
>
|
|
|
<template #suffix>
|
|
|
- <el-icon class="cursor-pointer" @click="showCityDialog = true"><ArrowDown /></el-icon>
|
|
|
+ <el-icon class="cursor-pointer" @click="showCityDialog = true">
|
|
|
+ <ArrowDown />
|
|
|
+ </el-icon>
|
|
|
</template>
|
|
|
</el-input>
|
|
|
</el-form-item>
|
|
|
@@ -128,9 +130,9 @@
|
|
|
<el-form-item prop="agreementConfirmed">
|
|
|
<el-checkbox v-model="formData.agreementConfirmed" :true-label="1" :false-label="0">
|
|
|
我已阅读并同意
|
|
|
- <el-link type="primary" :underline="false" @click="handleShowAgreement">《用户服务协议》</el-link>
|
|
|
+ <el-link type="primary" :underline="false" @click="handleShowAgreement"> 《用户服务协议》 </el-link>
|
|
|
和
|
|
|
- <el-link type="primary" :underline="false" @click="handleShowPrivacy">《隐私政策》</el-link>
|
|
|
+ <el-link type="primary" :underline="false" @click="handleShowPrivacy"> 《隐私政策》 </el-link>
|
|
|
,允许装修商家查看我的需求信息并与我联系
|
|
|
</el-checkbox>
|
|
|
</el-form-item>
|
|
|
@@ -138,8 +140,8 @@
|
|
|
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
- <el-button @click="handleClose">返回</el-button>
|
|
|
- <el-button type="primary" :loading="submitLoading" @click="handleSubmit">确定</el-button>
|
|
|
+ <el-button @click="handleClose"> 返回 </el-button>
|
|
|
+ <el-button type="primary" :loading="submitLoading" @click="handleSubmit"> 确定 </el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -179,8 +181,8 @@
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
- <el-button @click="showCityDialog = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="handleConfirmCity">确定</el-button>
|
|
|
+ <el-button @click="showCityDialog = false"> 取消 </el-button>
|
|
|
+ <el-button type="primary" @click="handleConfirmCity"> 确定 </el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -462,7 +464,7 @@
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer-center">
|
|
|
- <el-button type="primary" @click="agreementDialogVisible = false">已阅读并同意协议内容</el-button>
|
|
|
+ <el-button type="primary" @click="agreementDialogVisible = false"> 已阅读并同意协议内容 </el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -539,7 +541,7 @@
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer-center">
|
|
|
- <el-button type="primary" @click="privacyDialogVisible = false">已阅读并同意协议内容</el-button>
|
|
|
+ <el-button type="primary" @click="privacyDialogVisible = false"> 已阅读并同意协议内容 </el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -549,9 +551,17 @@
|
|
|
<script setup lang="ts" name="decorationAdd">
|
|
|
import { ref, reactive, onMounted } from "vue";
|
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
-import { ElMessage, type FormInstance, type UploadFile, type UploadProps, type UploadRequestOptions } from "element-plus";
|
|
|
+import {
|
|
|
+ ElMessage,
|
|
|
+ type FormInstance,
|
|
|
+ type UploadFile,
|
|
|
+ type UploadProps,
|
|
|
+ type UploadRequestOptions,
|
|
|
+ type UploadUserFile
|
|
|
+} from "element-plus";
|
|
|
import { Plus, ArrowDown } from "@element-plus/icons-vue";
|
|
|
-import { saveOrUpdateDecoration, getDistrict, uploadDecorationImage } from "@/api/modules/storeDecoration";
|
|
|
+import { saveOrUpdateDecoration, getDistrict } from "@/api/modules/storeDecoration";
|
|
|
+import { uploadFileToOss } from "@/api/upload.js";
|
|
|
import { localGet } from "@/utils";
|
|
|
|
|
|
const route = useRoute();
|
|
|
@@ -600,7 +610,7 @@ const selectedCityName = ref("");
|
|
|
const selectedDistrictName = ref("");
|
|
|
|
|
|
// 禁用「当天之前」的日期(核心方法)
|
|
|
-const disabledBeforeToday = (date) => {
|
|
|
+const disabledBeforeToday = date => {
|
|
|
// 初始化今天的日期(重置时分秒为0,避免时间戳干扰)
|
|
|
const today = new Date();
|
|
|
today.setHours(0, 0, 0, 0);
|
|
|
@@ -778,82 +788,50 @@ const beforeUpload: UploadProps["beforeUpload"] = (rawFile: File) => {
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
-// 图片上传 - 点击加号时调用 /file/uploadMore 接口
|
|
|
+// 图片上传:OSS 直传(@/api/upload.js)
|
|
|
const handleImageUpload = async (options: UploadRequestOptions) => {
|
|
|
- // 获取文件对象,可能是 options.file 或 options.file.raw
|
|
|
- const file = options.file.raw || options.file;
|
|
|
-
|
|
|
+ const uploadFileItem = options.file as UploadUserFile;
|
|
|
+ const raw = uploadFileItem.raw || uploadFileItem;
|
|
|
+ const file = raw instanceof File ? raw : null;
|
|
|
+
|
|
|
if (!file) {
|
|
|
- console.error("文件对象不存在");
|
|
|
ElMessage.error("文件对象不存在");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- console.log("开始上传文件:", file.name, "类型:", file.type, "大小:", file.size);
|
|
|
-
|
|
|
- const uploadFormData = new FormData();
|
|
|
- uploadFormData.append("file", file);
|
|
|
-
|
|
|
- options.file.status = "uploading";
|
|
|
- options.file.percentage = 0;
|
|
|
+ uploadFileItem.status = "uploading";
|
|
|
+ uploadFileItem.percentage = 0;
|
|
|
|
|
|
try {
|
|
|
- console.log("调用 /alienStore/file/uploadMore 接口上传文件");
|
|
|
- // 调用 /alienStore/file/uploadMore 接口上传文件
|
|
|
- const result: any = await uploadDecorationImage(uploadFormData);
|
|
|
- console.log("上传接口返回结果:", result);
|
|
|
-
|
|
|
- if (result?.code === 200 || result?.code === 0) {
|
|
|
- let fileUrl = "";
|
|
|
-
|
|
|
- // 处理不同的返回格式
|
|
|
- if (Array.isArray(result.data) && result.data.length > 0) {
|
|
|
- fileUrl = result.data[0];
|
|
|
- } else if (typeof result.data === "string") {
|
|
|
- fileUrl = result.data;
|
|
|
- } else if (result.data?.fileUrl) {
|
|
|
- fileUrl = result.data.fileUrl;
|
|
|
- } else if (result.data?.url) {
|
|
|
- fileUrl = result.data.url;
|
|
|
- } else if (result.fileUrl) {
|
|
|
- fileUrl = result.fileUrl;
|
|
|
- } else if (result.url) {
|
|
|
- fileUrl = result.url;
|
|
|
- }
|
|
|
+ const fileUrl = await uploadFileToOss(file, "image");
|
|
|
+ if (!fileUrl) {
|
|
|
+ throw new Error("上传失败,未返回文件地址");
|
|
|
+ }
|
|
|
|
|
|
- if (fileUrl) {
|
|
|
- options.file.status = "success";
|
|
|
- options.file.percentage = 100;
|
|
|
- options.file.url = fileUrl;
|
|
|
- options.file.response = { url: fileUrl };
|
|
|
-
|
|
|
- // 获取图片路径后,记录到 attachmentUrls 数组中,提交时会传递给保存接口
|
|
|
- if (!formData.attachmentUrls.includes(fileUrl)) {
|
|
|
- formData.attachmentUrls.push(fileUrl);
|
|
|
- console.log("文件上传成功,路径已记录:", fileUrl);
|
|
|
- console.log("当前附件列表:", formData.attachmentUrls);
|
|
|
- }
|
|
|
- options.onSuccess?.(result);
|
|
|
- // 触发表单验证
|
|
|
- formRef.value?.validateField("attachmentUrls");
|
|
|
- } else {
|
|
|
- console.error("上传接口返回数据格式错误:", result);
|
|
|
- throw new Error("上传接口返回数据格式错误");
|
|
|
- }
|
|
|
- } else {
|
|
|
- throw new Error(result?.msg || result?.message || "文件上传失败");
|
|
|
+ uploadFileItem.status = "success";
|
|
|
+ uploadFileItem.percentage = 100;
|
|
|
+ uploadFileItem.url = fileUrl;
|
|
|
+ uploadFileItem.response = { url: fileUrl };
|
|
|
+
|
|
|
+ if (!formData.attachmentUrls.includes(fileUrl)) {
|
|
|
+ formData.attachmentUrls.push(fileUrl);
|
|
|
}
|
|
|
+ options.onSuccess?.({ code: 200, data: fileUrl, url: fileUrl });
|
|
|
+ formRef.value?.validateField("attachmentUrls");
|
|
|
} catch (error: any) {
|
|
|
console.error("文件上传失败:", error);
|
|
|
- options.file.status = "fail";
|
|
|
- if (options.file.url && options.file.url.startsWith("blob:")) {
|
|
|
- URL.revokeObjectURL(options.file.url);
|
|
|
+ uploadFileItem.status = "fail";
|
|
|
+ if (uploadFileItem.url && uploadFileItem.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(uploadFileItem.url);
|
|
|
}
|
|
|
- const index = fileList.value.findIndex(f => f.uid === options.file.uid);
|
|
|
+ const index = fileList.value.findIndex(f => f.uid === uploadFileItem.uid);
|
|
|
if (index > -1) {
|
|
|
fileList.value.splice(index, 1);
|
|
|
}
|
|
|
- ElMessage.error(error?.message || "文件上传失败");
|
|
|
+ if (error?.message === "上传失败,未返回文件地址") {
|
|
|
+ ElMessage.error(error.message);
|
|
|
+ }
|
|
|
+ // 其余错误(含 OSS 签名/网络)已在 upload.js 中提示
|
|
|
options.onError?.(error);
|
|
|
}
|
|
|
};
|
|
|
@@ -906,7 +884,7 @@ const handleSubmit = async () => {
|
|
|
submitLoading.value = true;
|
|
|
try {
|
|
|
// 确保 attachmentUrls 是数组格式,包含所有上传成功的图片路径
|
|
|
- const attachmentUrlsList = Array.isArray(formData.attachmentUrls)
|
|
|
+ const attachmentUrlsList = Array.isArray(formData.attachmentUrls)
|
|
|
? formData.attachmentUrls.filter(url => url && url.trim() !== "")
|
|
|
: [];
|
|
|
|
|
|
@@ -983,82 +961,67 @@ onMounted(() => {
|
|
|
<style lang="scss" scoped>
|
|
|
.add-container {
|
|
|
:deep(.el-dialog__body) {
|
|
|
- padding: 20px;
|
|
|
max-height: 70vh;
|
|
|
+ padding: 20px;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
-
|
|
|
:deep(.el-form-item) {
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
-
|
|
|
:deep(.el-radio-group) {
|
|
|
display: flex;
|
|
|
gap: 20px;
|
|
|
}
|
|
|
-
|
|
|
.upload-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: #999;
|
|
|
margin-top: 5px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999999;
|
|
|
}
|
|
|
-
|
|
|
.dialog-footer {
|
|
|
- text-align: center;
|
|
|
padding: 20px 0 0;
|
|
|
+ text-align: center;
|
|
|
}
|
|
|
-
|
|
|
:deep(.el-upload--picture-card) {
|
|
|
width: 100px;
|
|
|
height: 100px;
|
|
|
}
|
|
|
-
|
|
|
:deep(.el-upload-list--picture-card .el-upload-list__item) {
|
|
|
width: 100px;
|
|
|
height: 100px;
|
|
|
}
|
|
|
-
|
|
|
.city-selector {
|
|
|
padding: 10px 0;
|
|
|
}
|
|
|
-
|
|
|
.cursor-pointer {
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
-
|
|
|
.agreement-content {
|
|
|
height: 50vh;
|
|
|
padding: 10px;
|
|
|
overflow-y: auto;
|
|
|
font-size: 14px;
|
|
|
line-height: 1.6;
|
|
|
-
|
|
|
h3 {
|
|
|
margin-top: 20px;
|
|
|
margin-bottom: 10px;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
-
|
|
|
p {
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
-
|
|
|
ul {
|
|
|
- margin-left: 20px;
|
|
|
margin-bottom: 10px;
|
|
|
-
|
|
|
+ margin-left: 20px;
|
|
|
li {
|
|
|
margin-bottom: 5px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
.dialog-footer-center {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
width: 100%;
|
|
|
-
|
|
|
.el-button {
|
|
|
width: 406px;
|
|
|
height: 60px;
|