| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- <template>
- <popup
- v-model:show="showValue"
- round
- class="farm-info-popup"
- :close-on-click-overlay="true"
- teleport="body"
- >
- <!-- 第一步:农场信息填写 -->
- <template v-if="currentStep === 1">
- <!-- 标题 -->
- <div class="popup-title">完善以下信息,生成智能种植方案</div>
- <!-- 表单区域 -->
- <el-form ref="formRef" :model="formData" :rules="rules" class="farm-form">
- <!-- 农场位置 -->
- <el-form-item label="农场位置" prop="address">
- <el-input v-model="formData.address" placeholder="请输入农场位置" clearable />
- </el-form-item>
- <!-- 农场品种 -->
- <el-form-item label="农场品种" prop="speciesId">
- <el-select
- v-model="formData.speciesId"
- placeholder="请选择"
- @change="handleSpecieChange"
- >
- <el-option
- v-for="item in specieList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- </el-form-item>
- <!-- 农场品类 -->
- <el-form-item label="农场品类" prop="typeId">
- <el-select
- v-model="formData.typeId"
- multiple
- collapse-tags
- placeholder="请选择"
- :disabled="!formData.speciesId"
- @change="handleFruitsChange"
- >
- <el-option
- v-for="item in fruitsList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- </el-form-item>
- <!-- 农场亩数 -->
- <el-form-item label="农场亩数" prop="mu">
- <el-input v-model="formData.mu" placeholder="请输入" type="number">
- <template #suffix>
- <span class="unit">亩</span>
- </template>
- </el-input>
- </el-form-item>
- <!-- 农场名称 -->
- <el-form-item label="农场名称" prop="name">
- <el-input
- v-model="formData.name"
- placeholder="请输入农场名称"
- clearable
- @input="handleNameInput"
- />
- </el-form-item>
- </el-form>
- </template>
- <!-- 第二步:物候期起始时间填写 -->
- <template v-else>
- <!-- 提示文字 -->
- <div class="popup-title">为了精准匹配种植方案,完善物候信息</div>
- <!-- 物候期表单 -->
- <el-form ref="phenologyFormRef" :model="phenologyData" :rules="phenologyRules" class="farm-form">
- <!-- 物候期选择器 -->
- <el-form-item
- label="当下物候期"
- prop="phenologyId"
- >
- <el-select
- v-model="phenologyData.phenologyId"
- placeholder="选择物候期"
- style="width: 100%"
- @change="handlePhenologyChange"
- >
- <el-option
- v-for="phenology in phenologyList"
- :key="phenology.phenologyId"
- :label="phenology.phenologyName"
- :value="phenology.phenologyId"
- />
- </el-select>
- </el-form-item>
- <!-- 日期选择器 -->
- <el-form-item
- label="起始时间"
- prop="phenologyStartDate"
- >
- <el-date-picker
- v-model="phenologyData.phenologyStartDate"
- type="date"
- placeholder="选择时间"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- style="width: 100%"
- />
- </el-form-item>
- </el-form>
- </template>
- <!-- 确认按钮 -->
- <div class="btn-confirm" @click="handleConfirm">确认信息</div>
- </popup>
- </template>
- <script setup>
- import { Popup } from "vant";
- import { computed, ref, watch, nextTick ,onMounted} from "vue";
- import { ElMessage } from "element-plus";
- import { convertPointToArray } from "@/utils/index";
- import { useStore } from "vuex";
- const store = useStore();
- const props = defineProps({
- // 控制弹窗显示/隐藏
- show: {
- type: Boolean,
- default: false,
- },
- // 是否在点击遮罩层后关闭弹窗
- closeOnClickOverlay: {
- type: Boolean,
- default: false,
- },
- // 初始表单数据
- initialData: {
- type: Object,
- default: () => ({}),
- },
- expertMiniUserId: {
- type: [String, Number],
- default: "",
- },
- });
- const city = ref("");
- const MAP_KEY = "CZLBZ-LJICQ-R4A5J-BN62X-YXCRJ-GNBUT";
- function getLocationName(location) {
- const params = {
- key: MAP_KEY,
- location,
- };
- VE_API.old_mini_map.location(params).then(({ result }) => {
- const add = result.formatted_addresses?.recommend ? result.formatted_addresses.recommend : result.address + "";
- formData.value.address = add;
- city.value = result.address_component?.city + result.address_component?.district || "";
- });
- }
- onMounted(() => {
- const arr = convertPointToArray(store.state.home.miniUserLocationPoint);
- getLocationName(`${arr[1]},${arr[0]}`);
- getSpecieList();
- });
- function getSpecieList() {
- return VE_API.farm.fetchSpecieList({ point: store.state.home.miniUserLocationPoint }).then(({ data }) => {
- specieList.value = data || [];
- return data;
- });
- }
- function getFruitsList(parentId) {
- VE_API.farm.fruitsTypeItemList({ parentId }).then(({ data }) => {
- fruitsList.value = data;
- });
- }
- const emit = defineEmits(["update:show", "confirm"]);
- // 处理v-model双向绑定
- const showValue = computed({
- get: () => props.show,
- set: (value) => emit("update:show", value),
- });
- const formRef = ref(null);
- const phenologyFormRef = ref(null);
- // 当前步骤:1-填写农场信息,2-填写物候期时间
- const currentStep = ref(1);
- // 用户是否手动修改过农场名称
- const isNameEdited = ref(false);
- // 表单数据
- const formData = ref({
- address: "",
- speciesId: "",
- typeId: [],
- mu: "",
- name: "",
- });
- // 物候期列表
- const phenologyList = ref([]);
- // 物候期表单数据
- const phenologyData = ref({});
- const specieList = ref([]);
- const fruitsList = ref([]);
- // 规范化多选品种 typeId(支持字符串/数组)
- const normalizeTypeId = (value) => {
- if (Array.isArray(value)) return value;
- if (value === null || value === undefined || value === "") return [];
- return [value];
- };
- // 自定义验证器:验证农场品种
- const validateVariety = (rule, value, callback) => {
- const hasType =
- Array.isArray(formData.value.typeId)
- ? formData.value.typeId.length > 0
- : !!formData.value.typeId;
- if (!formData.value.speciesId || !hasType) {
- callback(new Error("请选择农场品种"));
- } else {
- callback();
- }
- };
- // 表单验证规则
- const rules = {
- address: [{ required: true, message: "请输入农场位置", trigger: "blur" }],
- speciesId: [{ required: true, validator: validateVariety, trigger: "change" }],
- typeId: [{ required: true, validator: validateVariety, trigger: "change" }],
- mu: [
- { required: true, message: "请输入农场亩数", trigger: "blur" },
- { pattern: /^\d+(\.\d+)?$/, message: "请输入有效的数字", trigger: "blur" },
- ],
- name: [{ required: true, message: "请输入农场名称", trigger: "blur" }],
- };
- // 物候期表单验证规则
- const phenologyRules = {
- phenologyId: [{ required: true, message: "请选择物候期", trigger: "change" }],
- phenologyStartDate: [{ required: true, message: "请选择起始时间", trigger: "change" }],
- };
- // 监听初始数据变化
- watch(
- () => props.initialData,
- (newData) => {
- if (newData && Object.keys(newData).length > 0) {
- Object.assign(formData.value, newData);
- formData.value.typeId = normalizeTypeId(formData.value.typeId);
- }
- },
- { immediate: true, deep: true }
- );
- // 监听弹窗显示状态,重置表单
- watch(
- () => props.show,
- (newVal) => {
- if (newVal) {
- // 重置步骤为第一步
- currentStep.value = 1;
- // 重置物候期列表和表单数据
- phenologyList.value = [];
- phenologyData.value = {};
- // 重置名称编辑状态
- isNameEdited.value = false;
- // 弹窗打开时,如果有初始数据则使用,否则使用默认值
- if (props.initialData && Object.keys(props.initialData).length > 0) {
- Object.assign(formData.value, props.initialData);
- formData.value.typeId = normalizeTypeId(formData.value.typeId);
- } else {
- formData.value = {
- address: "",
- speciesId: "",
- typeId: [],
- mu: "",
- name: "",
- };
- }
- // 清除验证状态
- nextTick(() => {
- formRef.value?.clearValidate();
- phenologyFormRef.value?.clearValidate();
- });
- }
- }
- );
- // 品种1变化时,重置品种2并触发验证
- const handleSpecieChange = (val) => {
- formData.value.typeId = [];
- const specie = specieList.value.find(item => item.id === val);
- // 只有在用户没有手动修改名称时,才自动带出默认名称
- if (specie && !isNameEdited.value) {
- formData.value.name = city.value + specie.name + "农场";
- }
- getFruitsList(val);
- // 触发品种验证
- nextTick(() => {
- formRef.value?.validateField("speciesId");
- });
- };
- // 品种2变化时,触发验证
- const handleFruitsChange = () => {
- nextTick(() => {
- // 校验农场品种(包含大类和品种)
- formRef.value?.validateField("speciesId");
- formRef.value?.validateField("typeId");
- });
- };
- // 农场名称输入时,标记为用户已手动修改
- const handleNameInput = () => {
- isNameEdited.value = true;
- };
- // 确认信息
- const handleConfirm = async () => {
- // 第一步:验证农场信息表单
- if (currentStep.value === 1) {
- if (!formRef.value) return;
- try {
- await formRef.value.validate();
-
- // 验证通过,获取物候期数据并切换到第二步
- await getCurrentAndNextPhenology();
- currentStep.value = 2;
- } catch (error) {
- console.log("表单验证失败", error);
- }
- }
- // 第二步:验证物候期表单并关闭弹窗
- else {
- if (!phenologyFormRef.value) return;
- try {
- await phenologyFormRef.value.validate();
- // 验证通过,提交所有数据并关闭弹窗
- emit("confirm", {
- ...formData.value,
- ...phenologyData.value,
- wkt: store.state.home.miniUserLocationPoint,
- expertMiniUserId: props.expertMiniUserId,
- containerId: specieList.value.find(item => item.id === formData.value.speciesId)?.defaultContainerId,
- });
- emit("update:show", false);
- } catch (error) {
- console.log("物候期表单验证失败", error);
- }
- }
- };
- // 获取当前日期(YYYY-MM-DD格式)
- const getTodayDate = () => {
- const today = new Date();
- const year = today.getFullYear();
- const month = String(today.getMonth() + 1).padStart(2, "0");
- const day = String(today.getDate()).padStart(2, "0");
- return `${year}-${month}-${day}`;
- };
- // 物候期变化时,更新日期为对应物候期的 startDate
- const handlePhenologyChange = (phenologyId) => {
- const selectedPhenology = phenologyList.value.find(item => item.phenologyId === phenologyId);
- if (selectedPhenology && selectedPhenology.startDate) {
- phenologyData.value.phenologyStartDate = selectedPhenology.startDate;
- }
- };
- // 获取当前和下一个物候期
- const getCurrentAndNextPhenology = async () => {
- try {
- const { data } = await VE_API.home.getCurrentAndNextPhenology({
- expertMiniUserId: props.expertMiniUserId,
- containerId: specieList.value.find(item => item.id === formData.value.speciesId)?.defaultContainerId,
- });
- if (data && Array.isArray(data)) {
- phenologyList.value = data;
- // 初始化物候期表单数据,日期使用第一个物候期的 startDate
- const firstPhenology = data[0];
- phenologyData.value = {
- phenologyId: firstPhenology?.phenologyId || "",
- phenologyStartDate: firstPhenology?.startDate || getTodayDate(),
- };
- }
- } catch (error) {
- console.error("获取物候期数据失败", error);
- ElMessage.error("获取物候期数据失败");
- }
- };
- </script>
- <style scoped lang="scss">
- .farm-info-popup {
- width: 100%;
- padding: 20px 16px;
- border-radius: 12px;
- .popup-title {
- font-size: 16px;
- color: #121212;
- }
- .farm-form {
- margin: 16px 0;
- background: rgba(33, 153, 248, 0.05);
- padding: 10px;
- border-radius: 5px;
- border: 1px solid rgba(33, 153, 248, 0.2);
- :deep(.el-form-item__label) {
- color: #1d2129;
- }
- .variety-select-wrap {
- display: flex;
- gap: 10px;
- width: 100%;
- }
- .unit {
- color: #666;
- font-size: 14px;
- padding-right: 8px;
- }
- }
- .btn-confirm {
- padding: 10px;
- background: #2199f8;
- color: #ffffff;
- border-radius: 4px;
- font-size: 16px;
- text-align: center;
- }
- }
- </style>
|