|
|
|
|
@ -42,7 +42,54 @@
|
|
|
|
|
@input="onDescriptionInput"
|
|
|
|
|
></uv-textarea>
|
|
|
|
|
<view class="char-count">{{ formData.description.length }}/500</view>
|
|
|
|
|
<view class="error-text" v-if="errors.description">{{ errors.description }}</view>
|
|
|
|
|
<view class="error-text" v-if="errors.description">
|
|
|
|
|
{{ errors.description }}
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
邮箱
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
</view>
|
|
|
|
|
<uv-input
|
|
|
|
|
v-model="formData.email"
|
|
|
|
|
placeholder="请输入邮箱地址"
|
|
|
|
|
:clearable="true"
|
|
|
|
|
type="email"
|
|
|
|
|
@input="onEmailInput"
|
|
|
|
|
></uv-input>
|
|
|
|
|
<view class="error-text" v-if="errors.email">{{ errors.email }}</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
<view class="form-label">
|
|
|
|
|
手机
|
|
|
|
|
<text class="required">*</text>
|
|
|
|
|
</view>
|
|
|
|
|
<uv-input
|
|
|
|
|
v-model="formData.phone"
|
|
|
|
|
placeholder="请输入手机号"
|
|
|
|
|
:clearable="true"
|
|
|
|
|
type="number"
|
|
|
|
|
:maxlength="11"
|
|
|
|
|
@input="onPhoneInput"
|
|
|
|
|
></uv-input>
|
|
|
|
|
<view class="error-text" v-if="errors.phone">{{ errors.phone }}</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
<view class="form-label">联系厂家</view>
|
|
|
|
|
<uv-input
|
|
|
|
|
v-model="formData.vendor_contact"
|
|
|
|
|
placeholder="请输入联系厂家(选填)"
|
|
|
|
|
:clearable="true"
|
|
|
|
|
:maxlength="100"
|
|
|
|
|
@input="onVendorContactInput"
|
|
|
|
|
></uv-input>
|
|
|
|
|
<view class="error-text" v-if="errors.vendor_contact">
|
|
|
|
|
{{ errors.vendor_contact }}
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
@ -61,117 +108,186 @@
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
|
import { useUserStore } from '@/store'
|
|
|
|
|
import RPC from '@/utils/request'
|
|
|
|
|
import { ref, computed } from "vue";
|
|
|
|
|
import { useUserStore } from "@/store";
|
|
|
|
|
import RPC from "@/utils/request";
|
|
|
|
|
|
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
|
|
|
|
// 表单数据
|
|
|
|
|
const formData = ref({
|
|
|
|
|
name: '',
|
|
|
|
|
description: ''
|
|
|
|
|
})
|
|
|
|
|
name: "",
|
|
|
|
|
description: "",
|
|
|
|
|
email: "",
|
|
|
|
|
phone: "",
|
|
|
|
|
vendor_contact: "",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 错误信息
|
|
|
|
|
const errors = ref({
|
|
|
|
|
name: '',
|
|
|
|
|
description: ''
|
|
|
|
|
})
|
|
|
|
|
name: "",
|
|
|
|
|
description: "",
|
|
|
|
|
email: "",
|
|
|
|
|
phone: "",
|
|
|
|
|
vendor_contact: "",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 提交状态
|
|
|
|
|
const submitLoading = ref(false)
|
|
|
|
|
const submitLoading = ref(false);
|
|
|
|
|
|
|
|
|
|
// 邮箱验证
|
|
|
|
|
const validateEmail = (email) => {
|
|
|
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
|
|
return emailRegex.test(email);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 手机号验证
|
|
|
|
|
const validatePhone = (phone) => {
|
|
|
|
|
const phoneRegex = /^1[3-9]\d{9}$/;
|
|
|
|
|
return phoneRegex.test(phone);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 表单验证
|
|
|
|
|
const isFormValid = computed(() => {
|
|
|
|
|
return formData.value.name.trim() && formData.value.description.trim()
|
|
|
|
|
})
|
|
|
|
|
return (
|
|
|
|
|
formData.value.name.trim() &&
|
|
|
|
|
formData.value.description.trim() &&
|
|
|
|
|
formData.value.email.trim() &&
|
|
|
|
|
formData.value.phone.trim()
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 输入事件处理
|
|
|
|
|
const onNameInput = () => {
|
|
|
|
|
if (errors.value.name) {
|
|
|
|
|
errors.value.name = ''
|
|
|
|
|
}
|
|
|
|
|
errors.value.name = "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDescriptionInput = () => {
|
|
|
|
|
if (errors.value.description) {
|
|
|
|
|
errors.value.description = ''
|
|
|
|
|
errors.value.description = "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onEmailInput = () => {
|
|
|
|
|
if (errors.value.email) {
|
|
|
|
|
errors.value.email = "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onPhoneInput = () => {
|
|
|
|
|
if (errors.value.phone) {
|
|
|
|
|
errors.value.phone = "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onVendorContactInput = () => {
|
|
|
|
|
if (errors.value.vendor_contact) {
|
|
|
|
|
errors.value.vendor_contact = "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 表单验证函数
|
|
|
|
|
const validateForm = () => {
|
|
|
|
|
let isValid = true
|
|
|
|
|
let isValid = true;
|
|
|
|
|
|
|
|
|
|
// 验证需求名称
|
|
|
|
|
if (!formData.value.name.trim()) {
|
|
|
|
|
errors.value.name = '请输入需求名称'
|
|
|
|
|
isValid = false
|
|
|
|
|
errors.value.name = "请输入需求名称";
|
|
|
|
|
isValid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证需求描述
|
|
|
|
|
if (!formData.value.description.trim()) {
|
|
|
|
|
errors.value.description = '请输入需求描述'
|
|
|
|
|
isValid = false
|
|
|
|
|
errors.value.description = "请输入需求描述";
|
|
|
|
|
isValid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证邮箱
|
|
|
|
|
if (!formData.value.email.trim()) {
|
|
|
|
|
errors.value.email = "请输入邮箱地址";
|
|
|
|
|
isValid = false;
|
|
|
|
|
} else if (!validateEmail(formData.value.email.trim())) {
|
|
|
|
|
errors.value.email = "请输入正确的邮箱格式";
|
|
|
|
|
isValid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isValid
|
|
|
|
|
// 验证手机号
|
|
|
|
|
if (!formData.value.phone.trim()) {
|
|
|
|
|
errors.value.phone = "请输入手机号";
|
|
|
|
|
isValid = false;
|
|
|
|
|
} else if (!validatePhone(formData.value.phone.trim())) {
|
|
|
|
|
errors.value.phone = "请输入正确的手机号格式";
|
|
|
|
|
isValid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isValid;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 提交需求
|
|
|
|
|
const submitRequirement = async () => {
|
|
|
|
|
if (!validateForm()) {
|
|
|
|
|
return
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
submitLoading.value = true
|
|
|
|
|
submitLoading.value = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const response = await RPC.post('/requirement/create', {
|
|
|
|
|
const response = await RPC.post("/requirement/create", {
|
|
|
|
|
proposer_id: userStore.userInfo.id,
|
|
|
|
|
proposer: userStore.userInfo.username,
|
|
|
|
|
name: formData.value.name.trim(),
|
|
|
|
|
description: formData.value.description.trim()
|
|
|
|
|
})
|
|
|
|
|
description: formData.value.description.trim(),
|
|
|
|
|
email: formData.value.email.trim(),
|
|
|
|
|
phone: formData.value.phone.trim(),
|
|
|
|
|
vendor_contact: formData.value.vendor_contact.trim(),
|
|
|
|
|
category:'需求新增'
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '需求提交成功',
|
|
|
|
|
icon: 'success'
|
|
|
|
|
})
|
|
|
|
|
title: "需求提交成功",
|
|
|
|
|
icon: "success",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 延迟返回上一页
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
}, 1500)
|
|
|
|
|
|
|
|
|
|
uni.navigateBack();
|
|
|
|
|
}, 1500);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('提交需求失败:', error)
|
|
|
|
|
console.error("提交需求失败:", error);
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: error.message || '提交失败,请重试',
|
|
|
|
|
icon: 'none'
|
|
|
|
|
})
|
|
|
|
|
title: error.message || "提交失败,请重试",
|
|
|
|
|
icon: "none",
|
|
|
|
|
});
|
|
|
|
|
} finally {
|
|
|
|
|
submitLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
submitLoading.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 返回上一页
|
|
|
|
|
const goBack = () => {
|
|
|
|
|
if (formData.value.name.trim() || formData.value.description.trim()) {
|
|
|
|
|
const hasContent =
|
|
|
|
|
formData.value.name.trim() ||
|
|
|
|
|
formData.value.description.trim() ||
|
|
|
|
|
formData.value.email.trim() ||
|
|
|
|
|
formData.value.phone.trim() ||
|
|
|
|
|
formData.value.vendor_contact.trim();
|
|
|
|
|
|
|
|
|
|
if (hasContent) {
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '您有未保存的内容,确定要离开吗?',
|
|
|
|
|
title: "提示",
|
|
|
|
|
content: "您有未保存的内容,确定要离开吗?",
|
|
|
|
|
success: (res) => {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
uni.navigateBack();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
}
|
|
|
|
|
uni.navigateBack();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|